diff options
Diffstat (limited to 'sound/soc')
199 files changed, 20959 insertions, 4291 deletions
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 22aec9a1e9a4..4a56f3dfba51 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -78,4 +78,14 @@ config SND_ATMEL_SOC_PDMIC  	help  	  Say Y if you want to add support for Atmel ASoC driver for boards using  	  PDMIC. + +config SND_ATMEL_SOC_TSE850_PCM5142 +	tristate "ASoC driver for the Axentia TSE-850" +	depends on ARCH_AT91 && OF +	depends on ATMEL_SSC && I2C +	select SND_ATMEL_SOC_SSC_DMA +	select SND_SOC_PCM512x_I2C +	help +	  Say Y if you want to add support for the ASoC driver for the +	  Axentia TSE-850 with a PCM5142 codec.  endif diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index a2b127bd9c87..67e10cbd4ed7 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile @@ -13,9 +13,11 @@ snd-atmel-soc-wm8904-objs := atmel_wm8904.o  snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o  snd-atmel-soc-classd-objs := atmel-classd.o  snd-atmel-soc-pdmic-objs := atmel-pdmic.o +snd-atmel-soc-tse850-pcm5142-objs := tse850-pcm5142.o  obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o  obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o  obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o  obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o  obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o +obj-$(CONFIG_SND_ATMEL_SOC_TSE850_PCM5142) += snd-atmel-soc-tse850-pcm5142.o diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 16e459aedffe..a1e2c5682dcd 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -380,6 +380,7 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,  		ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));  		/* Clear the SSC dividers */  		ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0; +		ssc_p->forced_divider = 0;  	}  	spin_unlock_irq(&ssc_p->lock); @@ -426,14 +427,17 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,  		else  			if (div != ssc_p->cmr_div)  				return -EBUSY; +		ssc_p->forced_divider |= BIT(ATMEL_SSC_CMR_DIV);  		break;  	case ATMEL_SSC_TCMR_PERIOD:  		ssc_p->tcmr_period = div; +		ssc_p->forced_divider |= BIT(ATMEL_SSC_TCMR_PERIOD);  		break;  	case ATMEL_SSC_RCMR_PERIOD:  		ssc_p->rcmr_period = div; +		ssc_p->forced_divider |= BIT(ATMEL_SSC_RCMR_PERIOD);  		break;  	default: @@ -443,6 +447,28 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,  	return 0;  } +/* Is the cpu-dai master of the frame clock? */ +static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p) +{ +	switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBM_CFS: +	case SND_SOC_DAIFMT_CBS_CFS: +		return 1; +	} +	return 0; +} + +/* Is the cpu-dai master of the bit clock? */ +static int atmel_ssc_cbs(struct atmel_ssc_info *ssc_p) +{ +	switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBS_CFM: +	case SND_SOC_DAIFMT_CBS_CFS: +		return 1; +	} +	return 0; +} +  /*   * Configure the SSC.   */ @@ -459,6 +485,9 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,  	u32 tfmr, rfmr, tcmr, rcmr;  	int ret;  	int fslen, fslen_ext; +	u32 cmr_div; +	u32 tcmr_period; +	u32 rcmr_period;  	/*  	 * Currently, there is only one set of dma params for @@ -470,6 +499,46 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,  	else  		dir = 1; +	/* +	 * If the cpu dai should provide BCLK, but noone has provided the +	 * divider needed for that to work, fall back to something sensible. +	 */ +	cmr_div = ssc_p->cmr_div; +	if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_CMR_DIV)) && +	    atmel_ssc_cbs(ssc_p)) { +		int bclk_rate = snd_soc_params_to_bclk(params); + +		if (bclk_rate < 0) { +			dev_err(dai->dev, "unable to calculate cmr_div: %d\n", +				bclk_rate); +			return bclk_rate; +		} + +		cmr_div = DIV_ROUND_CLOSEST(ssc_p->mck_rate, 2 * bclk_rate); +	} + +	/* +	 * If the cpu dai should provide LRCLK, but noone has provided the +	 * dividers needed for that to work, fall back to something sensible. +	 */ +	tcmr_period = ssc_p->tcmr_period; +	rcmr_period = ssc_p->rcmr_period; +	if (atmel_ssc_cfs(ssc_p)) { +		int frame_size = snd_soc_params_to_frame_size(params); + +		if (frame_size < 0) { +			dev_err(dai->dev, +				"unable to calculate tx/rx cmr_period: %d\n", +				frame_size); +			return frame_size; +		} + +		if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_TCMR_PERIOD))) +			tcmr_period = frame_size / 2 - 1; +		if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_RCMR_PERIOD))) +			rcmr_period = frame_size / 2 - 1; +	} +  	dma_params = ssc_p->dma_params[dir];  	channels = params_channels(params); @@ -524,7 +593,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,  		fslen_ext = (bits - 1) / 16;  		fslen = (bits - 1) % 16; -		rcmr =	  SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) +		rcmr =	  SSC_BF(RCMR_PERIOD, rcmr_period)  			| SSC_BF(RCMR_STTDLY, START_DELAY)  			| SSC_BF(RCMR_START, SSC_START_FALLING_RF)  			| SSC_BF(RCMR_CKI, SSC_CKI_RISING) @@ -540,7 +609,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,  			| SSC_BF(RFMR_LOOP, 0)  			| SSC_BF(RFMR_DATLEN, (bits - 1)); -		tcmr =	  SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) +		tcmr =	  SSC_BF(TCMR_PERIOD, tcmr_period)  			| SSC_BF(TCMR_STTDLY, START_DELAY)  			| SSC_BF(TCMR_START, SSC_START_FALLING_RF)  			| SSC_BF(TCMR_CKI, SSC_CKI_FALLING) @@ -606,7 +675,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,  		fslen_ext = (bits - 1) / 16;  		fslen = (bits - 1) % 16; -		rcmr =	  SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) +		rcmr =	  SSC_BF(RCMR_PERIOD, rcmr_period)  			| SSC_BF(RCMR_STTDLY, START_DELAY)  			| SSC_BF(RCMR_START, SSC_START_FALLING_RF)  			| SSC_BF(RCMR_CKI, SSC_CKI_RISING) @@ -623,7 +692,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,  			| SSC_BF(RFMR_LOOP, 0)  			| SSC_BF(RFMR_DATLEN, (bits - 1)); -		tcmr =	  SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) +		tcmr =	  SSC_BF(TCMR_PERIOD, tcmr_period)  			| SSC_BF(TCMR_STTDLY, START_DELAY)  			| SSC_BF(TCMR_START, SSC_START_FALLING_RF)  			| SSC_BF(TCMR_CKI, SSC_CKI_FALLING) @@ -650,7 +719,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,  		 * MCK divider, and the BCLK signal is output  		 * on the SSC TK line.  		 */ -		rcmr =	  SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) +		rcmr =	  SSC_BF(RCMR_PERIOD, rcmr_period)  			| SSC_BF(RCMR_STTDLY, 1)  			| SSC_BF(RCMR_START, SSC_START_RISING_RF)  			| SSC_BF(RCMR_CKI, SSC_CKI_RISING) @@ -665,7 +734,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,  			| SSC_BF(RFMR_LOOP, 0)  			| SSC_BF(RFMR_DATLEN, (bits - 1)); -		tcmr =	  SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) +		tcmr =	  SSC_BF(TCMR_PERIOD, tcmr_period)  			| SSC_BF(TCMR_STTDLY, 1)  			| SSC_BF(TCMR_START, SSC_START_RISING_RF)  			| SSC_BF(TCMR_CKI, SSC_CKI_FALLING) @@ -760,7 +829,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,  	}  	/* set SSC clock mode register */ -	ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); +	ssc_writel(ssc_p->ssc->regs, CMR, cmr_div);  	/* set receive clock mode and format */  	ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h index 80b153857a88..75194f582131 100644 --- a/sound/soc/atmel/atmel_ssc_dai.h +++ b/sound/soc/atmel/atmel_ssc_dai.h @@ -113,6 +113,7 @@ struct atmel_ssc_info {  	unsigned short cmr_div;  	unsigned short tcmr_period;  	unsigned short rcmr_period; +	unsigned int forced_divider;  	struct atmel_pcm_dma_params *dma_params[2];  	struct atmel_ssc_state ssc_state;  	unsigned long mck_rate; diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c index fdd28ed3e0b9..fbc10f61eb55 100644 --- a/sound/soc/atmel/atmel_wm8904.c +++ b/sound/soc/atmel/atmel_wm8904.c @@ -53,7 +53,7 @@ static int atmel_asoc_wm8904_hw_params(struct snd_pcm_substream *substream,  	return 0;  } -static struct snd_soc_ops atmel_asoc_wm8904_ops = { +static const struct snd_soc_ops atmel_asoc_wm8904_ops = {  	.hw_params = atmel_asoc_wm8904_hw_params,  }; diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c new file mode 100644 index 000000000000..ac6a814c8ecf --- /dev/null +++ b/sound/soc/atmel/tse850-pcm5142.c @@ -0,0 +1,472 @@ +/* + * TSE-850 audio - ASoC driver for the Axentia TSE-850 with a PCM5142 codec + * + * Copyright (C) 2016 Axentia Technologies AB + * + * Author: Peter Rosin <peda@axentia.se> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + *               loop1 relays + *   IN1 +---o  +------------+  o---+ OUT1 + *            \                / + *             +              + + *             |   /          | + *             +--o  +--.     | + *             |  add   |     | + *             |        V     | + *             |      .---.   | + *   DAC +----------->|Sum|---+ + *             |      '---'   | + *             |              | + *             +              + + * + *   IN2 +---o--+------------+--o---+ OUT2 + *               loop2 relays + * + * The 'loop1' gpio pin controlls two relays, which are either in loop + * position, meaning that input and output are directly connected, or + * they are in mixer position, meaning that the signal is passed through + * the 'Sum' mixer. Similarly for 'loop2'. + * + * In the above, the 'loop1' relays are inactive, thus feeding IN1 to the + * mixer (if 'add' is active) and feeding the mixer output to OUT1. The + * 'loop2' relays are active, short-cutting the TSE-850 from channel 2. + * IN1, IN2, OUT1 and OUT2 are TSE-850 connectors and DAC is the PCB name + * of the (filtered) output from the PCM5142 codec. + */ + +#include <linux/clk.h> +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/regulator/consumer.h> + +#include <sound/soc.h> +#include <sound/pcm_params.h> + +#include "atmel_ssc_dai.h" + +struct tse850_priv { +	int ssc_id; + +	struct gpio_desc *add; +	struct gpio_desc *loop1; +	struct gpio_desc *loop2; + +	struct regulator *ana; + +	int add_cache; +	int loop1_cache; +	int loop2_cache; +}; + +static int tse850_get_mux1(struct snd_kcontrol *kctrl, +			   struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); +	struct snd_soc_card *card = dapm->card; +	struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + +	ucontrol->value.enumerated.item[0] = tse850->loop1_cache; + +	return 0; +} + +static int tse850_put_mux1(struct snd_kcontrol *kctrl, +			   struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); +	struct snd_soc_card *card = dapm->card; +	struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); +	struct soc_enum *e = (struct soc_enum *)kctrl->private_value; +	unsigned int val = ucontrol->value.enumerated.item[0]; + +	if (val >= e->items) +		return -EINVAL; + +	gpiod_set_value_cansleep(tse850->loop1, val); +	tse850->loop1_cache = val; + +	return snd_soc_dapm_put_enum_double(kctrl, ucontrol); +} + +static int tse850_get_mux2(struct snd_kcontrol *kctrl, +			   struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); +	struct snd_soc_card *card = dapm->card; +	struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + +	ucontrol->value.enumerated.item[0] = tse850->loop2_cache; + +	return 0; +} + +static int tse850_put_mux2(struct snd_kcontrol *kctrl, +			   struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); +	struct snd_soc_card *card = dapm->card; +	struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); +	struct soc_enum *e = (struct soc_enum *)kctrl->private_value; +	unsigned int val = ucontrol->value.enumerated.item[0]; + +	if (val >= e->items) +		return -EINVAL; + +	gpiod_set_value_cansleep(tse850->loop2, val); +	tse850->loop2_cache = val; + +	return snd_soc_dapm_put_enum_double(kctrl, ucontrol); +} + +int tse850_get_mix(struct snd_kcontrol *kctrl, +		   struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); +	struct snd_soc_card *card = dapm->card; +	struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + +	ucontrol->value.enumerated.item[0] = tse850->add_cache; + +	return 0; +} + +int tse850_put_mix(struct snd_kcontrol *kctrl, +		   struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); +	struct snd_soc_card *card = dapm->card; +	struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); +	int connect = !!ucontrol->value.integer.value[0]; + +	if (tse850->add_cache == connect) +		return 0; + +	/* +	 * Hmmm, this gpiod_set_value_cansleep call should probably happen +	 * inside snd_soc_dapm_mixer_update_power in the loop. +	 */ +	gpiod_set_value_cansleep(tse850->add, connect); +	tse850->add_cache = connect; + +	snd_soc_dapm_mixer_update_power(dapm, kctrl, connect, NULL); +	return 1; +} + +int tse850_get_ana(struct snd_kcontrol *kctrl, +		   struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); +	struct snd_soc_card *card = dapm->card; +	struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); +	int ret; + +	ret = regulator_get_voltage(tse850->ana); +	if (ret < 0) +		return ret; + +	/* +	 * Map regulator output values like so: +	 *      -11.5V to "Low" (enum 0) +	 * 11.5V-12.5V to "12V" (enum 1) +	 * 12.5V-13.5V to "13V" (enum 2) +	 *     ... +	 * 18.5V-19.5V to "19V" (enum 8) +	 * 19.5V-      to "20V" (enum 9) +	 */ +	if (ret < 11000000) +		ret = 11000000; +	else if (ret > 20000000) +		ret = 20000000; +	ret -= 11000000; +	ret = (ret + 500000) / 1000000; + +	ucontrol->value.enumerated.item[0] = ret; + +	return 0; +} + +int tse850_put_ana(struct snd_kcontrol *kctrl, +		   struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); +	struct snd_soc_card *card = dapm->card; +	struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); +	struct soc_enum *e = (struct soc_enum *)kctrl->private_value; +	unsigned int uV = ucontrol->value.enumerated.item[0]; +	int ret; + +	if (uV >= e->items) +		return -EINVAL; + +	/* +	 * Map enum zero (Low) to 2 volts on the regulator, do this since +	 * the ana regulator is supplied by the system 12V voltage and +	 * requesting anything below the system voltage causes the system +	 * voltage to be passed through the regulator. Also, the ana +	 * regulator induces noise when requesting voltages near the +	 * system voltage. So, by mapping Low to 2V, that noise is +	 * eliminated when all that is needed is 12V (the system voltage). +	 */ +	if (uV) +		uV = 11000000 + (1000000 * uV); +	else +		uV = 2000000; + +	ret = regulator_set_voltage(tse850->ana, uV, uV); +	if (ret < 0) +		return ret; + +	return snd_soc_dapm_put_enum_double(kctrl, ucontrol); +} + +static const char * const mux_text[] = { "Mixer", "Loop" }; + +static const struct soc_enum mux_enum = +	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, mux_text); + +static const struct snd_kcontrol_new mux1 = +	SOC_DAPM_ENUM_EXT("MUX1", mux_enum, tse850_get_mux1, tse850_put_mux1); + +static const struct snd_kcontrol_new mux2 = +	SOC_DAPM_ENUM_EXT("MUX2", mux_enum, tse850_get_mux2, tse850_put_mux2); + +#define TSE850_DAPM_SINGLE_EXT(xname, reg, shift, max, invert, xget, xput) \ +{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ +	.info = snd_soc_info_volsw, \ +	.get = xget, \ +	.put = xput, \ +	.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } + +static const struct snd_kcontrol_new mix[] = { +	TSE850_DAPM_SINGLE_EXT("IN Switch", SND_SOC_NOPM, 0, 1, 0, +			       tse850_get_mix, tse850_put_mix), +}; + +static const char * const ana_text[] = { +	"Low", "12V", "13V", "14V", "15V", "16V", "17V", "18V", "19V", "20V" +}; + +static const struct soc_enum ana_enum = +	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 9, ana_text); + +static const struct snd_kcontrol_new out = +	SOC_DAPM_ENUM_EXT("ANA", ana_enum, tse850_get_ana, tse850_put_ana); + +static const struct snd_soc_dapm_widget tse850_dapm_widgets[] = { +	SND_SOC_DAPM_LINE("OUT1", NULL), +	SND_SOC_DAPM_LINE("OUT2", NULL), +	SND_SOC_DAPM_LINE("IN1", NULL), +	SND_SOC_DAPM_LINE("IN2", NULL), +	SND_SOC_DAPM_INPUT("DAC"), +	SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0), +	SOC_MIXER_ARRAY("MIX", SND_SOC_NOPM, 0, 0, mix), +	SND_SOC_DAPM_MUX("MUX1", SND_SOC_NOPM, 0, 0, &mux1), +	SND_SOC_DAPM_MUX("MUX2", SND_SOC_NOPM, 0, 0, &mux2), +	SND_SOC_DAPM_OUT_DRV("OUT", SND_SOC_NOPM, 0, 0, &out, 1), +}; + +/* + * These connections are not entirely correct, since both IN1 and IN2 + * are always fed to MIX (if the "IN switch" is set so), i.e. without + * regard to the loop1 and loop2 relays that according to this only + * control MUX1 and MUX2 but in fact also control how the input signals + * are routed. + * But, 1) I don't know how to do it right, and 2) it doesn't seem to + * matter in practice since nothing is powered in those sections anyway. + */ +static const struct snd_soc_dapm_route tse850_intercon[] = { +	{ "OUT1", NULL, "MUX1" }, +	{ "OUT2", NULL, "MUX2" }, + +	{ "MUX1", "Loop",  "IN1" }, +	{ "MUX1", "Mixer", "OUT" }, + +	{ "MUX2", "Loop",  "IN2" }, +	{ "MUX2", "Mixer", "OUT" }, + +	{ "OUT", NULL, "MIX" }, + +	{ "MIX", NULL, "DAC" }, +	{ "MIX", "IN Switch", "IN1" }, +	{ "MIX", "IN Switch", "IN2" }, + +	/* connect board input to the codec left channel output pin */ +	{ "DAC", NULL, "OUTL" }, +}; + +static struct snd_soc_dai_link tse850_dailink = { +	.name = "TSE-850", +	.stream_name = "TSE-850-PCM", +	.codec_dai_name = "pcm512x-hifi", +	.dai_fmt = SND_SOC_DAIFMT_I2S +		 | SND_SOC_DAIFMT_NB_NF +		 | SND_SOC_DAIFMT_CBM_CFS, +}; + +static struct snd_soc_card tse850_card = { +	.name = "TSE-850-ASoC", +	.owner = THIS_MODULE, +	.dai_link = &tse850_dailink, +	.num_links = 1, +	.dapm_widgets = tse850_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(tse850_dapm_widgets), +	.dapm_routes = tse850_intercon, +	.num_dapm_routes = ARRAY_SIZE(tse850_intercon), +	.fully_routed = true, +}; + +static int tse850_dt_init(struct platform_device *pdev) +{ +	struct device_node *np = pdev->dev.of_node; +	struct device_node *codec_np, *cpu_np; +	struct snd_soc_card *card = &tse850_card; +	struct snd_soc_dai_link *dailink = &tse850_dailink; +	struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + +	if (!np) { +		dev_err(&pdev->dev, "only device tree supported\n"); +		return -EINVAL; +	} + +	cpu_np = of_parse_phandle(np, "axentia,ssc-controller", 0); +	if (!cpu_np) { +		dev_err(&pdev->dev, "failed to get dai and pcm info\n"); +		return -EINVAL; +	} +	dailink->cpu_of_node = cpu_np; +	dailink->platform_of_node = cpu_np; +	tse850->ssc_id = of_alias_get_id(cpu_np, "ssc"); +	of_node_put(cpu_np); + +	codec_np = of_parse_phandle(np, "axentia,audio-codec", 0); +	if (!codec_np) { +		dev_err(&pdev->dev, "failed to get codec info\n"); +		return -EINVAL; +	} +	dailink->codec_of_node = codec_np; +	of_node_put(codec_np); + +	return 0; +} + +static int tse850_probe(struct platform_device *pdev) +{ +	struct snd_soc_card *card = &tse850_card; +	struct device *dev = card->dev = &pdev->dev; +	struct tse850_priv *tse850; +	int ret; + +	tse850 = devm_kzalloc(dev, sizeof(*tse850), GFP_KERNEL); +	if (!tse850) +		return -ENOMEM; + +	snd_soc_card_set_drvdata(card, tse850); + +	ret = tse850_dt_init(pdev); +	if (ret) { +		dev_err(dev, "failed to init dt info\n"); +		return ret; +	} + +	tse850->add = devm_gpiod_get(dev, "axentia,add", GPIOD_OUT_HIGH); +	if (IS_ERR(tse850->add)) { +		if (PTR_ERR(tse850->add) != -EPROBE_DEFER) +			dev_err(dev, "failed to get 'add' gpio\n"); +		return PTR_ERR(tse850->add); +	} +	tse850->add_cache = 1; + +	tse850->loop1 = devm_gpiod_get(dev, "axentia,loop1", GPIOD_OUT_HIGH); +	if (IS_ERR(tse850->loop1)) { +		if (PTR_ERR(tse850->loop1) != -EPROBE_DEFER) +			dev_err(dev, "failed to get 'loop1' gpio\n"); +		return PTR_ERR(tse850->loop1); +	} +	tse850->loop1_cache = 1; + +	tse850->loop2 = devm_gpiod_get(dev, "axentia,loop2", GPIOD_OUT_HIGH); +	if (IS_ERR(tse850->loop2)) { +		if (PTR_ERR(tse850->loop2) != -EPROBE_DEFER) +			dev_err(dev, "failed to get 'loop2' gpio\n"); +		return PTR_ERR(tse850->loop2); +	} +	tse850->loop2_cache = 1; + +	tse850->ana = devm_regulator_get(dev, "axentia,ana"); +	if (IS_ERR(tse850->ana)) { +		if (PTR_ERR(tse850->ana) != -EPROBE_DEFER) +			dev_err(dev, "failed to get 'ana' regulator\n"); +		return PTR_ERR(tse850->ana); +	} + +	ret = regulator_enable(tse850->ana); +	if (ret < 0) { +		dev_err(dev, "failed to enable the 'ana' regulator\n"); +		return ret; +	} + +	ret = atmel_ssc_set_audio(tse850->ssc_id); +	if (ret != 0) { +		dev_err(dev, +			"failed to set SSC %d for audio\n", tse850->ssc_id); +		goto err_disable_ana; +	} + +	ret = snd_soc_register_card(card); +	if (ret) { +		dev_err(dev, "snd_soc_register_card failed\n"); +		goto err_put_audio; +	} + +	return 0; + +err_put_audio: +	atmel_ssc_put_audio(tse850->ssc_id); +err_disable_ana: +	regulator_disable(tse850->ana); +	return ret; +} + +static int tse850_remove(struct platform_device *pdev) +{ +	struct snd_soc_card *card = platform_get_drvdata(pdev); +	struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + +	snd_soc_unregister_card(card); +	atmel_ssc_put_audio(tse850->ssc_id); +	regulator_disable(tse850->ana); + +	return 0; +} + +static const struct of_device_id tse850_dt_ids[] = { +	{ .compatible = "axentia,tse850-pcm5142", }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, tse850_dt_ids); + +static struct platform_driver tse850_driver = { +	.driver = { +		.name = "axentia-tse850-pcm5142", +		.of_match_table = of_match_ptr(tse850_dt_ids), +	}, +	.probe = tse850_probe, +	.remove = tse850_remove, +}; + +module_platform_driver(tse850_driver); + +/* Module information */ +MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); +MODULE_DESCRIPTION("ALSA SoC driver for TSE-850 with PCM5142 codec"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig index d528aaceaad9..edf367100ebd 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig @@ -11,6 +11,7 @@ config SND_BCM2835_SOC_I2S  config SND_SOC_CYGNUS  	tristate "SoC platform audio for Broadcom Cygnus chips"  	depends on ARCH_BCM_CYGNUS || COMPILE_TEST +	depends on HAS_DMA  	help  	  Say Y if you want to add support for ASoC audio on Broadcom  	  Cygnus chips (bcm958300, bcm958305, bcm911360) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c67667bb970f..9e1718a8cb1c 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -48,6 +48,8 @@ config SND_SOC_ALL_CODECS  	select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC  	select SND_SOC_CS35L32 if I2C  	select SND_SOC_CS35L33 if I2C +	select SND_SOC_CS35L34 if I2C +	select SND_SOC_CS42L42 if I2C  	select SND_SOC_CS42L51_I2C if I2C  	select SND_SOC_CS42L52 if I2C && INPUT  	select SND_SOC_CS42L56 if I2C && INPUT @@ -83,6 +85,7 @@ config SND_SOC_ALL_CODECS  	select SND_SOC_MAX98095 if I2C  	select SND_SOC_MAX98357A if GPIOLIB  	select SND_SOC_MAX98371 if I2C +	select SND_SOC_MAX98504 if I2C  	select SND_SOC_MAX9867 if I2C  	select SND_SOC_MAX98925 if I2C  	select SND_SOC_MAX98926 if I2C @@ -114,6 +117,7 @@ config SND_SOC_ALL_CODECS  	select SND_SOC_RT5651 if I2C  	select SND_SOC_RT5659 if I2C  	select SND_SOC_RT5660 if I2C +	select SND_SOC_RT5665 if I2C  	select SND_SOC_RT5663 if I2C  	select SND_SOC_RT5670 if I2C  	select SND_SOC_RT5677 if I2C && SPI_MASTER @@ -399,6 +403,14 @@ config SND_SOC_CS35L33  	tristate "Cirrus Logic CS35L33 CODEC"  	depends on I2C +config SND_SOC_CS35L34 +	tristate "Cirrus Logic CS35L34 CODEC" +	depends on I2C + +config SND_SOC_CS42L42 +	tristate "Cirrus Logic CS42L42 CODEC" +	depends on I2C +  config SND_SOC_CS42L51  	tristate @@ -581,6 +593,13 @@ config SND_SOC_MAX9860  	depends on I2C  	select REGMAP_I2C +config SND_SOC_MSM8916_WCD_ANALOG +	tristate "Qualcomm MSM8916 WCD Analog Codec" +	depends on SPMI || COMPILE_TEST + +config SND_SOC_MSM8916_WCD_DIGITAL +	tristate "Qualcomm MSM8916 WCD DIGITAL Codec" +  config SND_SOC_PCM1681  	tristate "Texas Instruments PCM1681 CODEC"  	depends on I2C @@ -649,6 +668,7 @@ config SND_SOC_RL6231  	default y if SND_SOC_RT5651=y  	default y if SND_SOC_RT5659=y  	default y if SND_SOC_RT5660=y +	default y if SND_SOC_RT5665=y  	default y if SND_SOC_RT5663=y  	default y if SND_SOC_RT5670=y  	default y if SND_SOC_RT5677=y @@ -659,6 +679,7 @@ config SND_SOC_RL6231  	default m if SND_SOC_RT5651=m  	default m if SND_SOC_RT5659=m  	default m if SND_SOC_RT5660=m +	default m if SND_SOC_RT5665=m  	default m if SND_SOC_RT5663=m  	default m if SND_SOC_RT5670=m  	default m if SND_SOC_RT5677=m @@ -672,7 +693,6 @@ config SND_SOC_RL6347A  config SND_SOC_RT286  	tristate -	select SND_SOC_RT5663  	depends on I2C  config SND_SOC_RT298 @@ -708,6 +728,9 @@ config SND_SOC_RT5659  config SND_SOC_RT5660  	tristate +config SND_SOC_RT5665 +	tristate +  config SND_SOC_RT5663  	tristate @@ -874,6 +897,7 @@ config SND_SOC_UDA134X  config SND_SOC_UDA1380          tristate +	depends on I2C  config SND_SOC_WL1273  	tristate @@ -914,7 +938,7 @@ config SND_SOC_WM8523  	depends on I2C  config SND_SOC_WM8580 -	tristate "Wolfson Microelectronics WM8523 CODEC" +	tristate "Wolfson Microelectronics WM8580 and WM8581 CODECs"  	depends on I2C  config SND_SOC_WM8711 @@ -1048,15 +1072,18 @@ config SND_SOC_WM8998  config SND_SOC_WM9081  	tristate +	depends on I2C  config SND_SOC_WM9090  	tristate  config SND_SOC_WM9705  	tristate +	select REGMAP_AC97  config SND_SOC_WM9712  	tristate +	select REGMAP_AC97  config SND_SOC_WM9713  	tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 958cd4912fbc..7e1dad79610b 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -38,6 +38,8 @@ snd-soc-bt-sco-objs := bt-sco.o  snd-soc-cq93vc-objs := cq93vc.o  snd-soc-cs35l32-objs := cs35l32.o  snd-soc-cs35l33-objs := cs35l33.o +snd-soc-cs35l34-objs := cs35l34.o +snd-soc-cs42l42-objs := cs42l42.o  snd-soc-cs42l51-objs := cs42l51.o  snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o  snd-soc-cs42l52-objs := cs42l52.o @@ -86,6 +88,8 @@ snd-soc-max9850-objs := max9850.o  snd-soc-max9860-objs := max9860.o  snd-soc-mc13783-objs := mc13783.o  snd-soc-ml26124-objs := ml26124.o +snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o +snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o  snd-soc-nau8810-objs := nau8810.o  snd-soc-nau8825-objs := nau8825.o  snd-soc-hdmi-codec-objs := hdmi-codec.o @@ -114,6 +118,7 @@ snd-soc-rt5645-objs := rt5645.o  snd-soc-rt5651-objs := rt5651.o  snd-soc-rt5659-objs := rt5659.o  snd-soc-rt5660-objs := rt5660.o +snd-soc-rt5665-objs := rt5665.o  snd-soc-rt5663-objs := rt5663.o  snd-soc-rt5670-objs := rt5670.o  snd-soc-rt5677-objs := rt5677.o @@ -214,7 +219,6 @@ snd-soc-wm9705-objs := wm9705.o  snd-soc-wm9712-objs := wm9712.o  snd-soc-wm9713-objs := wm9713.o  snd-soc-wm-hubs-objs := wm_hubs.o -  # Amp  snd-soc-max9877-objs := max9877.o  snd-soc-max98504-objs := max98504.o @@ -263,6 +267,8 @@ obj-$(CONFIG_SND_SOC_BT_SCO)	+= snd-soc-bt-sco.o  obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o  obj-$(CONFIG_SND_SOC_CS35L32)	+= snd-soc-cs35l32.o  obj-$(CONFIG_SND_SOC_CS35L33)	+= snd-soc-cs35l33.o +obj-$(CONFIG_SND_SOC_CS35L34)	+= snd-soc-cs35l34.o +obj-$(CONFIG_SND_SOC_CS42L42)	+= snd-soc-cs42l42.o  obj-$(CONFIG_SND_SOC_CS42L51)	+= snd-soc-cs42l51.o  obj-$(CONFIG_SND_SOC_CS42L51_I2C)	+= snd-soc-cs42l51-i2c.o  obj-$(CONFIG_SND_SOC_CS42L52)	+= snd-soc-cs42l52.o @@ -310,6 +316,8 @@ obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o  obj-$(CONFIG_SND_SOC_MAX9860)	+= snd-soc-max9860.o  obj-$(CONFIG_SND_SOC_MC13783)	+= snd-soc-mc13783.o  obj-$(CONFIG_SND_SOC_ML26124)	+= snd-soc-ml26124.o +obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o +obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o  obj-$(CONFIG_SND_SOC_NAU8810)   += snd-soc-nau8810.o  obj-$(CONFIG_SND_SOC_NAU8825)   += snd-soc-nau8825.o  obj-$(CONFIG_SND_SOC_HDMI_CODEC)	+= snd-soc-hdmi-codec.o @@ -338,6 +346,7 @@ obj-$(CONFIG_SND_SOC_RT5645)	+= snd-soc-rt5645.o  obj-$(CONFIG_SND_SOC_RT5651)	+= snd-soc-rt5651.o  obj-$(CONFIG_SND_SOC_RT5659)	+= snd-soc-rt5659.o  obj-$(CONFIG_SND_SOC_RT5660)	+= snd-soc-rt5660.o +obj-$(CONFIG_SND_SOC_RT5665)	+= snd-soc-rt5665.o  obj-$(CONFIG_SND_SOC_RT5663)	+= snd-soc-rt5663.o  obj-$(CONFIG_SND_SOC_RT5670)	+= snd-soc-rt5670.o  obj-$(CONFIG_SND_SOC_RT5677)	+= snd-soc-rt5677.o diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 935ff7cb71c5..312b2a11abb6 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2587,8 +2587,6 @@ static struct platform_driver ab8500_codec_platform_driver = {  	},  	.probe		= ab8500_codec_driver_probe,  	.remove		= ab8500_codec_driver_remove, -	.suspend	= NULL, -	.resume		= NULL,  };  module_platform_driver(ab8500_codec_platform_driver); diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 439aa3ff1f99..b36511d965c8 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -160,7 +160,7 @@ static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,  	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);  	struct adau *adau = snd_soc_codec_get_drvdata(codec);  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; -	struct snd_soc_dapm_update update; +	struct snd_soc_dapm_update update = { 0 };  	unsigned int stream = e->shift_l;  	unsigned int val, change;  	int reg; diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index c91717d08513..ebdaf56c1d61 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -27,7 +27,27 @@  #include <sound/tlv.h>  #include <sound/ak4641.h> -#include "ak4641.h" +/* AK4641 register space */ +#define AK4641_PM1		0x00 +#define AK4641_PM2		0x01 +#define AK4641_SIG1		0x02 +#define AK4641_SIG2		0x03 +#define AK4641_MODE1		0x04 +#define AK4641_MODE2		0x05 +#define AK4641_DAC		0x06 +#define AK4641_MIC		0x07 +#define AK4641_TIMER		0x08 +#define AK4641_ALC1		0x09 +#define AK4641_ALC2		0x0a +#define AK4641_PGA		0x0b +#define AK4641_LATT		0x0c +#define AK4641_RATT		0x0d +#define AK4641_VOL		0x0e +#define AK4641_STATUS		0x0f +#define AK4641_EQLO		0x10 +#define AK4641_EQMID		0x11 +#define AK4641_EQHI		0x12 +#define AK4641_BTIF		0x13  /* codec private data */  struct ak4641_priv { diff --git a/sound/soc/codecs/ak4641.h b/sound/soc/codecs/ak4641.h deleted file mode 100644 index 4a263248efea..000000000000 --- a/sound/soc/codecs/ak4641.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * ak4641.h  --  AK4641 SoC Audio driver - * - * Copyright 2008 Harald Welte <laforge@gnufiish.org> - * - * Based on ak4535.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _AK4641_H -#define _AK4641_H - -/* AK4641 register space */ - -#define AK4641_PM1		0x00 -#define AK4641_PM2		0x01 -#define AK4641_SIG1		0x02 -#define AK4641_SIG2		0x03 -#define AK4641_MODE1		0x04 -#define AK4641_MODE2		0x05 -#define AK4641_DAC		0x06 -#define AK4641_MIC		0x07 -#define AK4641_TIMER		0x08 -#define AK4641_ALC1		0x09 -#define AK4641_ALC2		0x0a -#define AK4641_PGA		0x0b -#define AK4641_LATT		0x0c -#define AK4641_RATT		0x0d -#define AK4641_VOL		0x0e -#define AK4641_STATUS		0x0f -#define AK4641_EQLO		0x10 -#define AK4641_EQMID		0x11 -#define AK4641_EQHI		0x12 -#define AK4641_BTIF		0x13 - -#define AK4641_CACHEREGNUM	0x14 - - - -#define AK4641_DAI_HIFI		0 -#define AK4641_DAI_VOICE	1 - - -#endif diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 846ca079845f..0a734d910850 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -191,6 +191,14 @@ int arizona_init_spk(struct snd_soc_codec *codec)  		break;  	} +	return 0; +} +EXPORT_SYMBOL_GPL(arizona_init_spk); + +int arizona_init_spk_irqs(struct arizona *arizona) +{ +	int ret; +  	ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN,  				  "Thermal warning", arizona_thermal_warn,  				  arizona); @@ -209,19 +217,16 @@ int arizona_init_spk(struct snd_soc_codec *codec)  	return 0;  } -EXPORT_SYMBOL_GPL(arizona_init_spk); +EXPORT_SYMBOL_GPL(arizona_init_spk_irqs); -int arizona_free_spk(struct snd_soc_codec *codec) +int arizona_free_spk_irqs(struct arizona *arizona)  { -	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); -	struct arizona *arizona = priv->arizona; -  	arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, arizona);  	arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT, arizona);  	return 0;  } -EXPORT_SYMBOL_GPL(arizona_free_spk); +EXPORT_SYMBOL_GPL(arizona_free_spk_irqs);  static const struct snd_soc_dapm_route arizona_mono_routes[] = {  	{ "OUT1R", NULL, "OUT1L" }, @@ -252,6 +257,7 @@ EXPORT_SYMBOL_GPL(arizona_init_mono);  int arizona_init_gpio(struct snd_soc_codec *codec)  {  	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); +	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);  	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);  	struct arizona *arizona = priv->arizona;  	int i; @@ -259,21 +265,24 @@ int arizona_init_gpio(struct snd_soc_codec *codec)  	switch (arizona->type) {  	case WM5110:  	case WM8280: -		snd_soc_dapm_disable_pin(dapm, "DRC2 Signal Activity"); +		snd_soc_component_disable_pin(component, +					      "DRC2 Signal Activity");  		break;  	default:  		break;  	} -	snd_soc_dapm_disable_pin(dapm, "DRC1 Signal Activity"); +	snd_soc_component_disable_pin(component, "DRC1 Signal Activity");  	for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {  		switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {  		case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT: -			snd_soc_dapm_enable_pin(dapm, "DRC1 Signal Activity"); +			snd_soc_component_enable_pin(component, +						     "DRC1 Signal Activity");  			break;  		case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT: -			snd_soc_dapm_enable_pin(dapm, "DRC2 Signal Activity"); +			snd_soc_component_enable_pin(component, +						     "DRC2 Signal Activity");  			break;  		default:  			break; @@ -1233,6 +1242,46 @@ static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,  	return -EINVAL;  } +int arizona_clk_ev(struct snd_soc_dapm_widget *w, +		   struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); +	struct arizona *arizona = dev_get_drvdata(codec->dev->parent); +	unsigned int val; +	int clk_idx; +	int ret; + +	ret = regmap_read(arizona->regmap, w->reg, &val); +	if (ret) { +		dev_err(codec->dev, "Failed to check clock source: %d\n", ret); +		return ret; +	} + +	val = (val & ARIZONA_SYSCLK_SRC_MASK) >> ARIZONA_SYSCLK_SRC_SHIFT; + +	switch (val) { +	case ARIZONA_CLK_SRC_MCLK1: +		clk_idx = ARIZONA_MCLK1; +		break; +	case ARIZONA_CLK_SRC_MCLK2: +		clk_idx = ARIZONA_MCLK2; +		break; +	default: +		return 0; +	} + +	switch (event) { +	case SND_SOC_DAPM_PRE_PMU: +		return clk_prepare_enable(arizona->mclk[clk_idx]); +	case SND_SOC_DAPM_POST_PMD: +		clk_disable_unprepare(arizona->mclk[clk_idx]); +		return 0; +	default: +		return 0; +	} +} +EXPORT_SYMBOL_GPL(arizona_clk_ev); +  int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,  		       int source, unsigned int freq, int dir)  { @@ -2242,6 +2291,42 @@ static int arizona_is_enabled_fll(struct arizona_fll *fll, int base)  	return reg & ARIZONA_FLL1_ENA;  } +static int arizona_set_fll_clks(struct arizona_fll *fll, int base, bool ena) +{ +	struct arizona *arizona = fll->arizona; +	unsigned int val; +	struct clk *clk; +	int ret; + +	ret = regmap_read(arizona->regmap, base + 6, &val); +	if (ret != 0) { +		arizona_fll_err(fll, "Failed to read current source: %d\n", +				ret); +		return ret; +	} + +	val &= ARIZONA_FLL1_CLK_REF_SRC_MASK; +	val >>= ARIZONA_FLL1_CLK_REF_SRC_SHIFT; + +	switch (val) { +	case ARIZONA_FLL_SRC_MCLK1: +		clk = arizona->mclk[ARIZONA_MCLK1]; +		break; +	case ARIZONA_FLL_SRC_MCLK2: +		clk = arizona->mclk[ARIZONA_MCLK2]; +		break; +	default: +		return 0; +	} + +	if (ena) { +		return clk_prepare_enable(clk); +	} else { +		clk_disable_unprepare(clk); +		return 0; +	} +} +  static int arizona_enable_fll(struct arizona_fll *fll)  {  	struct arizona *arizona = fll->arizona; @@ -2264,6 +2349,10 @@ static int arizona_enable_fll(struct arizona_fll *fll)  		udelay(32);  		regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,  					 ARIZONA_FLL1_GAIN_MASK, 0); + +		if (arizona_is_enabled_fll(fll, fll->base + 0x10) > 0) +			arizona_set_fll_clks(fll, fll->base + 0x10, false); +		arizona_set_fll_clks(fll, fll->base, false);  	}  	/* @@ -2318,10 +2407,13 @@ static int arizona_enable_fll(struct arizona_fll *fll)  	if (!already_enabled)  		pm_runtime_get_sync(arizona->dev); -	if (use_sync) +	if (use_sync) { +		arizona_set_fll_clks(fll, fll->base + 0x10, true);  		regmap_update_bits_async(arizona->regmap, fll->base + 0x11,  					 ARIZONA_FLL1_SYNC_ENA,  					 ARIZONA_FLL1_SYNC_ENA); +	} +	arizona_set_fll_clks(fll, fll->base, true);  	regmap_update_bits_async(arizona->regmap, fll->base + 1,  				 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); @@ -2354,19 +2446,24 @@ static int arizona_enable_fll(struct arizona_fll *fll)  static void arizona_disable_fll(struct arizona_fll *fll)  {  	struct arizona *arizona = fll->arizona; -	bool change; +	bool ref_change, sync_change;  	regmap_update_bits_async(arizona->regmap, fll->base + 1,  				 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);  	regmap_update_bits_check(arizona->regmap, fll->base + 1, -				 ARIZONA_FLL1_ENA, 0, &change); -	regmap_update_bits(arizona->regmap, fll->base + 0x11, -			   ARIZONA_FLL1_SYNC_ENA, 0); +				 ARIZONA_FLL1_ENA, 0, &ref_change); +	regmap_update_bits_check(arizona->regmap, fll->base + 0x11, +				 ARIZONA_FLL1_SYNC_ENA, 0, &sync_change);  	regmap_update_bits_async(arizona->regmap, fll->base + 1,  				 ARIZONA_FLL1_FREERUN, 0); -	if (change) +	if (sync_change) +		arizona_set_fll_clks(fll, fll->base + 0x10, false); + +	if (ref_change) { +		arizona_set_fll_clks(fll, fll->base, false);  		pm_runtime_put_autosuspend(arizona->dev); +	}  }  int arizona_set_fll_refclk(struct arizona_fll *fll, int source, @@ -2598,30 +2695,6 @@ int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,  }  EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put); -int arizona_register_notifier(struct snd_soc_codec *codec, -			      struct notifier_block *nb, -			      int (*notify)(struct notifier_block *nb, -					    unsigned long action, void *data)) -{ -	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); -	struct arizona *arizona = priv->arizona; - -	nb->notifier_call = notify; - -	return blocking_notifier_chain_register(&arizona->notifier, nb); -} -EXPORT_SYMBOL_GPL(arizona_register_notifier); - -int arizona_unregister_notifier(struct snd_soc_codec *codec, -				struct notifier_block *nb) -{ -	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); -	struct arizona *arizona = priv->arizona; - -	return blocking_notifier_chain_unregister(&arizona->notifier, nb); -} -EXPORT_SYMBOL_GPL(arizona_unregister_notifier); -  MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");  MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");  MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 850aa338ba29..56707860657c 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -14,6 +14,8 @@  #define _ASOC_ARIZONA_H  #include <linux/completion.h> +#include <linux/notifier.h> +#include <linux/mfd/arizona/core.h>  #include <sound/soc.h> @@ -66,7 +68,6 @@  /* Notifier events */  #define ARIZONA_NOTIFY_VOICE_TRIGGER   0x1 -struct arizona;  struct wm_adsp;  struct arizona_dai_priv { @@ -255,26 +256,24 @@ extern const struct soc_enum arizona_output_anc_src[];  extern const struct snd_kcontrol_new arizona_voice_trigger_switch[]; -extern int arizona_in_ev(struct snd_soc_dapm_widget *w, -			 struct snd_kcontrol *kcontrol, -			 int event); -extern int arizona_out_ev(struct snd_soc_dapm_widget *w, -			  struct snd_kcontrol *kcontrol, -			  int event); -extern int arizona_hp_ev(struct snd_soc_dapm_widget *w, -			 struct snd_kcontrol *kcontrol, -			 int event); -extern int arizona_anc_ev(struct snd_soc_dapm_widget *w, -			  struct snd_kcontrol *kcontrol, -			  int event); - -extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, -				struct snd_ctl_elem_value *ucontrol); -extern int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, -				  struct snd_ctl_elem_value *ucontrol); - -extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, -			      int source, unsigned int freq, int dir); +int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, +		  int event); +int arizona_out_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, +		   int event); +int arizona_hp_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, +		  int event); +int arizona_anc_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, +		   int event); + +int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, +			 struct snd_ctl_elem_value *ucontrol); +int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, +			   struct snd_ctl_elem_value *ucontrol); + +int arizona_clk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, +		   int event); +int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, +		       unsigned int freq, int dir);  extern const struct snd_soc_dai_ops arizona_dai_ops;  extern const struct snd_soc_dai_ops arizona_simple_dai_ops; @@ -297,41 +296,57 @@ struct arizona_fll {  	char clock_ok_name[ARIZONA_FLL_NAME_LEN];  }; -extern int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags); -extern int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags); -extern int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w, -				  struct snd_kcontrol *kcontrol, int event); -extern void arizona_init_dvfs(struct arizona_priv *priv); - -extern int arizona_init_fll(struct arizona *arizona, int id, int base, -			    int lock_irq, int ok_irq, struct arizona_fll *fll); -extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source, -				  unsigned int Fref, unsigned int Fout); -extern int arizona_set_fll(struct arizona_fll *fll, int source, +int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags); +int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags); +int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w, +			   struct snd_kcontrol *kcontrol, int event); +void arizona_init_dvfs(struct arizona_priv *priv); + +int arizona_init_fll(struct arizona *arizona, int id, int base, +		     int lock_irq, int ok_irq, struct arizona_fll *fll); +int arizona_set_fll_refclk(struct arizona_fll *fll, int source,  			   unsigned int Fref, unsigned int Fout); +int arizona_set_fll(struct arizona_fll *fll, int source, +		    unsigned int Fref, unsigned int Fout); -extern int arizona_init_spk(struct snd_soc_codec *codec); -extern int arizona_init_gpio(struct snd_soc_codec *codec); -extern int arizona_init_mono(struct snd_soc_codec *codec); -extern int arizona_init_notifiers(struct snd_soc_codec *codec); +int arizona_init_spk(struct snd_soc_codec *codec); +int arizona_init_gpio(struct snd_soc_codec *codec); +int arizona_init_mono(struct snd_soc_codec *codec); +int arizona_init_notifiers(struct snd_soc_codec *codec); -extern int arizona_free_spk(struct snd_soc_codec *codec); +int arizona_init_spk_irqs(struct arizona *arizona); +int arizona_free_spk_irqs(struct arizona *arizona); -extern int arizona_init_dai(struct arizona_priv *priv, int dai); +int arizona_init_dai(struct arizona_priv *priv, int dai);  int arizona_set_output_mode(struct snd_soc_codec *codec, int output,  			    bool diff); -extern bool arizona_input_analog(struct snd_soc_codec *codec, int shift); +bool arizona_input_analog(struct snd_soc_codec *codec, int shift); + +const char *arizona_sample_rate_val_to_name(unsigned int rate_val); + +static inline int arizona_register_notifier(struct snd_soc_codec *codec, +					    struct notifier_block *nb, +					    int (*notify) +					    (struct notifier_block *nb, +					    unsigned long action, void *data)) +{ +	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); +	struct arizona *arizona = priv->arizona; + +	nb->notifier_call = notify; + +	return blocking_notifier_chain_register(&arizona->notifier, nb); +} -extern const char *arizona_sample_rate_val_to_name(unsigned int rate_val); +static inline int arizona_unregister_notifier(struct snd_soc_codec *codec, +					      struct notifier_block *nb) +{ +	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); +	struct arizona *arizona = priv->arizona; -extern int arizona_register_notifier(struct snd_soc_codec *codec, -				     struct notifier_block *nb, -				     int (*notify)(struct notifier_block *nb, -						   unsigned long action, -						   void *data)); -extern int arizona_unregister_notifier(struct snd_soc_codec *codec, -				       struct notifier_block *nb); +	return blocking_notifier_chain_unregister(&arizona->notifier, nb); +}  #endif diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c new file mode 100644 index 000000000000..7c5d1510cf2c --- /dev/null +++ b/sound/soc/codecs/cs35l34.c @@ -0,0 +1,1251 @@ +/* + * cs35l34.c -- CS35l34 ALSA SoC audio driver + * + * Copyright 2016 Cirrus Logic, Inc. + * + * Author: Paul Handrigan <Paul.Handrigan@cirrus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> +#include <linux/pm_runtime.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/of_irq.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <sound/cs35l34.h> + +#include "cs35l34.h" + +#define PDN_DONE_ATTEMPTS 10 +#define CS35L34_START_DELAY 50 + +struct  cs35l34_private { +	struct snd_soc_codec *codec; +	struct cs35l34_platform_data pdata; +	struct regmap *regmap; +	struct regulator_bulk_data core_supplies[2]; +	int num_core_supplies; +	int mclk_int; +	bool tdm_mode; +	struct gpio_desc *reset_gpio;	/* Active-low reset GPIO */ +}; + +static const struct reg_default cs35l34_reg[] = { +	{CS35L34_PWRCTL1, 0x01}, +	{CS35L34_PWRCTL2, 0x19}, +	{CS35L34_PWRCTL3, 0x01}, +	{CS35L34_ADSP_CLK_CTL, 0x08}, +	{CS35L34_MCLK_CTL, 0x11}, +	{CS35L34_AMP_INP_DRV_CTL, 0x01}, +	{CS35L34_AMP_DIG_VOL_CTL, 0x12}, +	{CS35L34_AMP_DIG_VOL, 0x00}, +	{CS35L34_AMP_ANLG_GAIN_CTL, 0x0F}, +	{CS35L34_PROTECT_CTL, 0x06}, +	{CS35L34_AMP_KEEP_ALIVE_CTL, 0x04}, +	{CS35L34_BST_CVTR_V_CTL, 0x00}, +	{CS35L34_BST_PEAK_I, 0x10}, +	{CS35L34_BST_RAMP_CTL, 0x87}, +	{CS35L34_BST_CONV_COEF_1, 0x24}, +	{CS35L34_BST_CONV_COEF_2, 0x24}, +	{CS35L34_BST_CONV_SLOPE_COMP, 0x4E}, +	{CS35L34_BST_CONV_SW_FREQ, 0x08}, +	{CS35L34_CLASS_H_CTL, 0x0D}, +	{CS35L34_CLASS_H_HEADRM_CTL, 0x0D}, +	{CS35L34_CLASS_H_RELEASE_RATE, 0x08}, +	{CS35L34_CLASS_H_FET_DRIVE_CTL, 0x41}, +	{CS35L34_CLASS_H_STATUS, 0x05}, +	{CS35L34_VPBR_CTL, 0x0A}, +	{CS35L34_VPBR_VOL_CTL, 0x90}, +	{CS35L34_VPBR_TIMING_CTL, 0x6A}, +	{CS35L34_PRED_MAX_ATTEN_SPK_LOAD, 0x95}, +	{CS35L34_PRED_BROWNOUT_THRESH, 0x1C}, +	{CS35L34_PRED_BROWNOUT_VOL_CTL, 0x00}, +	{CS35L34_PRED_BROWNOUT_RATE_CTL, 0x10}, +	{CS35L34_PRED_WAIT_CTL, 0x10}, +	{CS35L34_PRED_ZVP_INIT_IMP_CTL, 0x08}, +	{CS35L34_PRED_MAN_SAFE_VPI_CTL, 0x80}, +	{CS35L34_VPBR_ATTEN_STATUS, 0x00}, +	{CS35L34_PRED_BRWNOUT_ATT_STATUS, 0x00}, +	{CS35L34_SPKR_MON_CTL, 0xC6}, +	{CS35L34_ADSP_I2S_CTL, 0x00}, +	{CS35L34_ADSP_TDM_CTL, 0x00}, +	{CS35L34_TDM_TX_CTL_1_VMON, 0x00}, +	{CS35L34_TDM_TX_CTL_2_IMON, 0x04}, +	{CS35L34_TDM_TX_CTL_3_VPMON, 0x03}, +	{CS35L34_TDM_TX_CTL_4_VBSTMON, 0x07}, +	{CS35L34_TDM_TX_CTL_5_FLAG1, 0x08}, +	{CS35L34_TDM_TX_CTL_6_FLAG2, 0x09}, +	{CS35L34_TDM_TX_SLOT_EN_1, 0x00}, +	{CS35L34_TDM_TX_SLOT_EN_2, 0x00}, +	{CS35L34_TDM_TX_SLOT_EN_3, 0x00}, +	{CS35L34_TDM_TX_SLOT_EN_4, 0x00}, +	{CS35L34_TDM_RX_CTL_1_AUDIN, 0x40}, +	{CS35L34_TDM_RX_CTL_3_ALIVE, 0x04}, +	{CS35L34_MULT_DEV_SYNCH1, 0x00}, +	{CS35L34_MULT_DEV_SYNCH2, 0x80}, +	{CS35L34_PROT_RELEASE_CTL, 0x00}, +	{CS35L34_DIAG_MODE_REG_LOCK, 0x00}, +	{CS35L34_DIAG_MODE_CTL_1, 0x00}, +	{CS35L34_DIAG_MODE_CTL_2, 0x00}, +	{CS35L34_INT_MASK_1, 0xFF}, +	{CS35L34_INT_MASK_2, 0xFF}, +	{CS35L34_INT_MASK_3, 0xFF}, +	{CS35L34_INT_MASK_4, 0xFF}, +	{CS35L34_INT_STATUS_1, 0x30}, +	{CS35L34_INT_STATUS_2, 0x05}, +	{CS35L34_INT_STATUS_3, 0x00}, +	{CS35L34_INT_STATUS_4, 0x00}, +	{CS35L34_OTP_TRIM_STATUS, 0x00}, +}; + +static bool cs35l34_volatile_register(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case CS35L34_DEVID_AB: +	case CS35L34_DEVID_CD: +	case CS35L34_DEVID_E: +	case CS35L34_FAB_ID: +	case CS35L34_REV_ID: +	case CS35L34_INT_STATUS_1: +	case CS35L34_INT_STATUS_2: +	case CS35L34_INT_STATUS_3: +	case CS35L34_INT_STATUS_4: +	case CS35L34_CLASS_H_STATUS: +	case CS35L34_VPBR_ATTEN_STATUS: +	case CS35L34_OTP_TRIM_STATUS: +		return true; +	default: +		return false; +	} +} + +static bool cs35l34_readable_register(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case	CS35L34_DEVID_AB: +	case	CS35L34_DEVID_CD: +	case	CS35L34_DEVID_E: +	case	CS35L34_FAB_ID: +	case	CS35L34_REV_ID: +	case	CS35L34_PWRCTL1: +	case	CS35L34_PWRCTL2: +	case	CS35L34_PWRCTL3: +	case	CS35L34_ADSP_CLK_CTL: +	case	CS35L34_MCLK_CTL: +	case	CS35L34_AMP_INP_DRV_CTL: +	case	CS35L34_AMP_DIG_VOL_CTL: +	case	CS35L34_AMP_DIG_VOL: +	case	CS35L34_AMP_ANLG_GAIN_CTL: +	case	CS35L34_PROTECT_CTL: +	case	CS35L34_AMP_KEEP_ALIVE_CTL: +	case	CS35L34_BST_CVTR_V_CTL: +	case	CS35L34_BST_PEAK_I: +	case	CS35L34_BST_RAMP_CTL: +	case	CS35L34_BST_CONV_COEF_1: +	case	CS35L34_BST_CONV_COEF_2: +	case	CS35L34_BST_CONV_SLOPE_COMP: +	case	CS35L34_BST_CONV_SW_FREQ: +	case	CS35L34_CLASS_H_CTL: +	case	CS35L34_CLASS_H_HEADRM_CTL: +	case	CS35L34_CLASS_H_RELEASE_RATE: +	case	CS35L34_CLASS_H_FET_DRIVE_CTL: +	case	CS35L34_CLASS_H_STATUS: +	case	CS35L34_VPBR_CTL: +	case	CS35L34_VPBR_VOL_CTL: +	case	CS35L34_VPBR_TIMING_CTL: +	case	CS35L34_PRED_MAX_ATTEN_SPK_LOAD: +	case	CS35L34_PRED_BROWNOUT_THRESH: +	case	CS35L34_PRED_BROWNOUT_VOL_CTL: +	case	CS35L34_PRED_BROWNOUT_RATE_CTL: +	case	CS35L34_PRED_WAIT_CTL: +	case	CS35L34_PRED_ZVP_INIT_IMP_CTL: +	case	CS35L34_PRED_MAN_SAFE_VPI_CTL: +	case	CS35L34_VPBR_ATTEN_STATUS: +	case	CS35L34_PRED_BRWNOUT_ATT_STATUS: +	case	CS35L34_SPKR_MON_CTL: +	case	CS35L34_ADSP_I2S_CTL: +	case	CS35L34_ADSP_TDM_CTL: +	case	CS35L34_TDM_TX_CTL_1_VMON: +	case	CS35L34_TDM_TX_CTL_2_IMON: +	case	CS35L34_TDM_TX_CTL_3_VPMON: +	case	CS35L34_TDM_TX_CTL_4_VBSTMON: +	case	CS35L34_TDM_TX_CTL_5_FLAG1: +	case	CS35L34_TDM_TX_CTL_6_FLAG2: +	case	CS35L34_TDM_TX_SLOT_EN_1: +	case	CS35L34_TDM_TX_SLOT_EN_2: +	case	CS35L34_TDM_TX_SLOT_EN_3: +	case	CS35L34_TDM_TX_SLOT_EN_4: +	case	CS35L34_TDM_RX_CTL_1_AUDIN: +	case	CS35L34_TDM_RX_CTL_3_ALIVE: +	case	CS35L34_MULT_DEV_SYNCH1: +	case	CS35L34_MULT_DEV_SYNCH2: +	case	CS35L34_PROT_RELEASE_CTL: +	case	CS35L34_DIAG_MODE_REG_LOCK: +	case	CS35L34_DIAG_MODE_CTL_1: +	case	CS35L34_DIAG_MODE_CTL_2: +	case	CS35L34_INT_MASK_1: +	case	CS35L34_INT_MASK_2: +	case	CS35L34_INT_MASK_3: +	case	CS35L34_INT_MASK_4: +	case	CS35L34_INT_STATUS_1: +	case	CS35L34_INT_STATUS_2: +	case	CS35L34_INT_STATUS_3: +	case	CS35L34_INT_STATUS_4: +	case	CS35L34_OTP_TRIM_STATUS: +		return true; +	default: +		return false; +	} +} + +static bool cs35l34_precious_register(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case CS35L34_INT_STATUS_1: +	case CS35L34_INT_STATUS_2: +	case CS35L34_INT_STATUS_3: +	case CS35L34_INT_STATUS_4: +		return true; +	default: +		return false; +	} +} + +static int cs35l34_sdin_event(struct snd_soc_dapm_widget *w, +		struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); +	struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); +	int ret; + +	switch (event) { +	case SND_SOC_DAPM_PRE_PMU: +		if (priv->tdm_mode) +			regmap_update_bits(priv->regmap, CS35L34_PWRCTL3, +						CS35L34_PDN_TDM, 0x00); + +		ret = regmap_update_bits(priv->regmap, CS35L34_PWRCTL1, +						CS35L34_PDN_ALL, 0); +		if (ret < 0) { +			dev_err(codec->dev, "Cannot set Power bits %d\n", ret); +			return ret; +		} +		usleep_range(5000, 5100); +	break; +	case SND_SOC_DAPM_POST_PMD: +		if (priv->tdm_mode) { +			regmap_update_bits(priv->regmap, CS35L34_PWRCTL3, +					CS35L34_PDN_TDM, CS35L34_PDN_TDM); +		} +		ret = regmap_update_bits(priv->regmap, CS35L34_PWRCTL1, +					CS35L34_PDN_ALL, CS35L34_PDN_ALL); +	break; +	default: +		pr_err("Invalid event = 0x%x\n", event); +	} +	return 0; +} + +static int cs35l34_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, +				unsigned int rx_mask, int slots, int slot_width) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); +	unsigned int reg, bit_pos; +	int slot, slot_num; + +	if (slot_width != 8) +		return -EINVAL; + +	priv->tdm_mode = true; +	/* scan rx_mask for aud slot */ +	slot = ffs(rx_mask) - 1; +	if (slot >= 0) +		snd_soc_update_bits(codec, CS35L34_TDM_RX_CTL_1_AUDIN, +					CS35L34_X_LOC, slot); + +	/* scan tx_mask: vmon(2 slots); imon (2 slots); vpmon (1 slot) +	 * vbstmon (1 slot) +	 */ +	slot = ffs(tx_mask) - 1; +	slot_num = 0; + +	/* disable vpmon/vbstmon: enable later if set in tx_mask */ +	snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_3_VPMON, +				CS35L34_X_STATE | CS35L34_X_LOC, +				CS35L34_X_STATE | CS35L34_X_LOC); +	snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_4_VBSTMON, +				CS35L34_X_STATE | CS35L34_X_LOC, +				CS35L34_X_STATE | CS35L34_X_LOC); + +	/* disconnect {vp,vbst}_mon routes: eanble later if set in tx_mask*/ +	while (slot >= 0) { +		/* configure VMON_TX_LOC */ +		if (slot_num == 0) +			snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_1_VMON, +					CS35L34_X_STATE | CS35L34_X_LOC, slot); + +		/* configure IMON_TX_LOC */ +		if (slot_num == 4) { +			snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_2_IMON, +					CS35L34_X_STATE | CS35L34_X_LOC, slot); +		} +		/* configure VPMON_TX_LOC */ +		if (slot_num == 3) { +			snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_3_VPMON, +					CS35L34_X_STATE | CS35L34_X_LOC, slot); +		} +		/* configure VBSTMON_TX_LOC */ +		if (slot_num == 7) { +			snd_soc_update_bits(codec, +				CS35L34_TDM_TX_CTL_4_VBSTMON, +				CS35L34_X_STATE | CS35L34_X_LOC, slot); +		} + +		/* Enable the relevant tx slot */ +		reg = CS35L34_TDM_TX_SLOT_EN_4 - (slot/8); +		bit_pos = slot - ((slot / 8) * (8)); +		snd_soc_update_bits(codec, reg, +			1 << bit_pos, 1 << bit_pos); + +		tx_mask &= ~(1 << slot); +		slot = ffs(tx_mask) - 1; +		slot_num++; +	} + +	return 0; +} + +static int cs35l34_main_amp_event(struct snd_soc_dapm_widget *w, +		struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); +	struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		regmap_update_bits(priv->regmap, CS35L34_BST_CVTR_V_CTL, +				CS35L34_BST_CVTL_MASK, priv->pdata.boost_vtge); +		usleep_range(5000, 5100); +		regmap_update_bits(priv->regmap, CS35L34_PROTECT_CTL, +						CS35L34_MUTE, 0); +		break; +	case SND_SOC_DAPM_POST_PMD: +		regmap_update_bits(priv->regmap, CS35L34_BST_CVTR_V_CTL, +			CS35L34_BST_CVTL_MASK, 0); +		regmap_update_bits(priv->regmap, CS35L34_PROTECT_CTL, +			CS35L34_MUTE, CS35L34_MUTE); +		usleep_range(5000, 5100); +		break; +	default: +		pr_err("Invalid event = 0x%x\n", event); +	} +	return 0; +} + +static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 50, 0); + +static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 300, 100, 0); + + +static const struct snd_kcontrol_new cs35l34_snd_controls[] = { +	SOC_SINGLE_SX_TLV("Digital Volume", CS35L34_AMP_DIG_VOL, +		      0, 0x34, 0xE4, dig_vol_tlv), +	SOC_SINGLE_TLV("Amp Gain Volume", CS35L34_AMP_ANLG_GAIN_CTL, +		      0, 0xF, 0, amp_gain_tlv), +}; + + +static int cs35l34_mclk_event(struct snd_soc_dapm_widget *w, +		struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); +	struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); +	int ret, i; +	unsigned int reg; + +	switch (event) { +	case SND_SOC_DAPM_PRE_PMD: +		ret = regmap_read(priv->regmap, CS35L34_AMP_DIG_VOL_CTL, +			®); +		if (ret != 0) { +			pr_err("%s regmap read failure %d\n", __func__, ret); +			return ret; +		} +		if (reg & CS35L34_AMP_DIGSFT) +			msleep(40); +		else +			usleep_range(2000, 2100); + +		for (i = 0; i < PDN_DONE_ATTEMPTS; i++) { +			ret = regmap_read(priv->regmap, CS35L34_INT_STATUS_2, +				®); +			if (ret != 0) { +				pr_err("%s regmap read failure %d\n", +					__func__, ret); +				return ret; +			} +			if (reg & CS35L34_PDN_DONE) +				break; + +			usleep_range(5000, 5100); +		} +		if (i == PDN_DONE_ATTEMPTS) +			pr_err("%s Device did not power down properly\n", +				__func__); +		break; +	default: +		pr_err("Invalid event = 0x%x\n", event); +		break; +	} +	return 0; +} + +static const struct snd_soc_dapm_widget cs35l34_dapm_widgets[] = { +	SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L34_PWRCTL3, +					1, 1, cs35l34_sdin_event, +					SND_SOC_DAPM_PRE_PMU | +					SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L34_PWRCTL3, 2, 1), + +	SND_SOC_DAPM_SUPPLY("EXTCLK", CS35L34_PWRCTL3, 7, 1, +		cs35l34_mclk_event, SND_SOC_DAPM_PRE_PMD), + +	SND_SOC_DAPM_OUTPUT("SPK"), + +	SND_SOC_DAPM_INPUT("VP"), +	SND_SOC_DAPM_INPUT("VPST"), +	SND_SOC_DAPM_INPUT("ISENSE"), +	SND_SOC_DAPM_INPUT("VSENSE"), + +	SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L34_PWRCTL2, 7, 1), +	SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L34_PWRCTL2, 6, 1), +	SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L34_PWRCTL3, 3, 1), +	SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L34_PWRCTL3, 4, 1), +	SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L34_PWRCTL2, 5, 1), +	SND_SOC_DAPM_ADC("BOOST", NULL, CS35L34_PWRCTL2, 2, 1), + +	SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L34_PWRCTL2, 0, 1, NULL, 0, +		cs35l34_main_amp_event, SND_SOC_DAPM_POST_PMU | +			SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route cs35l34_audio_map[] = { +	{"SDIN", NULL, "AMP Playback"}, +	{"BOOST", NULL, "SDIN"}, +	{"CLASS H", NULL, "BOOST"}, +	{"Main AMP", NULL, "CLASS H"}, +	{"SPK", NULL, "Main AMP"}, + +	{"VPMON ADC", NULL, "CLASS H"}, +	{"VBSTMON ADC", NULL, "CLASS H"}, +	{"SPK", NULL, "VPMON ADC"}, +	{"SPK", NULL, "VBSTMON ADC"}, + +	{"IMON ADC", NULL, "ISENSE"}, +	{"VMON ADC", NULL, "VSENSE"}, +	{"SDOUT", NULL, "IMON ADC"}, +	{"SDOUT", NULL, "VMON ADC"}, +	{"AMP Capture", NULL, "SDOUT"}, + +	{"SDIN", NULL, "EXTCLK"}, +	{"SDOUT", NULL, "EXTCLK"}, +}; + +struct cs35l34_mclk_div { +	int mclk; +	int srate; +	u8 adsp_rate; +}; + +static struct cs35l34_mclk_div cs35l34_mclk_coeffs[] = { + +	/* MCLK, Sample Rate, adsp_rate */ + +	{5644800, 11025, 0x1}, +	{5644800, 22050, 0x4}, +	{5644800, 44100, 0x7}, + +	{6000000,  8000, 0x0}, +	{6000000, 11025, 0x1}, +	{6000000, 12000, 0x2}, +	{6000000, 16000, 0x3}, +	{6000000, 22050, 0x4}, +	{6000000, 24000, 0x5}, +	{6000000, 32000, 0x6}, +	{6000000, 44100, 0x7}, +	{6000000, 48000, 0x8}, + +	{6144000,  8000, 0x0}, +	{6144000, 11025, 0x1}, +	{6144000, 12000, 0x2}, +	{6144000, 16000, 0x3}, +	{6144000, 22050, 0x4}, +	{6144000, 24000, 0x5}, +	{6144000, 32000, 0x6}, +	{6144000, 44100, 0x7}, +	{6144000, 48000, 0x8}, +}; + +static int cs35l34_get_mclk_coeff(int mclk, int srate) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(cs35l34_mclk_coeffs); i++) { +		if (cs35l34_mclk_coeffs[i].mclk == mclk && +			cs35l34_mclk_coeffs[i].srate == srate) +			return i; +	} +	return -EINVAL; +} + +static int cs35l34_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ +	struct snd_soc_codec *codec = codec_dai->codec; +	struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); + +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBM_CFM: +		regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL, +				    0x80, 0x80); +		break; +	case SND_SOC_DAIFMT_CBS_CFS: +		regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL, +				    0x80, 0x00); +		break; +	default: +		return -EINVAL; +	} +	return 0; +} + +static int cs35l34_pcm_hw_params(struct snd_pcm_substream *substream, +				 struct snd_pcm_hw_params *params, +				 struct snd_soc_dai *dai) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); +	int srate = params_rate(params); +	int ret; + +	int coeff = cs35l34_get_mclk_coeff(priv->mclk_int, srate); + +	if (coeff < 0) { +		dev_err(codec->dev, "ERROR: Invalid mclk %d and/or srate %d\n", +			priv->mclk_int, srate); +		return coeff; +	} + +	ret = regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL, +		CS35L34_ADSP_RATE, cs35l34_mclk_coeffs[coeff].adsp_rate); +	if (ret != 0) +		dev_err(codec->dev, "Failed to set clock state %d\n", ret); + +	return ret; +} + +static unsigned int cs35l34_src_rates[] = { +	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 +}; + + +static struct snd_pcm_hw_constraint_list cs35l34_constraints = { +	.count  = ARRAY_SIZE(cs35l34_src_rates), +	.list   = cs35l34_src_rates, +}; + +static int cs35l34_pcm_startup(struct snd_pcm_substream *substream, +			       struct snd_soc_dai *dai) +{ + +	snd_pcm_hw_constraint_list(substream->runtime, 0, +				SNDRV_PCM_HW_PARAM_RATE, &cs35l34_constraints); +	return 0; +} + + +static int cs35l34_set_tristate(struct snd_soc_dai *dai, int tristate) +{ + +	struct snd_soc_codec *codec = dai->codec; + +	if (tristate) +		snd_soc_update_bits(codec, CS35L34_PWRCTL3, +					CS35L34_PDN_SDOUT, CS35L34_PDN_SDOUT); +	else +		snd_soc_update_bits(codec, CS35L34_PWRCTL3, +					CS35L34_PDN_SDOUT, 0); +	return 0; +} + +static int cs35l34_dai_set_sysclk(struct snd_soc_dai *dai, +				int clk_id, unsigned int freq, int dir) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct cs35l34_private *cs35l34 = snd_soc_codec_get_drvdata(codec); +	unsigned int value; + +	switch (freq) { +	case CS35L34_MCLK_5644: +		value = CS35L34_MCLK_RATE_5P6448; +		cs35l34->mclk_int = freq; +	break; +	case CS35L34_MCLK_6: +		value = CS35L34_MCLK_RATE_6P0000; +		cs35l34->mclk_int = freq; +	break; +	case CS35L34_MCLK_6144: +		value = CS35L34_MCLK_RATE_6P1440; +		cs35l34->mclk_int = freq; +	break; +	case CS35L34_MCLK_11289: +		value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_5P6448; +		cs35l34->mclk_int = freq / 2; +	break; +	case CS35L34_MCLK_12: +		value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_6P0000; +		cs35l34->mclk_int = freq / 2; +	break; +	case CS35L34_MCLK_12288: +		value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_6P1440; +		cs35l34->mclk_int = freq / 2; +	break; +	default: +		dev_err(codec->dev, "ERROR: Invalid Frequency %d\n", freq); +		cs35l34->mclk_int = 0; +		return -EINVAL; +	} +	regmap_update_bits(cs35l34->regmap, CS35L34_MCLK_CTL, +			CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_MASK, value); +	return 0; +} + +static const struct snd_soc_dai_ops cs35l34_ops = { +	.startup = cs35l34_pcm_startup, +	.set_tristate = cs35l34_set_tristate, +	.set_fmt = cs35l34_set_dai_fmt, +	.hw_params = cs35l34_pcm_hw_params, +	.set_sysclk = cs35l34_dai_set_sysclk, +	.set_tdm_slot = cs35l34_set_tdm_slot, +}; + +static struct snd_soc_dai_driver cs35l34_dai = { +		.name = "cs35l34", +		.id = 0, +		.playback = { +			.stream_name = "AMP Playback", +			.channels_min = 1, +			.channels_max = 8, +			.rates = CS35L34_RATES, +			.formats = CS35L34_FORMATS, +		}, +		.capture = { +			.stream_name = "AMP Capture", +			.channels_min = 1, +			.channels_max = 8, +			.rates = CS35L34_RATES, +			.formats = CS35L34_FORMATS, +		}, +		.ops = &cs35l34_ops, +		.symmetric_rates = 1, +}; + +static int cs35l34_boost_inductor(struct cs35l34_private *cs35l34, +	unsigned int inductor) +{ +	struct snd_soc_codec *codec = cs35l34->codec; + +	switch (inductor) { +	case 1000: /* 1 uH */ +		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x24); +		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x24); +		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP, +			0x4E); +		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 0); +		break; +	case 1200: /* 1.2 uH */ +		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x20); +		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x20); +		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP, +			0x47); +		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 1); +		break; +	case 1500: /* 1.5uH */ +		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x20); +		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x20); +		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP, +			0x3C); +		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 2); +		break; +	case 2200: /* 2.2uH */ +		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x19); +		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x25); +		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP, +			0x23); +		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 3); +		break; +	default: +		dev_err(codec->dev, "%s Invalid Inductor Value %d uH\n", +			__func__, inductor); +		return -EINVAL; +	} +	return 0; +} + +static int cs35l34_probe(struct snd_soc_codec *codec) +{ +	int ret = 0; +	struct cs35l34_private *cs35l34 = snd_soc_codec_get_drvdata(codec); + +	pm_runtime_get_sync(codec->dev); + +	/* Set over temperature warning attenuation to 6 dB */ +	regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL, +		 CS35L34_OTW_ATTN_MASK, 0x8); + +	/* Set Power control registers 2 and 3 to have everything +	 * powered down at initialization +	 */ +	regmap_write(cs35l34->regmap, CS35L34_PWRCTL2, 0xFD); +	regmap_write(cs35l34->regmap, CS35L34_PWRCTL3, 0x1F); + +	/* Set mute bit at startup */ +	regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL, +				CS35L34_MUTE, CS35L34_MUTE); + +	/* Set Platform Data */ +	if (cs35l34->pdata.boost_peak) +		regmap_update_bits(cs35l34->regmap, CS35L34_BST_PEAK_I, +				CS35L34_BST_PEAK_MASK, +				cs35l34->pdata.boost_peak); + +	if (cs35l34->pdata.gain_zc_disable) +		regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL, +			CS35L34_GAIN_ZC_MASK, 0); +	else +		regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL, +			CS35L34_GAIN_ZC_MASK, CS35L34_GAIN_ZC_MASK); + +	if (cs35l34->pdata.aif_half_drv) +		regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_CLK_CTL, +			CS35L34_ADSP_DRIVE, 0); + +	if (cs35l34->pdata.digsft_disable) +		regmap_update_bits(cs35l34->regmap, CS35L34_AMP_DIG_VOL_CTL, +			CS35L34_AMP_DIGSFT, 0); + +	if (cs35l34->pdata.amp_inv) +		regmap_update_bits(cs35l34->regmap, CS35L34_AMP_DIG_VOL_CTL, +			CS35L34_INV, CS35L34_INV); + +	if (cs35l34->pdata.boost_ind) +		ret = cs35l34_boost_inductor(cs35l34, cs35l34->pdata.boost_ind); + +	if (cs35l34->pdata.i2s_sdinloc) +		regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_I2S_CTL, +			CS35L34_I2S_LOC_MASK, +			cs35l34->pdata.i2s_sdinloc << CS35L34_I2S_LOC_SHIFT); + +	if (cs35l34->pdata.tdm_rising_edge) +		regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_TDM_CTL, +			1, 1); + +	pm_runtime_put_sync(codec->dev); + +	return ret; +} + + +static struct snd_soc_codec_driver soc_codec_dev_cs35l34 = { +	.probe = cs35l34_probe, + +	.component_driver = { +		.dapm_widgets = cs35l34_dapm_widgets, +		.num_dapm_widgets = ARRAY_SIZE(cs35l34_dapm_widgets), +		.dapm_routes = cs35l34_audio_map, +		.num_dapm_routes = ARRAY_SIZE(cs35l34_audio_map), +		.controls = cs35l34_snd_controls, +		.num_controls = ARRAY_SIZE(cs35l34_snd_controls), +	}, +}; + +static struct regmap_config cs35l34_regmap = { +	.reg_bits = 8, +	.val_bits = 8, + +	.max_register = CS35L34_MAX_REGISTER, +	.reg_defaults = cs35l34_reg, +	.num_reg_defaults = ARRAY_SIZE(cs35l34_reg), +	.volatile_reg = cs35l34_volatile_register, +	.readable_reg = cs35l34_readable_register, +	.precious_reg = cs35l34_precious_register, +	.cache_type = REGCACHE_RBTREE, +}; + +static int cs35l34_handle_of_data(struct i2c_client *i2c_client, +				struct cs35l34_platform_data *pdata) +{ +	struct device_node *np = i2c_client->dev.of_node; +	unsigned int val; + +	if (of_property_read_u32(np, "cirrus,boost-vtge-millivolt", +		&val) >= 0) { +		/* Boost Voltage has a maximum of 8V */ +		if (val > 8000 || (val < 3300 && val > 0)) { +			dev_err(&i2c_client->dev, +				"Invalid Boost Voltage %d mV\n", val); +			return -EINVAL; +		} +		if (val == 0) +			pdata->boost_vtge = 0; /* Use VP */ +		else +			pdata->boost_vtge = ((val - 3300)/100) + 1; +	} else { +		dev_warn(&i2c_client->dev, +			"Boost Voltage not specified. Using VP\n"); +	} + +	if (of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val) >= 0) { +		pdata->boost_ind = val; +	} else { +		dev_err(&i2c_client->dev, "Inductor not specified.\n"); +		return -EINVAL; +	} + +	if (of_property_read_u32(np, "cirrus,boost-peak-milliamp", &val) >= 0) { +		if (val > 3840 || val < 1200) { +			dev_err(&i2c_client->dev, +				"Invalid Boost Peak Current %d mA\n", val); +			return -EINVAL; +		} +		pdata->boost_peak = ((val - 1200)/80) + 1; +	} + +	pdata->aif_half_drv = of_property_read_bool(np, +		"cirrus,aif-half-drv"); +	pdata->digsft_disable = of_property_read_bool(np, +		"cirrus,digsft-disable"); + +	pdata->gain_zc_disable = of_property_read_bool(np, +		"cirrus,gain-zc-disable"); +	pdata->amp_inv = of_property_read_bool(np, "cirrus,amp-inv"); + +	if (of_property_read_u32(np, "cirrus,i2s-sdinloc", &val) >= 0) +		pdata->i2s_sdinloc = val; +	if (of_property_read_u32(np, "cirrus,tdm-rising-edge", &val) >= 0) +		pdata->tdm_rising_edge = val; + +	return 0; +} + +static irqreturn_t cs35l34_irq_thread(int irq, void *data) +{ +	struct cs35l34_private *cs35l34 = data; +	struct snd_soc_codec *codec = cs35l34->codec; +	unsigned int sticky1, sticky2, sticky3, sticky4; +	unsigned int mask1, mask2, mask3, mask4, current1; + + +	/* ack the irq by reading all status registers */ +	regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_4, &sticky4); +	regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_3, &sticky3); +	regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_2, &sticky2); +	regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_1, &sticky1); + +	regmap_read(cs35l34->regmap, CS35L34_INT_MASK_4, &mask4); +	regmap_read(cs35l34->regmap, CS35L34_INT_MASK_3, &mask3); +	regmap_read(cs35l34->regmap, CS35L34_INT_MASK_2, &mask2); +	regmap_read(cs35l34->regmap, CS35L34_INT_MASK_1, &mask1); + +	if (!(sticky1 & ~mask1) && !(sticky2 & ~mask2) && !(sticky3 & ~mask3) +		&& !(sticky4 & ~mask4)) +		return IRQ_NONE; + +	regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_1, ¤t1); + +	if (sticky1 & CS35L34_CAL_ERR) { +		dev_err(codec->dev, "Cal error\n"); + +		/* error is no longer asserted; safe to reset */ +		if (!(current1 & CS35L34_CAL_ERR)) { +			dev_dbg(codec->dev, "Cal error release\n"); +			regmap_update_bits(cs35l34->regmap, +					CS35L34_PROT_RELEASE_CTL, +					CS35L34_CAL_ERR_RLS, 0); +			regmap_update_bits(cs35l34->regmap, +					CS35L34_PROT_RELEASE_CTL, +					CS35L34_CAL_ERR_RLS, +					CS35L34_CAL_ERR_RLS); +			regmap_update_bits(cs35l34->regmap, +					CS35L34_PROT_RELEASE_CTL, +					CS35L34_CAL_ERR_RLS, 0); +			/* note: amp will re-calibrate on next resume */ +		} +	} + +	if (sticky1 & CS35L34_ALIVE_ERR) +		dev_err(codec->dev, "Alive error\n"); + +	if (sticky1 & CS35L34_AMP_SHORT) { +		dev_crit(codec->dev, "Amp short error\n"); + +		/* error is no longer asserted; safe to reset */ +		if (!(current1 & CS35L34_AMP_SHORT)) { +			dev_dbg(codec->dev, +				"Amp short error release\n"); +			regmap_update_bits(cs35l34->regmap, +					CS35L34_PROT_RELEASE_CTL, +					CS35L34_SHORT_RLS, 0); +			regmap_update_bits(cs35l34->regmap, +					CS35L34_PROT_RELEASE_CTL, +					CS35L34_SHORT_RLS, +					CS35L34_SHORT_RLS); +			regmap_update_bits(cs35l34->regmap, +					CS35L34_PROT_RELEASE_CTL, +					CS35L34_SHORT_RLS, 0); +		} +	} + +	if (sticky1 & CS35L34_OTW) { +		dev_crit(codec->dev, "Over temperature warning\n"); + +		/* error is no longer asserted; safe to reset */ +		if (!(current1 & CS35L34_OTW)) { +			dev_dbg(codec->dev, +				"Over temperature warning release\n"); +			regmap_update_bits(cs35l34->regmap, +					CS35L34_PROT_RELEASE_CTL, +					CS35L34_OTW_RLS, 0); +			regmap_update_bits(cs35l34->regmap, +					CS35L34_PROT_RELEASE_CTL, +					CS35L34_OTW_RLS, +					CS35L34_OTW_RLS); +			regmap_update_bits(cs35l34->regmap, +					CS35L34_PROT_RELEASE_CTL, +					CS35L34_OTW_RLS, 0); +		} +	} + +	if (sticky1 & CS35L34_OTE) { +		dev_crit(codec->dev, "Over temperature error\n"); + +		/* error is no longer asserted; safe to reset */ +		if (!(current1 & CS35L34_OTE)) { +			dev_dbg(codec->dev, +				"Over temperature error release\n"); +			regmap_update_bits(cs35l34->regmap, +					CS35L34_PROT_RELEASE_CTL, +					CS35L34_OTE_RLS, 0); +			regmap_update_bits(cs35l34->regmap, +					CS35L34_PROT_RELEASE_CTL, +					CS35L34_OTE_RLS, +					CS35L34_OTE_RLS); +			regmap_update_bits(cs35l34->regmap, +					CS35L34_PROT_RELEASE_CTL, +					CS35L34_OTE_RLS, 0); +		} +	} + +	if (sticky3 & CS35L34_BST_HIGH) { +		dev_crit(codec->dev, "VBST too high error; powering off!\n"); +		regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL2, +				CS35L34_PDN_AMP, CS35L34_PDN_AMP); +		regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL1, +				CS35L34_PDN_ALL, CS35L34_PDN_ALL); +	} + +	if (sticky3 & CS35L34_LBST_SHORT) { +		dev_crit(codec->dev, "LBST short error; powering off!\n"); +		regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL2, +				CS35L34_PDN_AMP, CS35L34_PDN_AMP); +		regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL1, +				CS35L34_PDN_ALL, CS35L34_PDN_ALL); +	} + +	return IRQ_HANDLED; +} + +static const char * const cs35l34_core_supplies[] = { +	"VA", +	"VP", +}; + +static int cs35l34_i2c_probe(struct i2c_client *i2c_client, +			      const struct i2c_device_id *id) +{ +	struct cs35l34_private *cs35l34; +	struct cs35l34_platform_data *pdata = +		dev_get_platdata(&i2c_client->dev); +	int i; +	int ret; +	unsigned int devid = 0; +	unsigned int reg; + +	cs35l34 = devm_kzalloc(&i2c_client->dev, +			       sizeof(struct cs35l34_private), +			       GFP_KERNEL); +	if (!cs35l34) { +		dev_err(&i2c_client->dev, "could not allocate codec\n"); +		return -ENOMEM; +	} + +	i2c_set_clientdata(i2c_client, cs35l34); +	cs35l34->regmap = devm_regmap_init_i2c(i2c_client, &cs35l34_regmap); +	if (IS_ERR(cs35l34->regmap)) { +		ret = PTR_ERR(cs35l34->regmap); +		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); +		return ret; +	} + +	cs35l34->num_core_supplies = ARRAY_SIZE(cs35l34_core_supplies); +	for (i = 0; i < ARRAY_SIZE(cs35l34_core_supplies); i++) +		cs35l34->core_supplies[i].supply = cs35l34_core_supplies[i]; + +	ret = devm_regulator_bulk_get(&i2c_client->dev, +		cs35l34->num_core_supplies, +		cs35l34->core_supplies); +	if (ret != 0) { +		dev_err(&i2c_client->dev, +			"Failed to request core supplies %d\n", ret); +		return ret; +	} + +	ret = regulator_bulk_enable(cs35l34->num_core_supplies, +					cs35l34->core_supplies); +	if (ret != 0) { +		dev_err(&i2c_client->dev, +			"Failed to enable core supplies: %d\n", ret); +		return ret; +	} + +	if (pdata) { +		cs35l34->pdata = *pdata; +	} else { +		pdata = devm_kzalloc(&i2c_client->dev, +				sizeof(struct cs35l34_platform_data), +				GFP_KERNEL); +		if (!pdata) { +			dev_err(&i2c_client->dev, +				"could not allocate pdata\n"); +			return -ENOMEM; +		} +		if (i2c_client->dev.of_node) { +			ret = cs35l34_handle_of_data(i2c_client, pdata); +			if (ret != 0) +				return ret; + +		} +		cs35l34->pdata = *pdata; +	} + +	ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL, +			cs35l34_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, +			"cs35l34", cs35l34); +	if (ret != 0) +		dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret); + +	cs35l34->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, +				"reset-gpios", GPIOD_OUT_LOW); +	if (IS_ERR(cs35l34->reset_gpio)) +		return PTR_ERR(cs35l34->reset_gpio); + +	gpiod_set_value_cansleep(cs35l34->reset_gpio, 1); + +	msleep(CS35L34_START_DELAY); + +	ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_AB, ®); + +	devid = (reg & 0xFF) << 12; +	ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_CD, ®); +	devid |= (reg & 0xFF) << 4; +	ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_E, ®); +	devid |= (reg & 0xF0) >> 4; + +	if (devid != CS35L34_CHIP_ID) { +		dev_err(&i2c_client->dev, +			"CS35l34 Device ID (%X). Expected ID %X\n", +			devid, CS35L34_CHIP_ID); +		ret = -ENODEV; +		goto err_regulator; +	} + +	ret = regmap_read(cs35l34->regmap, CS35L34_REV_ID, ®); +	if (ret < 0) { +		dev_err(&i2c_client->dev, "Get Revision ID failed\n"); +		goto err_regulator; +	} + +	dev_info(&i2c_client->dev, +		 "Cirrus Logic CS35l34 (%x), Revision: %02X\n", devid, +		reg & 0xFF); + +	/* Unmask critical interrupts */ +	regmap_update_bits(cs35l34->regmap, CS35L34_INT_MASK_1, +				CS35L34_M_CAL_ERR | CS35L34_M_ALIVE_ERR | +				CS35L34_M_AMP_SHORT | CS35L34_M_OTW | +				CS35L34_M_OTE, 0); +	regmap_update_bits(cs35l34->regmap, CS35L34_INT_MASK_3, +				CS35L34_M_BST_HIGH | CS35L34_M_LBST_SHORT, 0); + +	pm_runtime_set_autosuspend_delay(&i2c_client->dev, 100); +	pm_runtime_use_autosuspend(&i2c_client->dev); +	pm_runtime_set_active(&i2c_client->dev); +	pm_runtime_enable(&i2c_client->dev); + +	ret =  snd_soc_register_codec(&i2c_client->dev, +			&soc_codec_dev_cs35l34, &cs35l34_dai, 1); +	if (ret < 0) { +		dev_err(&i2c_client->dev, +			"%s: Register codec failed\n", __func__); +		goto err_regulator; +	} + +	return 0; + +err_regulator: +	regulator_bulk_disable(cs35l34->num_core_supplies, +		cs35l34->core_supplies); + +	return ret; +} + +static int cs35l34_i2c_remove(struct i2c_client *client) +{ +	struct cs35l34_private *cs35l34 = i2c_get_clientdata(client); + +	snd_soc_unregister_codec(&client->dev); + +	if (cs35l34->reset_gpio) +		gpiod_set_value_cansleep(cs35l34->reset_gpio, 0); + +	pm_runtime_disable(&client->dev); +	regulator_bulk_disable(cs35l34->num_core_supplies, +		cs35l34->core_supplies); + +	return 0; +} + +static int __maybe_unused cs35l34_runtime_resume(struct device *dev) +{ +	struct cs35l34_private *cs35l34 = dev_get_drvdata(dev); +	int ret; + +	ret = regulator_bulk_enable(cs35l34->num_core_supplies, +		cs35l34->core_supplies); + +	if (ret != 0) { +		dev_err(dev, "Failed to enable core supplies: %d\n", +			ret); +		return ret; +	} + +	regcache_cache_only(cs35l34->regmap, false); + +	gpiod_set_value_cansleep(cs35l34->reset_gpio, 1); +	msleep(CS35L34_START_DELAY); + +	ret = regcache_sync(cs35l34->regmap); +	if (ret != 0) { +		dev_err(dev, "Failed to restore register cache\n"); +		goto err; +	} +	return 0; +err: +	regcache_cache_only(cs35l34->regmap, true); +	regulator_bulk_disable(cs35l34->num_core_supplies, +		cs35l34->core_supplies); + +	return ret; +} + +static int __maybe_unused cs35l34_runtime_suspend(struct device *dev) +{ +	struct cs35l34_private *cs35l34 = dev_get_drvdata(dev); + +	regcache_cache_only(cs35l34->regmap, true); +	regcache_mark_dirty(cs35l34->regmap); + +	gpiod_set_value_cansleep(cs35l34->reset_gpio, 0); + +	regulator_bulk_disable(cs35l34->num_core_supplies, +			cs35l34->core_supplies); + +	return 0; +} + +static const struct dev_pm_ops cs35l34_pm_ops = { +	SET_RUNTIME_PM_OPS(cs35l34_runtime_suspend, +			   cs35l34_runtime_resume, +			   NULL) +}; + +static const struct of_device_id cs35l34_of_match[] = { +	{.compatible = "cirrus,cs35l34"}, +	{}, +}; +MODULE_DEVICE_TABLE(of, cs35l34_of_match); + +static const struct i2c_device_id cs35l34_id[] = { +	{"cs35l34", 0}, +	{} +}; +MODULE_DEVICE_TABLE(i2c, cs35l34_id); + +static struct i2c_driver cs35l34_i2c_driver = { +	.driver = { +		.name = "cs35l34", +		.pm = &cs35l34_pm_ops, +		.of_match_table = cs35l34_of_match, + +		}, +	.id_table = cs35l34_id, +	.probe = cs35l34_i2c_probe, +	.remove = cs35l34_i2c_remove, + +}; + +static int __init cs35l34_modinit(void) +{ +	int ret; + +	ret = i2c_add_driver(&cs35l34_i2c_driver); +	if (ret != 0) { +		pr_err("Failed to register CS35l34 I2C driver: %d\n", ret); +		return ret; +	} +	return 0; +} +module_init(cs35l34_modinit); + +static void __exit cs35l34_exit(void) +{ +	i2c_del_driver(&cs35l34_i2c_driver); +} +module_exit(cs35l34_exit); + +MODULE_DESCRIPTION("ASoC CS35l34 driver"); +MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <Paul.Handrigan@cirrus.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l34.h b/sound/soc/codecs/cs35l34.h new file mode 100644 index 000000000000..bcd54f127559 --- /dev/null +++ b/sound/soc/codecs/cs35l34.h @@ -0,0 +1,269 @@ +/* + * cs35l34.h -- CS35L34 ALSA SoC audio driver + * + * Copyright 2016 Cirrus Logic, Inc. + * + * Author: Paul Handrigan <Paul.Handrigan@cirrus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __CS35L34_H__ +#define __CS35L34_H__ + +#define CS35L34_CHIP_ID			0x00035A34 +#define CS35L34_DEVID_AB		0x01	/* Device ID A & B [RO] */ +#define CS35L34_DEVID_CD		0x02    /* Device ID C & D [RO] */ +#define CS35L34_DEVID_E			0x03    /* Device ID E [RO] */ +#define CS35L34_FAB_ID			0x04	/* Fab ID [RO] */ +#define CS35L34_REV_ID			0x05	/* Revision ID [RO] */ +#define CS35L34_PWRCTL1			0x06    /* Power Ctl 1 */ +#define CS35L34_PWRCTL2			0x07    /* Power Ctl 2 */ +#define CS35L34_PWRCTL3			0x08	/* Power Ctl 3 */ +#define CS35L34_ADSP_CLK_CTL		0x0A	/* (ADSP) Clock Ctl */ +#define CS35L34_MCLK_CTL		0x0B	/* Master Clocking Ctl */ +#define CS35L34_AMP_INP_DRV_CTL		0x14	/* Amp Input Drive Ctl */ +#define CS35L34_AMP_DIG_VOL_CTL		0x15	/* Amplifier Dig Volume Ctl */ +#define CS35L34_AMP_DIG_VOL		0x16	/* Amplifier Dig Volume */ +#define CS35L34_AMP_ANLG_GAIN_CTL	0x17	/* Amplifier Analog Gain Ctl */ +#define CS35L34_PROTECT_CTL		0x18	/* Amp Gain - Prot Ctl Param */ +#define CS35L34_AMP_KEEP_ALIVE_CTL	0x1A	/* Amplifier Keep Alive Ctl */ +#define CS35L34_BST_CVTR_V_CTL		0x1D	/* Boost Conv Voltage Ctl */ +#define CS35L34_BST_PEAK_I		0x1E	/* Boost Conv Peak Current */ +#define CS35L34_BST_RAMP_CTL		0x20	/* Boost Conv Soft Ramp Ctl */ +#define CS35L34_BST_CONV_COEF_1		0x21	/* Boost Conv Coefficients 1 */ +#define CS35L34_BST_CONV_COEF_2		0x22	/* Boost Conv Coefficients 2 */ +#define CS35L34_BST_CONV_SLOPE_COMP	0x23	/* Boost Conv Slope Comp */ +#define CS35L34_BST_CONV_SW_FREQ	0x24	/* Boost Conv L BST SW Freq */ +#define CS35L34_CLASS_H_CTL		0x30	/* CLS H Control */ +#define CS35L34_CLASS_H_HEADRM_CTL	0x31	/* CLS H Headroom Ctl */ +#define CS35L34_CLASS_H_RELEASE_RATE	0x32	/* CLS H Release Rate */ +#define CS35L34_CLASS_H_FET_DRIVE_CTL	0x33	/* CLS H Weak FET Drive Ctl */ +#define CS35L34_CLASS_H_STATUS		0x38	/* CLS H Status */ +#define CS35L34_VPBR_CTL		0x3A	/* VPBR Ctl */ +#define CS35L34_VPBR_VOL_CTL		0x3B	/* VPBR Volume Ctl */ +#define CS35L34_VPBR_TIMING_CTL		0x3C	/* VPBR Timing Ctl */ +#define CS35L34_PRED_MAX_ATTEN_SPK_LOAD	0x40	/* PRD Max Atten / Spkr Load */ +#define CS35L34_PRED_BROWNOUT_THRESH	0x41	/* PRD Brownout Threshold */ +#define CS35L34_PRED_BROWNOUT_VOL_CTL	0x42	/* PRD Brownout Volume Ctl */ +#define CS35L34_PRED_BROWNOUT_RATE_CTL	0x43	/* PRD Brownout Rate Ctl */ +#define CS35L34_PRED_WAIT_CTL		0x44	/* PRD Wait Ctl */ +#define CS35L34_PRED_ZVP_INIT_IMP_CTL	0x46	/* PRD ZVP Initial Imp Ctl */ +#define CS35L34_PRED_MAN_SAFE_VPI_CTL	0x47	/* PRD Manual Safe VPI Ctl */ +#define CS35L34_VPBR_ATTEN_STATUS	0x4B	/* VPBR Attenuation Status */ +#define CS35L34_PRED_BRWNOUT_ATT_STATUS	0x4C	/* PRD Brownout Atten Status */ +#define CS35L34_SPKR_MON_CTL		0x4E	/* Speaker Monitoring Ctl */ +#define CS35L34_ADSP_I2S_CTL		0x50	/* ADSP I2S Ctl */ +#define CS35L34_ADSP_TDM_CTL		0x51	/* ADSP TDM Ctl */ +#define CS35L34_TDM_TX_CTL_1_VMON	0x52	/* TDM TX Ctl 1 (VMON) */ +#define CS35L34_TDM_TX_CTL_2_IMON	0x53	/* TDM TX Ctl 2 (IMON) */ +#define CS35L34_TDM_TX_CTL_3_VPMON	0x54	/* TDM TX Ctl 3 (VPMON) */ +#define CS35L34_TDM_TX_CTL_4_VBSTMON	0x55	/* TDM TX Ctl 4 (VBSTMON) */ +#define CS35L34_TDM_TX_CTL_5_FLAG1	0x56	/* TDM TX Ctl 5 (FLAG1) */ +#define CS35L34_TDM_TX_CTL_6_FLAG2	0x57	/* TDM TX Ctl 6 (FLAG2) */ +#define CS35L34_TDM_TX_SLOT_EN_1	0x5A	/* TDM TX Slot Enable */ +#define CS35L34_TDM_TX_SLOT_EN_2	0x5B	/* TDM TX Slot Enable */ +#define CS35L34_TDM_TX_SLOT_EN_3	0x5C	/* TDM TX Slot Enable */ +#define CS35L34_TDM_TX_SLOT_EN_4	0x5D	/* TDM TX Slot Enable */ +#define CS35L34_TDM_RX_CTL_1_AUDIN	0x5E	/* TDM RX Ctl 1 */ +#define CS35L34_TDM_RX_CTL_3_ALIVE	0x60	/* TDM RX Ctl 3 (ALIVE) */ +#define CS35L34_MULT_DEV_SYNCH1		0x62	/* Multidevice Synch */ +#define CS35L34_MULT_DEV_SYNCH2		0x63	/* Multidevice Synch 2 */ +#define CS35L34_PROT_RELEASE_CTL	0x64	/* Protection Release Ctl */ +#define CS35L34_DIAG_MODE_REG_LOCK	0x68	/* Diagnostic Mode Reg Lock */ +#define CS35L34_DIAG_MODE_CTL_1		0x69	/* Diagnostic Mode Ctl 1 */ +#define CS35L34_DIAG_MODE_CTL_2		0x6A	/* Diagnostic Mode Ctl 2 */ +#define CS35L34_INT_MASK_1		0x70	/* Interrupt Mask 1 */ +#define CS35L34_INT_MASK_2		0x71	/* Interrupt Mask 2 */ +#define CS35L34_INT_MASK_3		0x72	/* Interrupt Mask 3 */ +#define CS35L34_INT_MASK_4		0x73	/* Interrupt Mask 4 */ +#define CS35L34_INT_STATUS_1		0x74	/* Interrupt Status 1 */ +#define CS35L34_INT_STATUS_2		0x75	/* Interrupt Status 2 */ +#define CS35L34_INT_STATUS_3		0x76	/* Interrupt Status 3 */ +#define CS35L34_INT_STATUS_4		0x77	/* Interrupt Status 4 */ +#define CS35L34_OTP_TRIM_STATUS		0x7E	/* OTP Trim Status */ + +#define CS35L34_MAX_REGISTER		0x7F +#define CS35L34_REGISTER_COUNT		0x4E + +#define CS35L34_MCLK_5644		5644800 +#define CS35L34_MCLK_6144		6144000 +#define CS35L34_MCLK_6			6000000 +#define CS35L34_MCLK_11289		11289600 +#define CS35L34_MCLK_12			12000000 +#define CS35L34_MCLK_12288		12288000 + +/* CS35L34_PWRCTL1 */ +#define CS35L34_SFT_RST			(1 << 7) +#define CS35L34_DISCHG_FLT		(1 << 1) +#define CS35L34_PDN_ALL			1 + +/* CS35L34_PWRCTL2 */ +#define CS35L34_PDN_VMON		(1 << 7) +#define CS35L34_PDN_IMON		(1 << 6) +#define CS35L34_PDN_CLASSH		(1 << 5) +#define CS35L34_PDN_VPBR		(1 << 4) +#define CS35L34_PDN_PRED		(1 << 3) +#define CS35L34_PDN_BST			(1 << 2) +#define CS35L34_PDN_AMP			1 + +/* CS35L34_PWRCTL3 */ +#define CS35L34_MCLK_DIS		(1 << 7) +#define CS35L34_PDN_VBSTMON_OUT		(1 << 4) +#define CS35L34_PDN_VMON_OUT		(1 << 3) +/* Tristate the ADSP SDOUT when in I2C mode */ +#define CS35L34_PDN_SDOUT		(1 << 2) +#define CS35L34_PDN_SDIN		(1 << 1) +#define CS35L34_PDN_TDM			1 + +/* CS35L34_ADSP_CLK_CTL */ +#define CS35L34_ADSP_RATE		0xF +#define CS35L34_ADSP_DRIVE		(1 << 4) +#define CS35L34_ADSP_M_S		(1 << 7) + +/* CS35L34_MCLK_CTL */ +#define CS35L34_MCLK_DIV		(1 << 4) +#define CS35L34_MCLK_RATE_MASK		0x7 +#define CS35L34_MCLK_RATE_6P1440	0x2 +#define CS35L34_MCLK_RATE_6P0000	0x1 +#define CS35L34_MCLK_RATE_5P6448	0x0 +#define CS35L34_MCLKDIS			(1 << 7) +#define CS35L34_MCLKDIV2		(1 << 6) +#define CS35L34_SDOUT_3ST_TDM		(1 << 5) +#define CS35L34_INT_FS_RATE		(1 << 4) +#define CS35L34_ADSP_FS			0xF + +/* CS35L34_AMP_INP_DRV_CTL */ +#define CS35L34_DRV_STR_SRC		(1 << 1) +#define CS35L34_DRV_STR			1 + +/* CS35L34_AMP_DIG_VOL_CTL */ +#define CS35L34_AMP_DSR_RATE_MASK	0xF0 +#define CS35L34_AMP_DSR_RATE_SHIFT	(1 << 4) +#define CS35L34_NOTCH_DIS		(1 << 3) +#define CS35L34_AMP_DIGSFT		(1 << 1) +#define CS35L34_INV			1 + +/* CS35L34_PROTECT_CTL */ +#define CS35L34_OTW_ATTN_MASK		0xC +#define CS35L34_OTW_THRD_MASK		0x3 +#define CS35L34_MUTE			(1 << 5) +#define CS35L34_GAIN_ZC			(1 << 4) +#define CS35L34_GAIN_ZC_MASK		0x10 +#define CS35L34_GAIN_ZC_SHIFT		4 + +/* CS35L34_AMP_KEEP_ALIVE_CTL */ +#define CS35L34_ALIVE_WD_DIS		(1 << 2) + +/* CS35L34_BST_CVTR_V_CTL */ +#define CS35L34_BST_CVTL_MASK		0x3F + +/* CS35L34_BST_PEAK_I */ +#define CS35L34_BST_PEAK_MASK		0x3F + +/* CS35L34_ADSP_I2S_CTL */ +#define CS35L34_I2S_LOC_MASK		0xC +#define CS35L34_I2S_LOC_SHIFT		2 + +/* CS35L34_MULT_DEV_SYNCH2 */ +#define CS35L34_SYNC2_MASK		0xF + +/* CS35L34_PROT_RELEASE_CTL */ +#define CS35L34_CAL_ERR_RLS		(1 << 7) +#define CS35L34_SHORT_RLS		(1 << 2) +#define CS35L34_OTW_RLS			(1 << 1) +#define CS35L34_OTE_RLS			1 + +/* CS35L34_INT_MASK_1 */ +#define CS35L34_M_CAL_ERR_SHIFT		7 +#define CS35L34_M_CAL_ERR		(1 << CS35L34_M_CAL_ERR_SHIFT) +#define CS35L34_M_ALIVE_ERR_SHIFT	5 +#define CS35L34_M_ALIVE_ERR		(1 << CS35L34_M_ALIVE_ERR_SHIFT) +#define CS35L34_M_ADSP_CLK_SHIFT	4 +#define CS35L34_M_ADSP_CLK_ERR		(1 << CS35L34_M_ADSP_CLK_SHIFT) +#define CS35L34_M_MCLK_SHIFT		3 +#define CS35L34_M_MCLK_ERR		(1 << CS35L34_M_MCLK_SHIFT) +#define CS35L34_M_AMP_SHORT_SHIFT	2 +#define CS35L34_M_AMP_SHORT		(1 << CS35L34_M_AMP_SHORT_SHIFT) +#define CS35L34_M_OTW_SHIFT		1 +#define CS35L34_M_OTW			(1 << CS35L34_M_OTW_SHIFT) +#define CS35L34_M_OTE_SHIFT		0 +#define CS35L34_M_OTE			(1 << CS35L34_M_OTE_SHIFT) + +/* CS35L34_INT_MASK_2 */ +#define CS35L34_M_PDN_DONE_SHIFT	4 +#define CS35L34_M_PDN_DONE		(1 << CS35L34_M_PDN_DONE_SHIFT) +#define CS35L34_M_PRED_SHIFT		3 +#define CS35L34_M_PRED_ERR		(1 << CS35L34_M_PRED_SHIFT) +#define CS35L34_M_PRED_CLR_SHIFT	2 +#define CS35L34_M_PRED_CLR		(1 << CS35L34_M_PRED_CLR_SHIFT) +#define CS35L34_M_VPBR_SHIFT		1 +#define CS35L34_M_VPBR_ERR		(1 << CS35L34_M_VPBR_SHIFT) +#define CS35L34_M_VPBR_CLR_SHIFT	0 +#define CS35L34_M_VPBR_CLR		(1 << CS35L34_M_VPBR_CLR_SHIFT) + +/* CS35L34_INT_MASK_3 */ +#define CS35L34_M_BST_HIGH_SHIFT	4 +#define CS35L34_M_BST_HIGH		(1 << CS35L34_M_BST_HIGH_SHIFT) +#define CS35L34_M_BST_HIGH_FLAG_SHIFT	3 +#define CS35L34_M_BST_HIGH_FLAG		(1 << CS35L34_M_BST_HIGH_FLAG_SHIFT) +#define CS35L34_M_BST_IPK_FLAG_SHIFT	2 +#define CS35L34_M_BST_IPK_FLAG		(1 << CS35L34_M_BST_IPK_FLAG_SHIFT) +#define CS35L34_M_LBST_SHORT_SHIFT	0 +#define CS35L34_M_LBST_SHORT		(1 << CS35L34_M_LBST_SHORT_SHIFT) + +/* CS35L34_INT_MASK_4 */ +#define CS35L34_M_VMON_OVFL_SHIFT	3 +#define CS35L34_M_VMON_OVFL		(1 << CS35L34_M_VMON_OVFL_SHIFT) +#define CS35L34_M_IMON_OVFL_SHIFT	2 +#define CS35L34_M_IMON_OVFL		(1 << CS35L34_M_IMON_OVFL_SHIFT) +#define CS35L34_M_VPMON_OVFL_SHIFT	1 +#define CS35L34_M_VPMON_OVFL		(1 << CS35L34_M_VPMON_OVFL_SHIFT) +#define CS35L34_M_VBSTMON_OVFL_SHIFT	1 +#define CS35L34_M_VBSTMON_OVFL		(1 << CS35L34_M_VBSTMON_OVFL_SHIFT) + +/* CS35L34_INT_1 */ +#define CS35L34_CAL_ERR			(1 << CS35L34_M_CAL_ERR_SHIFT) +#define CS35L34_ALIVE_ERR		(1 << CS35L34_M_ALIVE_ERR_SHIFT) +#define CS35L34_M_ADSP_CLK_ERR		(1 << CS35L34_M_ADSP_CLK_SHIFT) +#define CS35L34_MCLK_ERR		(1 << CS35L34_M_MCLK_SHIFT) +#define CS35L34_AMP_SHORT		(1 << CS35L34_M_AMP_SHORT_SHIFT) +#define CS35L34_OTW			(1 << CS35L34_M_OTW_SHIFT) +#define CS35L34_OTE			(1 << CS35L34_M_OTE_SHIFT) + +/* CS35L34_INT_2 */ +#define CS35L34_PDN_DONE		(1 << CS35L34_M_PDN_DONE_SHIFT) +#define CS35L34_PRED_ERR		(1 << CS35L34_M_PRED_SHIFT) +#define CS35L34_PRED_CLR		(1 << CS35L34_M_PRED_CLR_SHIFT) +#define CS35L34_VPBR_ERR		(1 << CS35L34_M_VPBR_SHIFT) +#define CS35L34_VPBR_CLR		(1 << CS35L34_M_VPBR_CLR_SHIFT) + +/* CS35L34_INT_3 */ +#define CS35L34_BST_HIGH		(1 << CS35L34_M_BST_HIGH_SHIFT) +#define CS35L34_BST_HIGH_FLAG		(1 << CS35L34_M_BST_HIGH_FLAG_SHIFT) +#define CS35L34_BST_IPK_FLAG		(1 << CS35L34_M_BST_IPK_FLAG_SHIFT) +#define CS35L34_LBST_SHORT		(1 << CS35L34_M_LBST_SHORT_SHIFT) + +/* CS35L34_INT_4 */ +#define CS35L34_VMON_OVFL		(1 << CS35L34_M_VMON_OVFL_SHIFT) +#define CS35L34_IMON_OVFL		(1 << CS35L34_M_IMON_OVFL_SHIFT) +#define CS35L34_VPMON_OVFL		(1 << CS35L34_M_VPMON_OVFL_SHIFT) +#define CS35L34_VBSTMON_OVFL		(1 << CS35L34_M_VBSTMON_OVFL_SHIFT) + +/* CS35L34_{RX,TX}_X */ +#define CS35L34_X_STATE_SHIFT		7 +#define CS35L34_X_STATE			(1 << CS35L34_X_STATE_SHIFT) +#define CS35L34_X_LOC_SHIFT		0 +#define CS35L34_X_LOC			(0x1F << CS35L34_X_LOC_SHIFT) + +#define CS35L34_RATES (SNDRV_PCM_RATE_48000 | \ +			SNDRV_PCM_RATE_44100 | \ +			SNDRV_PCM_RATE_32000) +#define CS35L34_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ +			SNDRV_PCM_FMTBIT_S24_LE | \ +			SNDRV_PCM_FMTBIT_S32_LE) + +#endif diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c new file mode 100644 index 000000000000..55e4520cdcaf --- /dev/null +++ b/sound/soc/codecs/cs42l42.c @@ -0,0 +1,1986 @@ +/* + * cs42l42.c -- CS42L42 ALSA SoC audio driver + * + * Copyright 2016 Cirrus Logic, Inc. + * + * Author: James Schulman <james.schulman@cirrus.com> + * Author: Brian Austin <brian.austin@cirrus.com> + * Author: Michael White <michael.white@cirrus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/of_device.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <dt-bindings/sound/cs42l42.h> + +#include "cs42l42.h" + +static const struct reg_default cs42l42_reg_defaults[] = { +	{ CS42L42_FRZ_CTL,			0x00 }, +	{ CS42L42_SRC_CTL,			0x10 }, +	{ CS42L42_MCLK_STATUS,			0x02 }, +	{ CS42L42_MCLK_CTL,			0x02 }, +	{ CS42L42_SFTRAMP_RATE,			0xA4 }, +	{ CS42L42_I2C_DEBOUNCE,			0x88 }, +	{ CS42L42_I2C_STRETCH,			0x03 }, +	{ CS42L42_I2C_TIMEOUT,			0xB7 }, +	{ CS42L42_PWR_CTL1,			0xFF }, +	{ CS42L42_PWR_CTL2,			0x84 }, +	{ CS42L42_PWR_CTL3,			0x20 }, +	{ CS42L42_RSENSE_CTL1,			0x40 }, +	{ CS42L42_RSENSE_CTL2,			0x00 }, +	{ CS42L42_OSC_SWITCH,			0x00 }, +	{ CS42L42_OSC_SWITCH_STATUS,		0x05 }, +	{ CS42L42_RSENSE_CTL3,			0x1B }, +	{ CS42L42_TSENSE_CTL,			0x1B }, +	{ CS42L42_TSRS_INT_DISABLE,		0x00 }, +	{ CS42L42_TRSENSE_STATUS,		0x00 }, +	{ CS42L42_HSDET_CTL1,			0x77 }, +	{ CS42L42_HSDET_CTL2,			0x00 }, +	{ CS42L42_HS_SWITCH_CTL,		0xF3 }, +	{ CS42L42_HS_DET_STATUS,		0x00 }, +	{ CS42L42_HS_CLAMP_DISABLE,		0x00 }, +	{ CS42L42_MCLK_SRC_SEL,			0x00 }, +	{ CS42L42_SPDIF_CLK_CFG,		0x00 }, +	{ CS42L42_FSYNC_PW_LOWER,		0x00 }, +	{ CS42L42_FSYNC_PW_UPPER,		0x00 }, +	{ CS42L42_FSYNC_P_LOWER,		0xF9 }, +	{ CS42L42_FSYNC_P_UPPER,		0x00 }, +	{ CS42L42_ASP_CLK_CFG,			0x00 }, +	{ CS42L42_ASP_FRM_CFG,			0x10 }, +	{ CS42L42_FS_RATE_EN,			0x00 }, +	{ CS42L42_IN_ASRC_CLK,			0x00 }, +	{ CS42L42_OUT_ASRC_CLK,			0x00 }, +	{ CS42L42_PLL_DIV_CFG1,			0x00 }, +	{ CS42L42_ADC_OVFL_STATUS,		0x00 }, +	{ CS42L42_MIXER_STATUS,			0x00 }, +	{ CS42L42_SRC_STATUS,			0x00 }, +	{ CS42L42_ASP_RX_STATUS,		0x00 }, +	{ CS42L42_ASP_TX_STATUS,		0x00 }, +	{ CS42L42_CODEC_STATUS,			0x00 }, +	{ CS42L42_DET_INT_STATUS1,		0x00 }, +	{ CS42L42_DET_INT_STATUS2,		0x00 }, +	{ CS42L42_SRCPL_INT_STATUS,		0x00 }, +	{ CS42L42_VPMON_STATUS,			0x00 }, +	{ CS42L42_PLL_LOCK_STATUS,		0x00 }, +	{ CS42L42_TSRS_PLUG_STATUS,		0x00 }, +	{ CS42L42_ADC_OVFL_INT_MASK,		0x01 }, +	{ CS42L42_MIXER_INT_MASK,		0x0F }, +	{ CS42L42_SRC_INT_MASK,			0x0F }, +	{ CS42L42_ASP_RX_INT_MASK,		0x1F }, +	{ CS42L42_ASP_TX_INT_MASK,		0x0F }, +	{ CS42L42_CODEC_INT_MASK,		0x03 }, +	{ CS42L42_SRCPL_INT_MASK,		0xFF }, +	{ CS42L42_VPMON_INT_MASK,		0x01 }, +	{ CS42L42_PLL_LOCK_INT_MASK,		0x01 }, +	{ CS42L42_TSRS_PLUG_INT_MASK,		0x0F }, +	{ CS42L42_PLL_CTL1,			0x00 }, +	{ CS42L42_PLL_DIV_FRAC0,		0x00 }, +	{ CS42L42_PLL_DIV_FRAC1,		0x00 }, +	{ CS42L42_PLL_DIV_FRAC2,		0x00 }, +	{ CS42L42_PLL_DIV_INT,			0x40 }, +	{ CS42L42_PLL_CTL3,			0x10 }, +	{ CS42L42_PLL_CAL_RATIO,		0x80 }, +	{ CS42L42_PLL_CTL4,			0x03 }, +	{ CS42L42_LOAD_DET_RCSTAT,		0x00 }, +	{ CS42L42_LOAD_DET_DONE,		0x00 }, +	{ CS42L42_LOAD_DET_EN,			0x00 }, +	{ CS42L42_HSBIAS_SC_AUTOCTL,		0x03 }, +	{ CS42L42_WAKE_CTL,			0xC0 }, +	{ CS42L42_ADC_DISABLE_MUTE,		0x00 }, +	{ CS42L42_TIPSENSE_CTL,			0x02 }, +	{ CS42L42_MISC_DET_CTL,			0x03 }, +	{ CS42L42_MIC_DET_CTL1,			0x1F }, +	{ CS42L42_MIC_DET_CTL2,			0x2F }, +	{ CS42L42_DET_STATUS1,			0x00 }, +	{ CS42L42_DET_STATUS2,			0x00 }, +	{ CS42L42_DET_INT1_MASK,		0xE0 }, +	{ CS42L42_DET_INT2_MASK,		0xFF }, +	{ CS42L42_HS_BIAS_CTL,			0xC2 }, +	{ CS42L42_ADC_CTL,			0x00 }, +	{ CS42L42_ADC_VOLUME,			0x00 }, +	{ CS42L42_ADC_WNF_HPF_CTL,		0x71 }, +	{ CS42L42_DAC_CTL1,			0x00 }, +	{ CS42L42_DAC_CTL2,			0x02 }, +	{ CS42L42_HP_CTL,			0x0D }, +	{ CS42L42_CLASSH_CTL,			0x07 }, +	{ CS42L42_MIXER_CHA_VOL,		0x3F }, +	{ CS42L42_MIXER_ADC_VOL,		0x3F }, +	{ CS42L42_MIXER_CHB_VOL,		0x3F }, +	{ CS42L42_EQ_COEF_IN0,			0x22 }, +	{ CS42L42_EQ_COEF_IN1,			0x00 }, +	{ CS42L42_EQ_COEF_IN2,			0x00 }, +	{ CS42L42_EQ_COEF_IN3,			0x00 }, +	{ CS42L42_EQ_COEF_RW,			0x00 }, +	{ CS42L42_EQ_COEF_OUT0,			0x00 }, +	{ CS42L42_EQ_COEF_OUT1,			0x00 }, +	{ CS42L42_EQ_COEF_OUT2,			0x00 }, +	{ CS42L42_EQ_COEF_OUT3,			0x00 }, +	{ CS42L42_EQ_INIT_STAT,			0x00 }, +	{ CS42L42_EQ_START_FILT,		0x00 }, +	{ CS42L42_EQ_MUTE_CTL,			0x00 }, +	{ CS42L42_SP_RX_CH_SEL,			0x04 }, +	{ CS42L42_SP_RX_ISOC_CTL,		0x04 }, +	{ CS42L42_SP_RX_FS,			0x8C }, +	{ CS42l42_SPDIF_CH_SEL,			0x0E }, +	{ CS42L42_SP_TX_ISOC_CTL,		0x04 }, +	{ CS42L42_SP_TX_FS,			0xCC }, +	{ CS42L42_SPDIF_SW_CTL1,		0x3F }, +	{ CS42L42_SRC_SDIN_FS,			0x40 }, +	{ CS42L42_SRC_SDOUT_FS,			0x40 }, +	{ CS42L42_SPDIF_CTL1,			0x01 }, +	{ CS42L42_SPDIF_CTL2,			0x00 }, +	{ CS42L42_SPDIF_CTL3,			0x00 }, +	{ CS42L42_SPDIF_CTL4,			0x42 }, +	{ CS42L42_ASP_TX_SZ_EN,			0x00 }, +	{ CS42L42_ASP_TX_CH_EN,			0x00 }, +	{ CS42L42_ASP_TX_CH_AP_RES,		0x0F }, +	{ CS42L42_ASP_TX_CH1_BIT_MSB,		0x00 }, +	{ CS42L42_ASP_TX_CH1_BIT_LSB,		0x00 }, +	{ CS42L42_ASP_TX_HIZ_DLY_CFG,		0x00 }, +	{ CS42L42_ASP_TX_CH2_BIT_MSB,		0x00 }, +	{ CS42L42_ASP_TX_CH2_BIT_LSB,		0x00 }, +	{ CS42L42_ASP_RX_DAI0_EN,		0x00 }, +	{ CS42L42_ASP_RX_DAI0_CH1_AP_RES,	0x03 }, +	{ CS42L42_ASP_RX_DAI0_CH1_BIT_MSB,	0x00 }, +	{ CS42L42_ASP_RX_DAI0_CH1_BIT_LSB,	0x00 }, +	{ CS42L42_ASP_RX_DAI0_CH2_AP_RES,	0x03 }, +	{ CS42L42_ASP_RX_DAI0_CH2_BIT_MSB,	0x00 }, +	{ CS42L42_ASP_RX_DAI0_CH2_BIT_LSB,	0x00 }, +	{ CS42L42_ASP_RX_DAI0_CH3_AP_RES,	0x03 }, +	{ CS42L42_ASP_RX_DAI0_CH3_BIT_MSB,	0x00 }, +	{ CS42L42_ASP_RX_DAI0_CH3_BIT_LSB,	0x00 }, +	{ CS42L42_ASP_RX_DAI0_CH4_AP_RES,	0x03 }, +	{ CS42L42_ASP_RX_DAI0_CH4_BIT_MSB,	0x00 }, +	{ CS42L42_ASP_RX_DAI0_CH4_BIT_LSB,	0x00 }, +	{ CS42L42_ASP_RX_DAI1_CH1_AP_RES,	0x03 }, +	{ CS42L42_ASP_RX_DAI1_CH1_BIT_MSB,	0x00 }, +	{ CS42L42_ASP_RX_DAI1_CH1_BIT_LSB,	0x00 }, +	{ CS42L42_ASP_RX_DAI1_CH2_AP_RES,	0x03 }, +	{ CS42L42_ASP_RX_DAI1_CH2_BIT_MSB,	0x00 }, +	{ CS42L42_ASP_RX_DAI1_CH2_BIT_LSB,	0x00 }, +	{ CS42L42_SUB_REVID,			0x03 }, +}; + +static bool cs42l42_readable_register(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case CS42L42_PAGE_REGISTER: +	case CS42L42_DEVID_AB: +	case CS42L42_DEVID_CD: +	case CS42L42_DEVID_E: +	case CS42L42_FABID: +	case CS42L42_REVID: +	case CS42L42_FRZ_CTL: +	case CS42L42_SRC_CTL: +	case CS42L42_MCLK_STATUS: +	case CS42L42_MCLK_CTL: +	case CS42L42_SFTRAMP_RATE: +	case CS42L42_I2C_DEBOUNCE: +	case CS42L42_I2C_STRETCH: +	case CS42L42_I2C_TIMEOUT: +	case CS42L42_PWR_CTL1: +	case CS42L42_PWR_CTL2: +	case CS42L42_PWR_CTL3: +	case CS42L42_RSENSE_CTL1: +	case CS42L42_RSENSE_CTL2: +	case CS42L42_OSC_SWITCH: +	case CS42L42_OSC_SWITCH_STATUS: +	case CS42L42_RSENSE_CTL3: +	case CS42L42_TSENSE_CTL: +	case CS42L42_TSRS_INT_DISABLE: +	case CS42L42_TRSENSE_STATUS: +	case CS42L42_HSDET_CTL1: +	case CS42L42_HSDET_CTL2: +	case CS42L42_HS_SWITCH_CTL: +	case CS42L42_HS_DET_STATUS: +	case CS42L42_HS_CLAMP_DISABLE: +	case CS42L42_MCLK_SRC_SEL: +	case CS42L42_SPDIF_CLK_CFG: +	case CS42L42_FSYNC_PW_LOWER: +	case CS42L42_FSYNC_PW_UPPER: +	case CS42L42_FSYNC_P_LOWER: +	case CS42L42_FSYNC_P_UPPER: +	case CS42L42_ASP_CLK_CFG: +	case CS42L42_ASP_FRM_CFG: +	case CS42L42_FS_RATE_EN: +	case CS42L42_IN_ASRC_CLK: +	case CS42L42_OUT_ASRC_CLK: +	case CS42L42_PLL_DIV_CFG1: +	case CS42L42_ADC_OVFL_STATUS: +	case CS42L42_MIXER_STATUS: +	case CS42L42_SRC_STATUS: +	case CS42L42_ASP_RX_STATUS: +	case CS42L42_ASP_TX_STATUS: +	case CS42L42_CODEC_STATUS: +	case CS42L42_DET_INT_STATUS1: +	case CS42L42_DET_INT_STATUS2: +	case CS42L42_SRCPL_INT_STATUS: +	case CS42L42_VPMON_STATUS: +	case CS42L42_PLL_LOCK_STATUS: +	case CS42L42_TSRS_PLUG_STATUS: +	case CS42L42_ADC_OVFL_INT_MASK: +	case CS42L42_MIXER_INT_MASK: +	case CS42L42_SRC_INT_MASK: +	case CS42L42_ASP_RX_INT_MASK: +	case CS42L42_ASP_TX_INT_MASK: +	case CS42L42_CODEC_INT_MASK: +	case CS42L42_SRCPL_INT_MASK: +	case CS42L42_VPMON_INT_MASK: +	case CS42L42_PLL_LOCK_INT_MASK: +	case CS42L42_TSRS_PLUG_INT_MASK: +	case CS42L42_PLL_CTL1: +	case CS42L42_PLL_DIV_FRAC0: +	case CS42L42_PLL_DIV_FRAC1: +	case CS42L42_PLL_DIV_FRAC2: +	case CS42L42_PLL_DIV_INT: +	case CS42L42_PLL_CTL3: +	case CS42L42_PLL_CAL_RATIO: +	case CS42L42_PLL_CTL4: +	case CS42L42_LOAD_DET_RCSTAT: +	case CS42L42_LOAD_DET_DONE: +	case CS42L42_LOAD_DET_EN: +	case CS42L42_HSBIAS_SC_AUTOCTL: +	case CS42L42_WAKE_CTL: +	case CS42L42_ADC_DISABLE_MUTE: +	case CS42L42_TIPSENSE_CTL: +	case CS42L42_MISC_DET_CTL: +	case CS42L42_MIC_DET_CTL1: +	case CS42L42_MIC_DET_CTL2: +	case CS42L42_DET_STATUS1: +	case CS42L42_DET_STATUS2: +	case CS42L42_DET_INT1_MASK: +	case CS42L42_DET_INT2_MASK: +	case CS42L42_HS_BIAS_CTL: +	case CS42L42_ADC_CTL: +	case CS42L42_ADC_VOLUME: +	case CS42L42_ADC_WNF_HPF_CTL: +	case CS42L42_DAC_CTL1: +	case CS42L42_DAC_CTL2: +	case CS42L42_HP_CTL: +	case CS42L42_CLASSH_CTL: +	case CS42L42_MIXER_CHA_VOL: +	case CS42L42_MIXER_ADC_VOL: +	case CS42L42_MIXER_CHB_VOL: +	case CS42L42_EQ_COEF_IN0: +	case CS42L42_EQ_COEF_IN1: +	case CS42L42_EQ_COEF_IN2: +	case CS42L42_EQ_COEF_IN3: +	case CS42L42_EQ_COEF_RW: +	case CS42L42_EQ_COEF_OUT0: +	case CS42L42_EQ_COEF_OUT1: +	case CS42L42_EQ_COEF_OUT2: +	case CS42L42_EQ_COEF_OUT3: +	case CS42L42_EQ_INIT_STAT: +	case CS42L42_EQ_START_FILT: +	case CS42L42_EQ_MUTE_CTL: +	case CS42L42_SP_RX_CH_SEL: +	case CS42L42_SP_RX_ISOC_CTL: +	case CS42L42_SP_RX_FS: +	case CS42l42_SPDIF_CH_SEL: +	case CS42L42_SP_TX_ISOC_CTL: +	case CS42L42_SP_TX_FS: +	case CS42L42_SPDIF_SW_CTL1: +	case CS42L42_SRC_SDIN_FS: +	case CS42L42_SRC_SDOUT_FS: +	case CS42L42_SPDIF_CTL1: +	case CS42L42_SPDIF_CTL2: +	case CS42L42_SPDIF_CTL3: +	case CS42L42_SPDIF_CTL4: +	case CS42L42_ASP_TX_SZ_EN: +	case CS42L42_ASP_TX_CH_EN: +	case CS42L42_ASP_TX_CH_AP_RES: +	case CS42L42_ASP_TX_CH1_BIT_MSB: +	case CS42L42_ASP_TX_CH1_BIT_LSB: +	case CS42L42_ASP_TX_HIZ_DLY_CFG: +	case CS42L42_ASP_TX_CH2_BIT_MSB: +	case CS42L42_ASP_TX_CH2_BIT_LSB: +	case CS42L42_ASP_RX_DAI0_EN: +	case CS42L42_ASP_RX_DAI0_CH1_AP_RES: +	case CS42L42_ASP_RX_DAI0_CH1_BIT_MSB: +	case CS42L42_ASP_RX_DAI0_CH1_BIT_LSB: +	case CS42L42_ASP_RX_DAI0_CH2_AP_RES: +	case CS42L42_ASP_RX_DAI0_CH2_BIT_MSB: +	case CS42L42_ASP_RX_DAI0_CH2_BIT_LSB: +	case CS42L42_ASP_RX_DAI0_CH3_AP_RES: +	case CS42L42_ASP_RX_DAI0_CH3_BIT_MSB: +	case CS42L42_ASP_RX_DAI0_CH3_BIT_LSB: +	case CS42L42_ASP_RX_DAI0_CH4_AP_RES: +	case CS42L42_ASP_RX_DAI0_CH4_BIT_MSB: +	case CS42L42_ASP_RX_DAI0_CH4_BIT_LSB: +	case CS42L42_ASP_RX_DAI1_CH1_AP_RES: +	case CS42L42_ASP_RX_DAI1_CH1_BIT_MSB: +	case CS42L42_ASP_RX_DAI1_CH1_BIT_LSB: +	case CS42L42_ASP_RX_DAI1_CH2_AP_RES: +	case CS42L42_ASP_RX_DAI1_CH2_BIT_MSB: +	case CS42L42_ASP_RX_DAI1_CH2_BIT_LSB: +	case CS42L42_SUB_REVID: +		return true; +	default: +		return false; +	} +} + +static bool cs42l42_volatile_register(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case CS42L42_DEVID_AB: +	case CS42L42_DEVID_CD: +	case CS42L42_DEVID_E: +	case CS42L42_MCLK_STATUS: +	case CS42L42_TRSENSE_STATUS: +	case CS42L42_HS_DET_STATUS: +	case CS42L42_ADC_OVFL_STATUS: +	case CS42L42_MIXER_STATUS: +	case CS42L42_SRC_STATUS: +	case CS42L42_ASP_RX_STATUS: +	case CS42L42_ASP_TX_STATUS: +	case CS42L42_CODEC_STATUS: +	case CS42L42_DET_INT_STATUS1: +	case CS42L42_DET_INT_STATUS2: +	case CS42L42_SRCPL_INT_STATUS: +	case CS42L42_VPMON_STATUS: +	case CS42L42_PLL_LOCK_STATUS: +	case CS42L42_TSRS_PLUG_STATUS: +	case CS42L42_LOAD_DET_RCSTAT: +	case CS42L42_LOAD_DET_DONE: +	case CS42L42_DET_STATUS1: +	case CS42L42_DET_STATUS2: +		return true; +	default: +		return false; +	} +} + +static const struct regmap_range_cfg cs42l42_page_range = { +	.name = "Pages", +	.range_min = 0, +	.range_max = CS42L42_MAX_REGISTER, +	.selector_reg = CS42L42_PAGE_REGISTER, +	.selector_mask = 0xff, +	.selector_shift = 0, +	.window_start = 0, +	.window_len = 256, +}; + +static const struct regmap_config cs42l42_regmap = { +	.reg_bits = 8, +	.val_bits = 8, + +	.readable_reg = cs42l42_readable_register, +	.volatile_reg = cs42l42_volatile_register, + +	.ranges = &cs42l42_page_range, +	.num_ranges = 1, + +	.max_register = CS42L42_MAX_REGISTER, +	.reg_defaults = cs42l42_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(cs42l42_reg_defaults), +	.cache_type = REGCACHE_RBTREE, +}; + +static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, false); +static DECLARE_TLV_DB_SCALE(mixer_tlv, -6200, 100, false); + +static const char * const cs42l42_hpf_freq_text[] = { +	"1.86Hz", "120Hz", "235Hz", "466Hz" +}; + +static SOC_ENUM_SINGLE_DECL(cs42l42_hpf_freq_enum, CS42L42_ADC_WNF_HPF_CTL, +			    CS42L42_ADC_HPF_CF_SHIFT, +			    cs42l42_hpf_freq_text); + +static const char * const cs42l42_wnf3_freq_text[] = { +	"160Hz", "180Hz", "200Hz", "220Hz", +	"240Hz", "260Hz", "280Hz", "300Hz" +}; + +static SOC_ENUM_SINGLE_DECL(cs42l42_wnf3_freq_enum, CS42L42_ADC_WNF_HPF_CTL, +			    CS42L42_ADC_WNF_CF_SHIFT, +			    cs42l42_wnf3_freq_text); + +static const char * const cs42l42_wnf05_freq_text[] = { +	"280Hz", "315Hz", "350Hz", "385Hz", +	"420Hz", "455Hz", "490Hz", "525Hz" +}; + +static SOC_ENUM_SINGLE_DECL(cs42l42_wnf05_freq_enum, CS42L42_ADC_WNF_HPF_CTL, +			    CS42L42_ADC_WNF_CF_SHIFT, +			    cs42l42_wnf05_freq_text); + +static const struct snd_kcontrol_new cs42l42_snd_controls[] = { +	/* ADC Volume and Filter Controls */ +	SOC_SINGLE("ADC Notch Switch", CS42L42_ADC_CTL, +				CS42L42_ADC_NOTCH_DIS_SHIFT, true, false), +	SOC_SINGLE("ADC Weak Force Switch", CS42L42_ADC_CTL, +				CS42L42_ADC_FORCE_WEAK_VCM_SHIFT, true, false), +	SOC_SINGLE("ADC Invert Switch", CS42L42_ADC_CTL, +				CS42L42_ADC_INV_SHIFT, true, false), +	SOC_SINGLE("ADC Boost Switch", CS42L42_ADC_CTL, +				CS42L42_ADC_DIG_BOOST_SHIFT, true, false), +	SOC_SINGLE_SX_TLV("ADC Volume", CS42L42_ADC_VOLUME, +				CS42L42_ADC_VOL_SHIFT, 0xA0, 0x6C, adc_tlv), +	SOC_SINGLE("ADC WNF Switch", CS42L42_ADC_WNF_HPF_CTL, +				CS42L42_ADC_WNF_EN_SHIFT, true, false), +	SOC_SINGLE("ADC HPF Switch", CS42L42_ADC_WNF_HPF_CTL, +				CS42L42_ADC_HPF_EN_SHIFT, true, false), +	SOC_ENUM("HPF Corner Freq", cs42l42_hpf_freq_enum), +	SOC_ENUM("WNF 3dB Freq", cs42l42_wnf3_freq_enum), +	SOC_ENUM("WNF 05dB Freq", cs42l42_wnf05_freq_enum), + +	/* DAC Volume and Filter Controls */ +	SOC_SINGLE("DACA Invert Switch", CS42L42_DAC_CTL1, +				CS42L42_DACA_INV_SHIFT, true, false), +	SOC_SINGLE("DACB Invert Switch", CS42L42_DAC_CTL1, +				CS42L42_DACB_INV_SHIFT, true, false), +	SOC_SINGLE("DAC HPF Switch", CS42L42_DAC_CTL2, +				CS42L42_DAC_HPF_EN_SHIFT, true, false), +	SOC_DOUBLE_R_TLV("Mixer Volume", CS42L42_MIXER_CHA_VOL, +			 CS42L42_MIXER_CHB_VOL, CS42L42_MIXER_CH_VOL_SHIFT, +				0x3e, 1, mixer_tlv) +}; + +static int cs42l42_hpdrv_evt(struct snd_soc_dapm_widget *w, +				struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + +	if (event & SND_SOC_DAPM_POST_PMU) { +		/* Enable the channels */ +		snd_soc_update_bits(codec, CS42L42_ASP_RX_DAI0_EN, +				CS42L42_ASP_RX0_CH_EN_MASK, +				(CS42L42_ASP_RX0_CH1_EN | +				CS42L42_ASP_RX0_CH2_EN) << +				CS42L42_ASP_RX0_CH_EN_SHIFT); + +		/* Power up */ +		snd_soc_update_bits(codec, CS42L42_PWR_CTL1, +			CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK | +				CS42L42_HP_PDN_MASK, 0); +	} else if (event & SND_SOC_DAPM_PRE_PMD) { +		/* Disable the channels */ +		snd_soc_update_bits(codec, CS42L42_ASP_RX_DAI0_EN, +				CS42L42_ASP_RX0_CH_EN_MASK, 0); + +		/* Power down */ +		snd_soc_update_bits(codec, CS42L42_PWR_CTL1, +			CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK | +				CS42L42_HP_PDN_MASK, +			CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK | +				CS42L42_HP_PDN_MASK); +	} else { +		dev_err(codec->dev, "Invalid event 0x%x\n", event); +	} +	return 0; +} + +static const struct snd_soc_dapm_widget cs42l42_dapm_widgets[] = { +	SND_SOC_DAPM_OUTPUT("HP"), +	SND_SOC_DAPM_AIF_IN("SDIN", NULL, 0, CS42L42_ASP_CLK_CFG, +					CS42L42_ASP_SCLK_EN_SHIFT, false), +	SND_SOC_DAPM_OUT_DRV_E("HPDRV", SND_SOC_NOPM, 0, +					0, NULL, 0, cs42l42_hpdrv_evt, +					SND_SOC_DAPM_POST_PMU | +					SND_SOC_DAPM_PRE_PMD) +}; + +static const struct snd_soc_dapm_route cs42l42_audio_map[] = { +	{"SDIN", NULL, "Playback"}, +	{"HPDRV", NULL, "SDIN"}, +	{"HP", NULL, "HPDRV"} +}; + +static int cs42l42_set_bias_level(struct snd_soc_codec *codec, +					enum snd_soc_bias_level level) +{ +	struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec); +	int ret; + +	switch (level) { +	case SND_SOC_BIAS_ON: +		break; +	case SND_SOC_BIAS_PREPARE: +		break; +	case SND_SOC_BIAS_STANDBY: +		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { +			regcache_cache_only(cs42l42->regmap, false); +			regcache_sync(cs42l42->regmap); +			ret = regulator_bulk_enable( +						ARRAY_SIZE(cs42l42->supplies), +						cs42l42->supplies); +			if (ret != 0) { +				dev_err(codec->dev, +					"Failed to enable regulators: %d\n", +					ret); +				return ret; +			} +		} +		break; +	case SND_SOC_BIAS_OFF: + +		regcache_cache_only(cs42l42->regmap, true); +		regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), +						    cs42l42->supplies); +		break; +	} + +	return 0; +} + +static int cs42l42_codec_probe(struct snd_soc_codec *codec) +{ +	struct cs42l42_private *cs42l42 = +		(struct cs42l42_private *)snd_soc_codec_get_drvdata(codec); + +	cs42l42->codec = codec; + +	return 0; +} + +static const struct snd_soc_codec_driver soc_codec_dev_cs42l42 = { +	.probe = cs42l42_codec_probe, +	.set_bias_level = cs42l42_set_bias_level, +	.ignore_pmdown_time = true, + +	.component_driver = { +		.dapm_widgets = cs42l42_dapm_widgets, +		.num_dapm_widgets = ARRAY_SIZE(cs42l42_dapm_widgets), +		.dapm_routes = cs42l42_audio_map, +		.num_dapm_routes = ARRAY_SIZE(cs42l42_audio_map), + +		.controls = cs42l42_snd_controls, +		.num_controls = ARRAY_SIZE(cs42l42_snd_controls), +	}, +}; + +struct cs42l42_pll_params { +	u32 sclk; +	u8 mclk_div; +	u8 mclk_src_sel; +	u8 sclk_prediv; +	u8 pll_div_int; +	u32 pll_div_frac; +	u8 pll_mode; +	u8 pll_divout; +	u32 mclk_int; +	u8 pll_cal_ratio; +}; + +/* + * Common PLL Settings for given SCLK + * Table 4-5 from the Datasheet + */ +static const struct cs42l42_pll_params pll_ratio_table[] = { +	{ 1536000, 0, 1, 0x00, 0x7D, 0x000000, 0x03, 0x10, 12000000, 125 }, +	{ 2822400, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 11289600, 128 }, +	{ 3000000, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 12000000, 128 }, +	{ 3072000, 0, 1, 0x00, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125 }, +	{ 4000000, 0, 1, 0x00, 0x30, 0x800000, 0x03, 0x10, 12000000, 96 }, +	{ 4096000, 0, 1, 0x00, 0x2E, 0xE00000, 0x03, 0x10, 12000000, 94 }, +	{ 5644800, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 11289600, 128 }, +	{ 6000000, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 12000000, 128 }, +	{ 6144000, 0, 1, 0x01, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125 }, +	{ 11289600, 0, 0, 0, 0, 0, 0, 0, 11289600, 0 }, +	{ 12000000, 0, 0, 0, 0, 0, 0, 0, 12000000, 0 }, +	{ 12288000, 0, 0, 0, 0, 0, 0, 0, 12288000, 0 }, +	{ 22579200, 1, 0, 0, 0, 0, 0, 0, 22579200, 0 }, +	{ 24000000, 1, 0, 0, 0, 0, 0, 0, 24000000, 0 }, +	{ 24576000, 1, 0, 0, 0, 0, 0, 0, 24576000, 0 } +}; + +static int cs42l42_pll_config(struct snd_soc_codec *codec) +{ +	struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec); +	int i; +	u32 fsync; + +	for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) { +		if (pll_ratio_table[i].sclk == cs42l42->sclk) { +			/* Configure the internal sample rate */ +			snd_soc_update_bits(codec, CS42L42_MCLK_CTL, +					CS42L42_INTERNAL_FS_MASK, +					((pll_ratio_table[i].mclk_int != +					12000000) && +					(pll_ratio_table[i].mclk_int != +					24000000)) << +					CS42L42_INTERNAL_FS_SHIFT); +			/* Set the MCLK src (PLL or SCLK) and the divide +			 * ratio +			 */ +			snd_soc_update_bits(codec, CS42L42_MCLK_SRC_SEL, +					CS42L42_MCLK_SRC_SEL_MASK | +					CS42L42_MCLKDIV_MASK, +					(pll_ratio_table[i].mclk_src_sel +					<< CS42L42_MCLK_SRC_SEL_SHIFT) | +					(pll_ratio_table[i].mclk_div << +					CS42L42_MCLKDIV_SHIFT)); +			/* Set up the LRCLK */ +			fsync = cs42l42->sclk / cs42l42->srate; +			if (((fsync * cs42l42->srate) != cs42l42->sclk) +				|| ((fsync % 2) != 0)) { +				dev_err(codec->dev, +					"Unsupported sclk %d/sample rate %d\n", +					cs42l42->sclk, +					cs42l42->srate); +				return -EINVAL; +			} +			/* Set the LRCLK period */ +			snd_soc_update_bits(codec, +					CS42L42_FSYNC_P_LOWER, +					CS42L42_FSYNC_PERIOD_MASK, +					CS42L42_FRAC0_VAL(fsync - 1) << +					CS42L42_FSYNC_PERIOD_SHIFT); +			snd_soc_update_bits(codec, +					CS42L42_FSYNC_P_UPPER, +					CS42L42_FSYNC_PERIOD_MASK, +					CS42L42_FRAC1_VAL(fsync - 1) << +					CS42L42_FSYNC_PERIOD_SHIFT); +			/* Set the LRCLK to 50% duty cycle */ +			fsync = fsync / 2; +			snd_soc_update_bits(codec, +					CS42L42_FSYNC_PW_LOWER, +					CS42L42_FSYNC_PULSE_WIDTH_MASK, +					CS42L42_FRAC0_VAL(fsync - 1) << +					CS42L42_FSYNC_PULSE_WIDTH_SHIFT); +			snd_soc_update_bits(codec, +					CS42L42_FSYNC_PW_UPPER, +					CS42L42_FSYNC_PULSE_WIDTH_MASK, +					CS42L42_FRAC1_VAL(fsync - 1) << +					CS42L42_FSYNC_PULSE_WIDTH_SHIFT); +			snd_soc_update_bits(codec, +					CS42L42_ASP_FRM_CFG, +					CS42L42_ASP_5050_MASK, +					CS42L42_ASP_5050_MASK); +			/* Set the frame delay to 1.0 SCLK clocks */ +			snd_soc_update_bits(codec, CS42L42_ASP_FRM_CFG, +					CS42L42_ASP_FSD_MASK, +					CS42L42_ASP_FSD_1_0 << +					CS42L42_ASP_FSD_SHIFT); +			/* Set the sample rates (96k or lower) */ +			snd_soc_update_bits(codec, CS42L42_FS_RATE_EN, +					CS42L42_FS_EN_MASK, +					(CS42L42_FS_EN_IASRC_96K | +					CS42L42_FS_EN_OASRC_96K) << +					CS42L42_FS_EN_SHIFT); +			/* Set the input/output internal MCLK clock ~12 MHz */ +			snd_soc_update_bits(codec, CS42L42_IN_ASRC_CLK, +					CS42L42_CLK_IASRC_SEL_MASK, +					CS42L42_CLK_IASRC_SEL_12 << +					CS42L42_CLK_IASRC_SEL_SHIFT); +			snd_soc_update_bits(codec, +					CS42L42_OUT_ASRC_CLK, +					CS42L42_CLK_OASRC_SEL_MASK, +					CS42L42_CLK_OASRC_SEL_12 << +					CS42L42_CLK_OASRC_SEL_SHIFT); +			/* channel 1 on low LRCLK, 32 bit */ +			snd_soc_update_bits(codec, +					CS42L42_ASP_RX_DAI0_CH1_AP_RES, +					CS42L42_ASP_RX_CH_AP_MASK | +					CS42L42_ASP_RX_CH_RES_MASK, +					(CS42L42_ASP_RX_CH_AP_LOW << +					CS42L42_ASP_RX_CH_AP_SHIFT) | +					(CS42L42_ASP_RX_CH_RES_32 << +					CS42L42_ASP_RX_CH_RES_SHIFT)); +			/* Channel 2 on high LRCLK, 32 bit */ +			snd_soc_update_bits(codec, +					CS42L42_ASP_RX_DAI0_CH2_AP_RES, +					CS42L42_ASP_RX_CH_AP_MASK | +					CS42L42_ASP_RX_CH_RES_MASK, +					(CS42L42_ASP_RX_CH_AP_HI << +					CS42L42_ASP_RX_CH_AP_SHIFT) | +					(CS42L42_ASP_RX_CH_RES_32 << +					CS42L42_ASP_RX_CH_RES_SHIFT)); +			if (pll_ratio_table[i].mclk_src_sel == 0) { +				/* Pass the clock straight through */ +				snd_soc_update_bits(codec, +					CS42L42_PLL_CTL1, +					CS42L42_PLL_START_MASK,	0); +			} else { +				/* Configure PLL per table 4-5 */ +				snd_soc_update_bits(codec, +					CS42L42_PLL_DIV_CFG1, +					CS42L42_SCLK_PREDIV_MASK, +					pll_ratio_table[i].sclk_prediv +					<< CS42L42_SCLK_PREDIV_SHIFT); +				snd_soc_update_bits(codec, +					CS42L42_PLL_DIV_INT, +					CS42L42_PLL_DIV_INT_MASK, +					pll_ratio_table[i].pll_div_int +					<< CS42L42_PLL_DIV_INT_SHIFT); +				snd_soc_update_bits(codec, +					CS42L42_PLL_DIV_FRAC0, +					CS42L42_PLL_DIV_FRAC_MASK, +					CS42L42_FRAC0_VAL( +					pll_ratio_table[i].pll_div_frac) +					<< CS42L42_PLL_DIV_FRAC_SHIFT); +				snd_soc_update_bits(codec, +					CS42L42_PLL_DIV_FRAC1, +					CS42L42_PLL_DIV_FRAC_MASK, +					CS42L42_FRAC1_VAL( +					pll_ratio_table[i].pll_div_frac) +					<< CS42L42_PLL_DIV_FRAC_SHIFT); +				snd_soc_update_bits(codec, +					CS42L42_PLL_DIV_FRAC2, +					CS42L42_PLL_DIV_FRAC_MASK, +					CS42L42_FRAC2_VAL( +					pll_ratio_table[i].pll_div_frac) +					<< CS42L42_PLL_DIV_FRAC_SHIFT); +				snd_soc_update_bits(codec, +					CS42L42_PLL_CTL4, +					CS42L42_PLL_MODE_MASK, +					pll_ratio_table[i].pll_mode +					<< CS42L42_PLL_MODE_SHIFT); +				snd_soc_update_bits(codec, +					CS42L42_PLL_CTL3, +					CS42L42_PLL_DIVOUT_MASK, +					pll_ratio_table[i].pll_divout +					<< CS42L42_PLL_DIVOUT_SHIFT); +				snd_soc_update_bits(codec, +					CS42L42_PLL_CAL_RATIO, +					CS42L42_PLL_CAL_RATIO_MASK, +					pll_ratio_table[i].pll_cal_ratio +					<< CS42L42_PLL_CAL_RATIO_SHIFT); +			} +			return 0; +		} +	} + +	return -EINVAL; +} + +static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ +	struct snd_soc_codec *codec = codec_dai->codec; +	u32 asp_cfg_val = 0; + +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBS_CFM: +		asp_cfg_val |= CS42L42_ASP_MASTER_MODE << +				CS42L42_ASP_MODE_SHIFT; +		break; +	case SND_SOC_DAIFMT_CBS_CFS: +		asp_cfg_val |= CS42L42_ASP_SLAVE_MODE << +				CS42L42_ASP_MODE_SHIFT; +		break; +	default: +		return -EINVAL; +	} + +	/* interface format */ +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { +	case SND_SOC_DAIFMT_I2S: +	case SND_SOC_DAIFMT_LEFT_J: +		break; +	default: +		return -EINVAL; +	} + +	/* Bitclock/frame inversion */ +	switch (fmt & SND_SOC_DAIFMT_INV_MASK) { +	case SND_SOC_DAIFMT_NB_NF: +		break; +	case SND_SOC_DAIFMT_NB_IF: +		asp_cfg_val |= CS42L42_ASP_POL_INV << +				CS42L42_ASP_LCPOL_IN_SHIFT; +		break; +	case SND_SOC_DAIFMT_IB_NF: +		asp_cfg_val |= CS42L42_ASP_POL_INV << +				CS42L42_ASP_SCPOL_IN_DAC_SHIFT; +		break; +	case SND_SOC_DAIFMT_IB_IF: +		asp_cfg_val |= CS42L42_ASP_POL_INV << +				CS42L42_ASP_LCPOL_IN_SHIFT; +		asp_cfg_val |= CS42L42_ASP_POL_INV << +				CS42L42_ASP_SCPOL_IN_DAC_SHIFT; +		break; +	} + +	snd_soc_update_bits(codec, CS42L42_ASP_CLK_CFG, +				CS42L42_ASP_MODE_MASK | +				CS42L42_ASP_SCPOL_IN_DAC_MASK | +				CS42L42_ASP_LCPOL_IN_MASK, asp_cfg_val); + +	return 0; +} + +static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, +				struct snd_pcm_hw_params *params, +				struct snd_soc_dai *dai) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec); +	int retval; + +	cs42l42->srate = params_rate(params); +	cs42l42->swidth = params_width(params); + +	retval = cs42l42_pll_config(codec); + +	return retval; +} + +static int cs42l42_set_sysclk(struct snd_soc_dai *dai, +				int clk_id, unsigned int freq, int dir) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec); + +	cs42l42->sclk = freq; + +	return 0; +} + +static int cs42l42_digital_mute(struct snd_soc_dai *dai, int mute) +{ +	struct snd_soc_codec *codec = dai->codec; +	unsigned int regval; +	u8 fullScaleVol; + +	if (mute) { +		/* Mark SCLK as not present to turn on the internal +		 * oscillator. +		 */ +		snd_soc_update_bits(codec, CS42L42_OSC_SWITCH, +						CS42L42_SCLK_PRESENT_MASK, 0); + +		snd_soc_update_bits(codec, CS42L42_PLL_CTL1, +				CS42L42_PLL_START_MASK, +				0 << CS42L42_PLL_START_SHIFT); + +		/* Mute the headphone */ +		snd_soc_update_bits(codec, CS42L42_HP_CTL, +				CS42L42_HP_ANA_AMUTE_MASK | +				CS42L42_HP_ANA_BMUTE_MASK, +				CS42L42_HP_ANA_AMUTE_MASK | +				CS42L42_HP_ANA_BMUTE_MASK); +	} else { +		snd_soc_update_bits(codec, CS42L42_PLL_CTL1, +				CS42L42_PLL_START_MASK, +				1 << CS42L42_PLL_START_SHIFT); +		/* Read the headphone load */ +		regval = snd_soc_read(codec, CS42L42_LOAD_DET_RCSTAT); +		if (((regval & CS42L42_RLA_STAT_MASK) >> +			CS42L42_RLA_STAT_SHIFT) == CS42L42_RLA_STAT_15_OHM) { +			fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK; +		} else { +			fullScaleVol = 0; +		} + +		/* Un-mute the headphone, set the full scale volume flag */ +		snd_soc_update_bits(codec, CS42L42_HP_CTL, +				CS42L42_HP_ANA_AMUTE_MASK | +				CS42L42_HP_ANA_BMUTE_MASK | +				CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol); + +		/* Mark SCLK as present, turn off internal oscillator */ +		snd_soc_update_bits(codec, CS42L42_OSC_SWITCH, +				CS42L42_SCLK_PRESENT_MASK, +				CS42L42_SCLK_PRESENT_MASK); +	} + +	return 0; +} + +#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ +			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \ +			SNDRV_PCM_FMTBIT_S32_LE) + + +static struct snd_soc_dai_ops cs42l42_ops = { +	.hw_params	= cs42l42_pcm_hw_params, +	.set_fmt	= cs42l42_set_dai_fmt, +	.set_sysclk	= cs42l42_set_sysclk, +	.digital_mute = cs42l42_digital_mute +}; + +static struct snd_soc_dai_driver cs42l42_dai = { +		.name = "cs42l42", +		.playback = { +			.stream_name = "Playback", +			.channels_min = 1, +			.channels_max = 2, +			.rates = SNDRV_PCM_RATE_8000_192000, +			.formats = CS42L42_FORMATS, +		}, +		.capture = { +			.stream_name = "Capture", +			.channels_min = 1, +			.channels_max = 2, +			.rates = SNDRV_PCM_RATE_8000_192000, +			.formats = CS42L42_FORMATS, +		}, +		.ops = &cs42l42_ops, +}; + +static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42) +{ +	unsigned int hs_det_status; +	unsigned int int_status; + +	/* Mask the auto detect interrupt */ +	regmap_update_bits(cs42l42->regmap, +		CS42L42_CODEC_INT_MASK, +		CS42L42_PDN_DONE_MASK | +		CS42L42_HSDET_AUTO_DONE_MASK, +		(1 << CS42L42_PDN_DONE_SHIFT) | +		(1 << CS42L42_HSDET_AUTO_DONE_SHIFT)); + +	/* Set hs detect to automatic, disabled mode */ +	regmap_update_bits(cs42l42->regmap, +		CS42L42_HSDET_CTL2, +		CS42L42_HSDET_CTRL_MASK | +		CS42L42_HSDET_SET_MASK | +		CS42L42_HSBIAS_REF_MASK | +		CS42L42_HSDET_AUTO_TIME_MASK, +		(2 << CS42L42_HSDET_CTRL_SHIFT) | +		(2 << CS42L42_HSDET_SET_SHIFT) | +		(0 << CS42L42_HSBIAS_REF_SHIFT) | +		(3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); + +	/* Read and save the hs detection result */ +	regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status); + +	cs42l42->hs_type = (hs_det_status & CS42L42_HSDET_TYPE_MASK) >> +				CS42L42_HSDET_TYPE_SHIFT; + +	/* Set up button detection */ +	if ((cs42l42->hs_type == CS42L42_PLUG_CTIA) || +	      (cs42l42->hs_type == CS42L42_PLUG_OMTP)) { +		/* Set auto HS bias settings to default */ +		regmap_update_bits(cs42l42->regmap, +			CS42L42_HSBIAS_SC_AUTOCTL, +			CS42L42_HSBIAS_SENSE_EN_MASK | +			CS42L42_AUTO_HSBIAS_HIZ_MASK | +			CS42L42_TIP_SENSE_EN_MASK | +			CS42L42_HSBIAS_SENSE_TRIP_MASK, +			(0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | +			(0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | +			(0 << CS42L42_TIP_SENSE_EN_SHIFT) | +			(3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); + +		/* Set up hs detect level sensitivity */ +		regmap_update_bits(cs42l42->regmap, +			CS42L42_MIC_DET_CTL1, +			CS42L42_LATCH_TO_VP_MASK | +			CS42L42_EVENT_STAT_SEL_MASK | +			CS42L42_HS_DET_LEVEL_MASK, +			(1 << CS42L42_LATCH_TO_VP_SHIFT) | +			(0 << CS42L42_EVENT_STAT_SEL_SHIFT) | +			(cs42l42->bias_thresholds[0] << +			CS42L42_HS_DET_LEVEL_SHIFT)); + +		/* Set auto HS bias settings to default */ +		regmap_update_bits(cs42l42->regmap, +			CS42L42_HSBIAS_SC_AUTOCTL, +			CS42L42_HSBIAS_SENSE_EN_MASK | +			CS42L42_AUTO_HSBIAS_HIZ_MASK | +			CS42L42_TIP_SENSE_EN_MASK | +			CS42L42_HSBIAS_SENSE_TRIP_MASK, +			(1 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | +			(1 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | +			(0 << CS42L42_TIP_SENSE_EN_SHIFT) | +			(3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); + +		/* Turn on level detect circuitry */ +		regmap_update_bits(cs42l42->regmap, +			CS42L42_MISC_DET_CTL, +			CS42L42_DETECT_MODE_MASK | +			CS42L42_HSBIAS_CTL_MASK | +			CS42L42_PDN_MIC_LVL_DET_MASK, +			(0 << CS42L42_DETECT_MODE_SHIFT) | +			(3 << CS42L42_HSBIAS_CTL_SHIFT) | +			(0 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); + +		msleep(cs42l42->btn_det_init_dbnce); + +		/* Clear any button interrupts before unmasking them */ +		regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS2, +			    &int_status); + +		/* Unmask button detect interrupts */ +		regmap_update_bits(cs42l42->regmap, +			CS42L42_DET_INT2_MASK, +			CS42L42_M_DETECT_TF_MASK | +			CS42L42_M_DETECT_FT_MASK | +			CS42L42_M_HSBIAS_HIZ_MASK | +			CS42L42_M_SHORT_RLS_MASK | +			CS42L42_M_SHORT_DET_MASK, +			(0 << CS42L42_M_DETECT_TF_SHIFT) | +			(0 << CS42L42_M_DETECT_FT_SHIFT) | +			(0 << CS42L42_M_HSBIAS_HIZ_SHIFT) | +			(1 << CS42L42_M_SHORT_RLS_SHIFT) | +			(1 << CS42L42_M_SHORT_DET_SHIFT)); +	} else { +		/* Make sure button detect and HS bias circuits are off */ +		regmap_update_bits(cs42l42->regmap, +			CS42L42_MISC_DET_CTL, +			CS42L42_DETECT_MODE_MASK | +			CS42L42_HSBIAS_CTL_MASK | +			CS42L42_PDN_MIC_LVL_DET_MASK, +			(0 << CS42L42_DETECT_MODE_SHIFT) | +			(1 << CS42L42_HSBIAS_CTL_SHIFT) | +			(1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); +	} + +	regmap_update_bits(cs42l42->regmap, +				CS42L42_DAC_CTL2, +				CS42L42_HPOUT_PULLDOWN_MASK | +				CS42L42_HPOUT_LOAD_MASK | +				CS42L42_HPOUT_CLAMP_MASK | +				CS42L42_DAC_HPF_EN_MASK | +				CS42L42_DAC_MON_EN_MASK, +				(0 << CS42L42_HPOUT_PULLDOWN_SHIFT) | +				(0 << CS42L42_HPOUT_LOAD_SHIFT) | +				(0 << CS42L42_HPOUT_CLAMP_SHIFT) | +				(1 << CS42L42_DAC_HPF_EN_SHIFT) | +				(0 << CS42L42_DAC_MON_EN_SHIFT)); + +	/* Unmask tip sense interrupts */ +	regmap_update_bits(cs42l42->regmap, +		CS42L42_TSRS_PLUG_INT_MASK, +		CS42L42_RS_PLUG_MASK | +		CS42L42_RS_UNPLUG_MASK | +		CS42L42_TS_PLUG_MASK | +		CS42L42_TS_UNPLUG_MASK, +		(1 << CS42L42_RS_PLUG_SHIFT) | +		(1 << CS42L42_RS_UNPLUG_SHIFT) | +		(0 << CS42L42_TS_PLUG_SHIFT) | +		(0 << CS42L42_TS_UNPLUG_SHIFT)); +} + +static void cs42l42_init_hs_type_detect(struct cs42l42_private *cs42l42) +{ +	/* Mask tip sense interrupts */ +	regmap_update_bits(cs42l42->regmap, +				CS42L42_TSRS_PLUG_INT_MASK, +				CS42L42_RS_PLUG_MASK | +				CS42L42_RS_UNPLUG_MASK | +				CS42L42_TS_PLUG_MASK | +				CS42L42_TS_UNPLUG_MASK, +				(1 << CS42L42_RS_PLUG_SHIFT) | +				(1 << CS42L42_RS_UNPLUG_SHIFT) | +				(1 << CS42L42_TS_PLUG_SHIFT) | +				(1 << CS42L42_TS_UNPLUG_SHIFT)); + +	/* Make sure button detect and HS bias circuits are off */ +	regmap_update_bits(cs42l42->regmap, +				CS42L42_MISC_DET_CTL, +				CS42L42_DETECT_MODE_MASK | +				CS42L42_HSBIAS_CTL_MASK | +				CS42L42_PDN_MIC_LVL_DET_MASK, +				(0 << CS42L42_DETECT_MODE_SHIFT) | +				(1 << CS42L42_HSBIAS_CTL_SHIFT) | +				(1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); + +	/* Set auto HS bias settings to default */ +	regmap_update_bits(cs42l42->regmap, +				CS42L42_HSBIAS_SC_AUTOCTL, +				CS42L42_HSBIAS_SENSE_EN_MASK | +				CS42L42_AUTO_HSBIAS_HIZ_MASK | +				CS42L42_TIP_SENSE_EN_MASK | +				CS42L42_HSBIAS_SENSE_TRIP_MASK, +				(0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | +				(0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | +				(0 << CS42L42_TIP_SENSE_EN_SHIFT) | +				(3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); + +	/* Set hs detect to manual, disabled mode */ +	regmap_update_bits(cs42l42->regmap, +				CS42L42_HSDET_CTL2, +				CS42L42_HSDET_CTRL_MASK | +				CS42L42_HSDET_SET_MASK | +				CS42L42_HSBIAS_REF_MASK | +				CS42L42_HSDET_AUTO_TIME_MASK, +				(0 << CS42L42_HSDET_CTRL_SHIFT) | +				(2 << CS42L42_HSDET_SET_SHIFT) | +				(0 << CS42L42_HSBIAS_REF_SHIFT) | +				(3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); + +	regmap_update_bits(cs42l42->regmap, +				CS42L42_DAC_CTL2, +				CS42L42_HPOUT_PULLDOWN_MASK | +				CS42L42_HPOUT_LOAD_MASK | +				CS42L42_HPOUT_CLAMP_MASK | +				CS42L42_DAC_HPF_EN_MASK | +				CS42L42_DAC_MON_EN_MASK, +				(8 << CS42L42_HPOUT_PULLDOWN_SHIFT) | +				(0 << CS42L42_HPOUT_LOAD_SHIFT) | +				(1 << CS42L42_HPOUT_CLAMP_SHIFT) | +				(1 << CS42L42_DAC_HPF_EN_SHIFT) | +				(1 << CS42L42_DAC_MON_EN_SHIFT)); + +	/* Power up HS bias to 2.7V */ +	regmap_update_bits(cs42l42->regmap, +				CS42L42_MISC_DET_CTL, +				CS42L42_DETECT_MODE_MASK | +				CS42L42_HSBIAS_CTL_MASK | +				CS42L42_PDN_MIC_LVL_DET_MASK, +				(0 << CS42L42_DETECT_MODE_SHIFT) | +				(3 << CS42L42_HSBIAS_CTL_SHIFT) | +				(1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); + +	/* Wait for HS bias to ramp up */ +	msleep(cs42l42->hs_bias_ramp_time); + +	/* Unmask auto detect interrupt */ +	regmap_update_bits(cs42l42->regmap, +				CS42L42_CODEC_INT_MASK, +				CS42L42_PDN_DONE_MASK | +				CS42L42_HSDET_AUTO_DONE_MASK, +				(1 << CS42L42_PDN_DONE_SHIFT) | +				(0 << CS42L42_HSDET_AUTO_DONE_SHIFT)); + +	/* Set hs detect to automatic, enabled mode */ +	regmap_update_bits(cs42l42->regmap, +				CS42L42_HSDET_CTL2, +				CS42L42_HSDET_CTRL_MASK | +				CS42L42_HSDET_SET_MASK | +				CS42L42_HSBIAS_REF_MASK | +				CS42L42_HSDET_AUTO_TIME_MASK, +				(3 << CS42L42_HSDET_CTRL_SHIFT) | +				(2 << CS42L42_HSDET_SET_SHIFT) | +				(0 << CS42L42_HSBIAS_REF_SHIFT) | +				(3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); +} + +static void cs42l42_cancel_hs_type_detect(struct cs42l42_private *cs42l42) +{ +	/* Mask button detect interrupts */ +	regmap_update_bits(cs42l42->regmap, +		CS42L42_DET_INT2_MASK, +		CS42L42_M_DETECT_TF_MASK | +		CS42L42_M_DETECT_FT_MASK | +		CS42L42_M_HSBIAS_HIZ_MASK | +		CS42L42_M_SHORT_RLS_MASK | +		CS42L42_M_SHORT_DET_MASK, +		(1 << CS42L42_M_DETECT_TF_SHIFT) | +		(1 << CS42L42_M_DETECT_FT_SHIFT) | +		(1 << CS42L42_M_HSBIAS_HIZ_SHIFT) | +		(1 << CS42L42_M_SHORT_RLS_SHIFT) | +		(1 << CS42L42_M_SHORT_DET_SHIFT)); + +	/* Ground HS bias */ +	regmap_update_bits(cs42l42->regmap, +				CS42L42_MISC_DET_CTL, +				CS42L42_DETECT_MODE_MASK | +				CS42L42_HSBIAS_CTL_MASK | +				CS42L42_PDN_MIC_LVL_DET_MASK, +				(0 << CS42L42_DETECT_MODE_SHIFT) | +				(1 << CS42L42_HSBIAS_CTL_SHIFT) | +				(1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); + +	/* Set auto HS bias settings to default */ +	regmap_update_bits(cs42l42->regmap, +				CS42L42_HSBIAS_SC_AUTOCTL, +				CS42L42_HSBIAS_SENSE_EN_MASK | +				CS42L42_AUTO_HSBIAS_HIZ_MASK | +				CS42L42_TIP_SENSE_EN_MASK | +				CS42L42_HSBIAS_SENSE_TRIP_MASK, +				(0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | +				(0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | +				(0 << CS42L42_TIP_SENSE_EN_SHIFT) | +				(3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); + +	/* Set hs detect to manual, disabled mode */ +	regmap_update_bits(cs42l42->regmap, +				CS42L42_HSDET_CTL2, +				CS42L42_HSDET_CTRL_MASK | +				CS42L42_HSDET_SET_MASK | +				CS42L42_HSBIAS_REF_MASK | +				CS42L42_HSDET_AUTO_TIME_MASK, +				(0 << CS42L42_HSDET_CTRL_SHIFT) | +				(2 << CS42L42_HSDET_SET_SHIFT) | +				(0 << CS42L42_HSBIAS_REF_SHIFT) | +				(3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); +} + +static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42) +{ +	int bias_level; +	unsigned int detect_status; + +	/* Mask button detect interrupts */ +	regmap_update_bits(cs42l42->regmap, +		CS42L42_DET_INT2_MASK, +		CS42L42_M_DETECT_TF_MASK | +		CS42L42_M_DETECT_FT_MASK | +		CS42L42_M_HSBIAS_HIZ_MASK | +		CS42L42_M_SHORT_RLS_MASK | +		CS42L42_M_SHORT_DET_MASK, +		(1 << CS42L42_M_DETECT_TF_SHIFT) | +		(1 << CS42L42_M_DETECT_FT_SHIFT) | +		(1 << CS42L42_M_HSBIAS_HIZ_SHIFT) | +		(1 << CS42L42_M_SHORT_RLS_SHIFT) | +		(1 << CS42L42_M_SHORT_DET_SHIFT)); + +	usleep_range(cs42l42->btn_det_event_dbnce * 1000, +		     cs42l42->btn_det_event_dbnce * 2000); + +	/* Test all 4 level detect biases */ +	bias_level = 1; +	do { +		/* Adjust button detect level sensitivity */ +		regmap_update_bits(cs42l42->regmap, +			CS42L42_MIC_DET_CTL1, +			CS42L42_LATCH_TO_VP_MASK | +			CS42L42_EVENT_STAT_SEL_MASK | +			CS42L42_HS_DET_LEVEL_MASK, +			(1 << CS42L42_LATCH_TO_VP_SHIFT) | +			(0 << CS42L42_EVENT_STAT_SEL_SHIFT) | +			(cs42l42->bias_thresholds[bias_level] << +			CS42L42_HS_DET_LEVEL_SHIFT)); + +		regmap_read(cs42l42->regmap, CS42L42_DET_STATUS2, +				&detect_status); +	} while ((detect_status & CS42L42_HS_TRUE_MASK) && +		(++bias_level < CS42L42_NUM_BIASES)); + +	switch (bias_level) { +	case 1: /* Function C button press */ +		dev_dbg(cs42l42->codec->dev, "Function C button press\n"); +		break; +	case 2: /* Function B button press */ +		dev_dbg(cs42l42->codec->dev, "Function B button press\n"); +		break; +	case 3: /* Function D button press */ +		dev_dbg(cs42l42->codec->dev, "Function D button press\n"); +		break; +	case 4: /* Function A button press */ +		dev_dbg(cs42l42->codec->dev, "Function A button press\n"); +		break; +	} + +	/* Set button detect level sensitivity back to default */ +	regmap_update_bits(cs42l42->regmap, +		CS42L42_MIC_DET_CTL1, +		CS42L42_LATCH_TO_VP_MASK | +		CS42L42_EVENT_STAT_SEL_MASK | +		CS42L42_HS_DET_LEVEL_MASK, +		(1 << CS42L42_LATCH_TO_VP_SHIFT) | +		(0 << CS42L42_EVENT_STAT_SEL_SHIFT) | +		(cs42l42->bias_thresholds[0] << CS42L42_HS_DET_LEVEL_SHIFT)); + +	/* Clear any button interrupts before unmasking them */ +	regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS2, +		    &detect_status); + +	/* Unmask button detect interrupts */ +	regmap_update_bits(cs42l42->regmap, +		CS42L42_DET_INT2_MASK, +		CS42L42_M_DETECT_TF_MASK | +		CS42L42_M_DETECT_FT_MASK | +		CS42L42_M_HSBIAS_HIZ_MASK | +		CS42L42_M_SHORT_RLS_MASK | +		CS42L42_M_SHORT_DET_MASK, +		(0 << CS42L42_M_DETECT_TF_SHIFT) | +		(0 << CS42L42_M_DETECT_FT_SHIFT) | +		(0 << CS42L42_M_HSBIAS_HIZ_SHIFT) | +		(1 << CS42L42_M_SHORT_RLS_SHIFT) | +		(1 << CS42L42_M_SHORT_DET_SHIFT)); +} + +struct cs42l42_irq_params { +	u16 status_addr; +	u16 mask_addr; +	u8 mask; +}; + +static const struct cs42l42_irq_params irq_params_table[] = { +	{CS42L42_ADC_OVFL_STATUS, CS42L42_ADC_OVFL_INT_MASK, +		CS42L42_ADC_OVFL_VAL_MASK}, +	{CS42L42_MIXER_STATUS, CS42L42_MIXER_INT_MASK, +		CS42L42_MIXER_VAL_MASK}, +	{CS42L42_SRC_STATUS, CS42L42_SRC_INT_MASK, +		CS42L42_SRC_VAL_MASK}, +	{CS42L42_ASP_RX_STATUS, CS42L42_ASP_RX_INT_MASK, +		CS42L42_ASP_RX_VAL_MASK}, +	{CS42L42_ASP_TX_STATUS, CS42L42_ASP_TX_INT_MASK, +		CS42L42_ASP_TX_VAL_MASK}, +	{CS42L42_CODEC_STATUS, CS42L42_CODEC_INT_MASK, +		CS42L42_CODEC_VAL_MASK}, +	{CS42L42_DET_INT_STATUS1, CS42L42_DET_INT1_MASK, +		CS42L42_DET_INT_VAL1_MASK}, +	{CS42L42_DET_INT_STATUS2, CS42L42_DET_INT2_MASK, +		CS42L42_DET_INT_VAL2_MASK}, +	{CS42L42_SRCPL_INT_STATUS, CS42L42_SRCPL_INT_MASK, +		CS42L42_SRCPL_VAL_MASK}, +	{CS42L42_VPMON_STATUS, CS42L42_VPMON_INT_MASK, +		CS42L42_VPMON_VAL_MASK}, +	{CS42L42_PLL_LOCK_STATUS, CS42L42_PLL_LOCK_INT_MASK, +		CS42L42_PLL_LOCK_VAL_MASK}, +	{CS42L42_TSRS_PLUG_STATUS, CS42L42_TSRS_PLUG_INT_MASK, +		CS42L42_TSRS_PLUG_VAL_MASK} +}; + +static irqreturn_t cs42l42_irq_thread(int irq, void *data) +{ +	struct cs42l42_private *cs42l42 = (struct cs42l42_private *)data; +	struct snd_soc_codec *codec = cs42l42->codec; +	unsigned int stickies[12]; +	unsigned int masks[12]; +	unsigned int current_plug_status; +	unsigned int current_button_status; +	unsigned int i; + +	/* Read sticky registers to clear interurpt */ +	for (i = 0; i < ARRAY_SIZE(stickies); i++) { +		regmap_read(cs42l42->regmap, irq_params_table[i].status_addr, +				&(stickies[i])); +		regmap_read(cs42l42->regmap, irq_params_table[i].mask_addr, +				&(masks[i])); +		stickies[i] = stickies[i] & (~masks[i]) & +				irq_params_table[i].mask; +	} + +	/* Read tip sense status before handling type detect */ +	current_plug_status = (stickies[11] & +		(CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK)) >> +		CS42L42_TS_PLUG_SHIFT; + +	/* Read button sense status */ +	current_button_status = stickies[7] & +		(CS42L42_M_DETECT_TF_MASK | +		CS42L42_M_DETECT_FT_MASK | +		CS42L42_M_HSBIAS_HIZ_MASK); + +	/* Check auto-detect status */ +	if ((~masks[5]) & irq_params_table[5].mask) { +		if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) { +			cs42l42_process_hs_type_detect(cs42l42); +			dev_dbg(codec->dev, +				"Auto detect done (%d)\n", +				cs42l42->hs_type); +		} +	} + +	/* Check tip sense status */ +	if ((~masks[11]) & irq_params_table[11].mask) { +		switch (current_plug_status) { +		case CS42L42_TS_PLUG: +			if (cs42l42->plug_state != CS42L42_TS_PLUG) { +				cs42l42->plug_state = CS42L42_TS_PLUG; +				cs42l42_init_hs_type_detect(cs42l42); +			} +			break; + +		case CS42L42_TS_UNPLUG: +			if (cs42l42->plug_state != CS42L42_TS_UNPLUG) { +				cs42l42->plug_state = CS42L42_TS_UNPLUG; +				cs42l42_cancel_hs_type_detect(cs42l42); +				dev_dbg(codec->dev, +					"Unplug event\n"); +			} +			break; + +		default: +			if (cs42l42->plug_state != CS42L42_TS_TRANS) +				cs42l42->plug_state = CS42L42_TS_TRANS; +		} +	} + +	/* Check button detect status */ +	if ((~masks[7]) & irq_params_table[7].mask) { +		if (!(current_button_status & +			CS42L42_M_HSBIAS_HIZ_MASK)) { + +			if (current_button_status & +				CS42L42_M_DETECT_TF_MASK) { +				dev_dbg(codec->dev, +					"Button released\n"); +			} else if (current_button_status & +				CS42L42_M_DETECT_FT_MASK) { +				cs42l42_handle_button_press(cs42l42); +			} +		} +	} + +	return IRQ_HANDLED; +} + +static void cs42l42_set_interrupt_masks(struct cs42l42_private *cs42l42) +{ +	regmap_update_bits(cs42l42->regmap, CS42L42_ADC_OVFL_INT_MASK, +			CS42L42_ADC_OVFL_MASK, +			(1 << CS42L42_ADC_OVFL_SHIFT)); + +	regmap_update_bits(cs42l42->regmap, CS42L42_MIXER_INT_MASK, +			CS42L42_MIX_CHB_OVFL_MASK | +			CS42L42_MIX_CHA_OVFL_MASK | +			CS42L42_EQ_OVFL_MASK | +			CS42L42_EQ_BIQUAD_OVFL_MASK, +			(1 << CS42L42_MIX_CHB_OVFL_SHIFT) | +			(1 << CS42L42_MIX_CHA_OVFL_SHIFT) | +			(1 << CS42L42_EQ_OVFL_SHIFT) | +			(1 << CS42L42_EQ_BIQUAD_OVFL_SHIFT)); + +	regmap_update_bits(cs42l42->regmap, CS42L42_SRC_INT_MASK, +			CS42L42_SRC_ILK_MASK | +			CS42L42_SRC_OLK_MASK | +			CS42L42_SRC_IUNLK_MASK | +			CS42L42_SRC_OUNLK_MASK, +			(1 << CS42L42_SRC_ILK_SHIFT) | +			(1 << CS42L42_SRC_OLK_SHIFT) | +			(1 << CS42L42_SRC_IUNLK_SHIFT) | +			(1 << CS42L42_SRC_OUNLK_SHIFT)); + +	regmap_update_bits(cs42l42->regmap, CS42L42_ASP_RX_INT_MASK, +			CS42L42_ASPRX_NOLRCK_MASK | +			CS42L42_ASPRX_EARLY_MASK | +			CS42L42_ASPRX_LATE_MASK | +			CS42L42_ASPRX_ERROR_MASK | +			CS42L42_ASPRX_OVLD_MASK, +			(1 << CS42L42_ASPRX_NOLRCK_SHIFT) | +			(1 << CS42L42_ASPRX_EARLY_SHIFT) | +			(1 << CS42L42_ASPRX_LATE_SHIFT) | +			(1 << CS42L42_ASPRX_ERROR_SHIFT) | +			(1 << CS42L42_ASPRX_OVLD_SHIFT)); + +	regmap_update_bits(cs42l42->regmap, CS42L42_ASP_TX_INT_MASK, +			CS42L42_ASPTX_NOLRCK_MASK | +			CS42L42_ASPTX_EARLY_MASK | +			CS42L42_ASPTX_LATE_MASK | +			CS42L42_ASPTX_SMERROR_MASK, +			(1 << CS42L42_ASPTX_NOLRCK_SHIFT) | +			(1 << CS42L42_ASPTX_EARLY_SHIFT) | +			(1 << CS42L42_ASPTX_LATE_SHIFT) | +			(1 << CS42L42_ASPTX_SMERROR_SHIFT)); + +	regmap_update_bits(cs42l42->regmap, CS42L42_CODEC_INT_MASK, +			CS42L42_PDN_DONE_MASK | +			CS42L42_HSDET_AUTO_DONE_MASK, +			(1 << CS42L42_PDN_DONE_SHIFT) | +			(1 << CS42L42_HSDET_AUTO_DONE_SHIFT)); + +	regmap_update_bits(cs42l42->regmap, CS42L42_SRCPL_INT_MASK, +			CS42L42_SRCPL_ADC_LK_MASK | +			CS42L42_SRCPL_DAC_LK_MASK | +			CS42L42_SRCPL_ADC_UNLK_MASK | +			CS42L42_SRCPL_DAC_UNLK_MASK, +			(1 << CS42L42_SRCPL_ADC_LK_SHIFT) | +			(1 << CS42L42_SRCPL_DAC_LK_SHIFT) | +			(1 << CS42L42_SRCPL_ADC_UNLK_SHIFT) | +			(1 << CS42L42_SRCPL_DAC_UNLK_SHIFT)); + +	regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT1_MASK, +			CS42L42_TIP_SENSE_UNPLUG_MASK | +			CS42L42_TIP_SENSE_PLUG_MASK | +			CS42L42_HSBIAS_SENSE_MASK, +			(1 << CS42L42_TIP_SENSE_UNPLUG_SHIFT) | +			(1 << CS42L42_TIP_SENSE_PLUG_SHIFT) | +			(1 << CS42L42_HSBIAS_SENSE_SHIFT)); + +	regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT2_MASK, +			CS42L42_M_DETECT_TF_MASK | +			CS42L42_M_DETECT_FT_MASK | +			CS42L42_M_HSBIAS_HIZ_MASK | +			CS42L42_M_SHORT_RLS_MASK | +			CS42L42_M_SHORT_DET_MASK, +			(1 << CS42L42_M_DETECT_TF_SHIFT) | +			(1 << CS42L42_M_DETECT_FT_SHIFT) | +			(1 << CS42L42_M_HSBIAS_HIZ_SHIFT) | +			(1 << CS42L42_M_SHORT_RLS_SHIFT) | +			(1 << CS42L42_M_SHORT_DET_SHIFT)); + +	regmap_update_bits(cs42l42->regmap, CS42L42_VPMON_INT_MASK, +			CS42L42_VPMON_MASK, +			(1 << CS42L42_VPMON_SHIFT)); + +	regmap_update_bits(cs42l42->regmap, CS42L42_PLL_LOCK_INT_MASK, +			CS42L42_PLL_LOCK_MASK, +			(1 << CS42L42_PLL_LOCK_SHIFT)); + +	regmap_update_bits(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK, +			CS42L42_RS_PLUG_MASK | +			CS42L42_RS_UNPLUG_MASK | +			CS42L42_TS_PLUG_MASK | +			CS42L42_TS_UNPLUG_MASK, +			(1 << CS42L42_RS_PLUG_SHIFT) | +			(1 << CS42L42_RS_UNPLUG_SHIFT) | +			(0 << CS42L42_TS_PLUG_SHIFT) | +			(0 << CS42L42_TS_UNPLUG_SHIFT)); +} + +static void cs42l42_setup_hs_type_detect(struct cs42l42_private *cs42l42) +{ +	unsigned int reg; + +	cs42l42->hs_type = CS42L42_PLUG_INVALID; + +	/* Latch analog controls to VP power domain */ +	regmap_update_bits(cs42l42->regmap, CS42L42_MIC_DET_CTL1, +			CS42L42_LATCH_TO_VP_MASK | +			CS42L42_EVENT_STAT_SEL_MASK | +			CS42L42_HS_DET_LEVEL_MASK, +			(1 << CS42L42_LATCH_TO_VP_SHIFT) | +			(0 << CS42L42_EVENT_STAT_SEL_SHIFT) | +			(cs42l42->bias_thresholds[0] << +			CS42L42_HS_DET_LEVEL_SHIFT)); + +	/* Remove ground noise-suppression clamps */ +	regmap_update_bits(cs42l42->regmap, +			CS42L42_HS_CLAMP_DISABLE, +			CS42L42_HS_CLAMP_DISABLE_MASK, +			(1 << CS42L42_HS_CLAMP_DISABLE_SHIFT)); + +	/* Enable the tip sense circuit */ +	regmap_update_bits(cs42l42->regmap, CS42L42_TIPSENSE_CTL, +			CS42L42_TIP_SENSE_CTRL_MASK | +			CS42L42_TIP_SENSE_INV_MASK | +			CS42L42_TIP_SENSE_DEBOUNCE_MASK, +			(3 << CS42L42_TIP_SENSE_CTRL_SHIFT) | +			(0 << CS42L42_TIP_SENSE_INV_SHIFT) | +			(2 << CS42L42_TIP_SENSE_DEBOUNCE_SHIFT)); + +	/* Save the initial status of the tip sense */ +	regmap_read(cs42l42->regmap, +			  CS42L42_TSRS_PLUG_STATUS, +			  ®); +	cs42l42->plug_state = (((char) reg) & +		      (CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK)) >> +		      CS42L42_TS_PLUG_SHIFT; +} + +static const unsigned int threshold_defaults[] = { +	CS42L42_HS_DET_LEVEL_15, +	CS42L42_HS_DET_LEVEL_8, +	CS42L42_HS_DET_LEVEL_4, +	CS42L42_HS_DET_LEVEL_1 +}; + +static int cs42l42_handle_device_data(struct i2c_client *i2c_client, +					struct cs42l42_private *cs42l42) +{ +	struct device_node *np = i2c_client->dev.of_node; +	unsigned int val; +	unsigned int thresholds[CS42L42_NUM_BIASES]; +	int ret; +	int i; + +	ret = of_property_read_u32(np, "cirrus,ts-inv", &val); + +	if (!ret) { +		switch (val) { +		case CS42L42_TS_INV_EN: +		case CS42L42_TS_INV_DIS: +			cs42l42->ts_inv = val; +			break; +		default: +			dev_err(&i2c_client->dev, +				"Wrong cirrus,ts-inv DT value %d\n", +				val); +			cs42l42->ts_inv = CS42L42_TS_INV_DIS; +		} +	} else { +		cs42l42->ts_inv = CS42L42_TS_INV_DIS; +	} + +	regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL, +			CS42L42_TS_INV_MASK, +			(cs42l42->ts_inv << CS42L42_TS_INV_SHIFT)); + +	ret = of_property_read_u32(np, "cirrus,ts-dbnc-rise", &val); + +	if (!ret) { +		switch (val) { +		case CS42L42_TS_DBNCE_0: +		case CS42L42_TS_DBNCE_125: +		case CS42L42_TS_DBNCE_250: +		case CS42L42_TS_DBNCE_500: +		case CS42L42_TS_DBNCE_750: +		case CS42L42_TS_DBNCE_1000: +		case CS42L42_TS_DBNCE_1250: +		case CS42L42_TS_DBNCE_1500: +			cs42l42->ts_dbnc_rise = val; +			break; +		default: +			dev_err(&i2c_client->dev, +				"Wrong cirrus,ts-dbnc-rise DT value %d\n", +				val); +			cs42l42->ts_dbnc_rise = CS42L42_TS_DBNCE_1000; +		} +	} else { +		cs42l42->ts_dbnc_rise = CS42L42_TS_DBNCE_1000; +	} + +	regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL, +			CS42L42_TS_RISE_DBNCE_TIME_MASK, +			(cs42l42->ts_dbnc_rise << +			CS42L42_TS_RISE_DBNCE_TIME_SHIFT)); + +	ret = of_property_read_u32(np, "cirrus,ts-dbnc-fall", &val); + +	if (!ret) { +		switch (val) { +		case CS42L42_TS_DBNCE_0: +		case CS42L42_TS_DBNCE_125: +		case CS42L42_TS_DBNCE_250: +		case CS42L42_TS_DBNCE_500: +		case CS42L42_TS_DBNCE_750: +		case CS42L42_TS_DBNCE_1000: +		case CS42L42_TS_DBNCE_1250: +		case CS42L42_TS_DBNCE_1500: +			cs42l42->ts_dbnc_fall = val; +			break; +		default: +			dev_err(&i2c_client->dev, +				"Wrong cirrus,ts-dbnc-fall DT value %d\n", +				val); +			cs42l42->ts_dbnc_fall = CS42L42_TS_DBNCE_0; +		} +	} else { +		cs42l42->ts_dbnc_fall = CS42L42_TS_DBNCE_0; +	} + +	regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL, +			CS42L42_TS_FALL_DBNCE_TIME_MASK, +			(cs42l42->ts_dbnc_fall << +			CS42L42_TS_FALL_DBNCE_TIME_SHIFT)); + +	ret = of_property_read_u32(np, "cirrus,btn-det-init-dbnce", &val); + +	if (!ret) { +		if ((val >= CS42L42_BTN_DET_INIT_DBNCE_MIN) && +			(val <= CS42L42_BTN_DET_INIT_DBNCE_MAX)) +			cs42l42->btn_det_init_dbnce = val; +		else { +			dev_err(&i2c_client->dev, +				"Wrong cirrus,btn-det-init-dbnce DT value %d\n", +				val); +			cs42l42->btn_det_init_dbnce = +				CS42L42_BTN_DET_INIT_DBNCE_DEFAULT; +		} +	} else { +		cs42l42->btn_det_init_dbnce = +			CS42L42_BTN_DET_INIT_DBNCE_DEFAULT; +	} + +	ret = of_property_read_u32(np, "cirrus,btn-det-event-dbnce", &val); + +	if (!ret) { +		if ((val >= CS42L42_BTN_DET_EVENT_DBNCE_MIN) && +			(val <= CS42L42_BTN_DET_EVENT_DBNCE_MAX)) +			cs42l42->btn_det_event_dbnce = val; +		else { +			dev_err(&i2c_client->dev, +			"Wrong cirrus,btn-det-event-dbnce DT value %d\n", val); +			cs42l42->btn_det_event_dbnce = +				CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT; +		} +	} else { +		cs42l42->btn_det_event_dbnce = +			CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT; +	} + +	ret = of_property_read_u32_array(np, "cirrus,bias-lvls", +				   (u32 *)thresholds, CS42L42_NUM_BIASES); + +	if (!ret) { +		for (i = 0; i < CS42L42_NUM_BIASES; i++) { +			if ((thresholds[i] >= CS42L42_HS_DET_LEVEL_MIN) && +				(thresholds[i] <= CS42L42_HS_DET_LEVEL_MAX)) +				cs42l42->bias_thresholds[i] = thresholds[i]; +			else { +				dev_err(&i2c_client->dev, +				"Wrong cirrus,bias-lvls[%d] DT value %d\n", i, +					thresholds[i]); +				cs42l42->bias_thresholds[i] = +					threshold_defaults[i]; +			} +		} +	} else { +		for (i = 0; i < CS42L42_NUM_BIASES; i++) +			cs42l42->bias_thresholds[i] = threshold_defaults[i]; +	} + +	ret = of_property_read_u32(np, "cirrus,hs-bias-ramp-rate", &val); + +	if (!ret) { +		switch (val) { +		case CS42L42_HSBIAS_RAMP_FAST_RISE_SLOW_FALL: +			cs42l42->hs_bias_ramp_rate = val; +			cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME0; +			break; +		case CS42L42_HSBIAS_RAMP_FAST: +			cs42l42->hs_bias_ramp_rate = val; +			cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME1; +			break; +		case CS42L42_HSBIAS_RAMP_SLOW: +			cs42l42->hs_bias_ramp_rate = val; +			cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2; +			break; +		case CS42L42_HSBIAS_RAMP_SLOWEST: +			cs42l42->hs_bias_ramp_rate = val; +			cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME3; +			break; +		default: +			dev_err(&i2c_client->dev, +				"Wrong cirrus,hs-bias-ramp-rate DT value %d\n", +				val); +			cs42l42->hs_bias_ramp_rate = CS42L42_HSBIAS_RAMP_SLOW; +			cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2; +		} +	} else { +		cs42l42->hs_bias_ramp_rate = CS42L42_HSBIAS_RAMP_SLOW; +		cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2; +	} + +	regmap_update_bits(cs42l42->regmap, CS42L42_HS_BIAS_CTL, +			CS42L42_HSBIAS_RAMP_MASK, +			(cs42l42->hs_bias_ramp_rate << +			CS42L42_HSBIAS_RAMP_SHIFT)); + +	return 0; +} + +static int cs42l42_i2c_probe(struct i2c_client *i2c_client, +				       const struct i2c_device_id *id) +{ +	struct cs42l42_private *cs42l42; +	int ret, i; +	unsigned int devid = 0; +	unsigned int reg; + +	cs42l42 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l42_private), +			       GFP_KERNEL); +	if (!cs42l42) +		return -ENOMEM; + +	i2c_set_clientdata(i2c_client, cs42l42); + +	cs42l42->regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap); +	if (IS_ERR(cs42l42->regmap)) { +		ret = PTR_ERR(cs42l42->regmap); +		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); +		return ret; +	} + +	for (i = 0; i < ARRAY_SIZE(cs42l42->supplies); i++) +		cs42l42->supplies[i].supply = cs42l42_supply_names[i]; + +	ret = devm_regulator_bulk_get(&i2c_client->dev, +				      ARRAY_SIZE(cs42l42->supplies), +				      cs42l42->supplies); +	if (ret != 0) { +		dev_err(&i2c_client->dev, +			"Failed to request supplies: %d\n", ret); +		return ret; +	} + +	ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies), +				    cs42l42->supplies); +	if (ret != 0) { +		dev_err(&i2c_client->dev, +			"Failed to enable supplies: %d\n", ret); +		return ret; +	} + +	/* Reset the Device */ +	cs42l42->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, +		"reset", GPIOD_OUT_LOW); +	if (IS_ERR(cs42l42->reset_gpio)) +		return PTR_ERR(cs42l42->reset_gpio); + +	if (cs42l42->reset_gpio) { +		dev_dbg(&i2c_client->dev, "Found reset GPIO\n"); +		gpiod_set_value_cansleep(cs42l42->reset_gpio, 1); +	} +	mdelay(3); + +	/* Request IRQ */ +	ret = devm_request_threaded_irq(&i2c_client->dev, +			i2c_client->irq, +			NULL, cs42l42_irq_thread, +			IRQF_ONESHOT | IRQF_TRIGGER_LOW, +			"cs42l42", cs42l42); + +	if (ret != 0) +		dev_err(&i2c_client->dev, +			"Failed to request IRQ: %d\n", ret); + +	/* initialize codec */ +	ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_AB, ®); +	devid = (reg & 0xFF) << 12; + +	ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_CD, ®); +	devid |= (reg & 0xFF) << 4; + +	ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_E, ®); +	devid |= (reg & 0xF0) >> 4; + +	if (devid != CS42L42_CHIP_ID) { +		ret = -ENODEV; +		dev_err(&i2c_client->dev, +			"CS42L42 Device ID (%X). Expected %X\n", +			devid, CS42L42_CHIP_ID); +		return ret; +	} + +	ret = regmap_read(cs42l42->regmap, CS42L42_REVID, ®); +	if (ret < 0) { +		dev_err(&i2c_client->dev, "Get Revision ID failed\n"); +		return ret; +	} + +	dev_info(&i2c_client->dev, +		 "Cirrus Logic CS42L42, Revision: %02X\n", reg & 0xFF); + +	/* Power up the codec */ +	regmap_update_bits(cs42l42->regmap, CS42L42_PWR_CTL1, +			CS42L42_ASP_DAO_PDN_MASK | +			CS42L42_ASP_DAI_PDN_MASK | +			CS42L42_MIXER_PDN_MASK | +			CS42L42_EQ_PDN_MASK | +			CS42L42_HP_PDN_MASK | +			CS42L42_ADC_PDN_MASK | +			CS42L42_PDN_ALL_MASK, +			(1 << CS42L42_ASP_DAO_PDN_SHIFT) | +			(1 << CS42L42_ASP_DAI_PDN_SHIFT) | +			(1 << CS42L42_MIXER_PDN_SHIFT) | +			(1 << CS42L42_EQ_PDN_SHIFT) | +			(1 << CS42L42_HP_PDN_SHIFT) | +			(1 << CS42L42_ADC_PDN_SHIFT) | +			(0 << CS42L42_PDN_ALL_SHIFT)); + +	if (i2c_client->dev.of_node) { +		ret = cs42l42_handle_device_data(i2c_client, cs42l42); +		if (ret != 0) +			return ret; +	} + +	/* Setup headset detection */ +	cs42l42_setup_hs_type_detect(cs42l42); + +	/* Mask/Unmask Interrupts */ +	cs42l42_set_interrupt_masks(cs42l42); + +	/* Register codec for machine driver */ +	ret =  snd_soc_register_codec(&i2c_client->dev, +			&soc_codec_dev_cs42l42, &cs42l42_dai, 1); +	if (ret < 0) +		goto err_disable; +	return 0; + +err_disable: +	regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), +				cs42l42->supplies); +	return ret; +} + +static int cs42l42_i2c_remove(struct i2c_client *i2c_client) +{ +	struct cs42l42_private *cs42l42 = i2c_get_clientdata(i2c_client); + +	snd_soc_unregister_codec(&i2c_client->dev); + +	/* Hold down reset */ +	if (cs42l42->reset_gpio) +		gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); + +	return 0; +} + +#ifdef CONFIG_PM +static int cs42l42_runtime_suspend(struct device *dev) +{ +	struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); + +	regcache_cache_only(cs42l42->regmap, true); +	regcache_mark_dirty(cs42l42->regmap); + +	/* Hold down reset */ +	if (cs42l42->reset_gpio) +		gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); + +	/* remove power */ +	regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), +				cs42l42->supplies); + +	return 0; +} + +static int cs42l42_runtime_resume(struct device *dev) +{ +	struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); +	int ret; + +	/* Enable power */ +	ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies), +					cs42l42->supplies); +	if (ret != 0) { +		dev_err(dev, "Failed to enable supplies: %d\n", +			ret); +		return ret; +	} + +	if (cs42l42->reset_gpio) +		gpiod_set_value_cansleep(cs42l42->reset_gpio, 1); + +	regcache_cache_only(cs42l42->regmap, false); +	regcache_sync(cs42l42->regmap); + +	return 0; +} +#endif + +static const struct dev_pm_ops cs42l42_runtime_pm = { +	SET_RUNTIME_PM_OPS(cs42l42_runtime_suspend, cs42l42_runtime_resume, +			   NULL) +}; + +static const struct of_device_id cs42l42_of_match[] = { +	{ .compatible = "cirrus,cs42l42", }, +	{}, +}; +MODULE_DEVICE_TABLE(of, cs42l42_of_match); + + +static const struct i2c_device_id cs42l42_id[] = { +	{"cs42l42", 0}, +	{} +}; + +MODULE_DEVICE_TABLE(i2c, cs42l42_id); + +static struct i2c_driver cs42l42_i2c_driver = { +	.driver = { +		.name = "cs42l42", +		.pm = &cs42l42_runtime_pm, +		.of_match_table = cs42l42_of_match, +		}, +	.id_table = cs42l42_id, +	.probe = cs42l42_i2c_probe, +	.remove = cs42l42_i2c_remove, +}; + +module_i2c_driver(cs42l42_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS42L42 driver"); +MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>"); +MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>"); +MODULE_AUTHOR("Michael White, Cirrus Logic Inc, <michael.white@cirrus.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h new file mode 100644 index 000000000000..d87a0a5322d5 --- /dev/null +++ b/sound/soc/codecs/cs42l42.h @@ -0,0 +1,776 @@ +/* + * cs42l42.h -- CS42L42 ALSA SoC audio driver header + * + * Copyright 2016 Cirrus Logic, Inc. + * + * Author: James Schulman <james.schulman@cirrus.com> + * Author: Brian Austin <brian.austin@cirrus.com> + * Author: Michael White <michael.white@cirrus.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __CS42L42_H__ +#define __CS42L42_H__ + +#define CS42L42_PAGE_REGISTER	0x00	/* Page Select Register */ +#define CS42L42_WIN_START	0x00 +#define CS42L42_WIN_LEN		0x100 +#define CS42L42_RANGE_MIN	0x00 +#define CS42L42_RANGE_MAX	0x7F + +#define CS42L42_PAGE_10		0x1000 +#define CS42L42_PAGE_11		0x1100 +#define CS42L42_PAGE_12		0x1200 +#define CS42L42_PAGE_13		0x1300 +#define CS42L42_PAGE_15		0x1500 +#define CS42L42_PAGE_19		0x1900 +#define CS42L42_PAGE_1B		0x1B00 +#define CS42L42_PAGE_1C		0x1C00 +#define CS42L42_PAGE_1D		0x1D00 +#define CS42L42_PAGE_1F		0x1F00 +#define CS42L42_PAGE_20		0x2000 +#define CS42L42_PAGE_21		0x2100 +#define CS42L42_PAGE_23		0x2300 +#define CS42L42_PAGE_24		0x2400 +#define CS42L42_PAGE_25		0x2500 +#define CS42L42_PAGE_26		0x2600 +#define CS42L42_PAGE_28		0x2800 +#define CS42L42_PAGE_29		0x2900 +#define CS42L42_PAGE_2A		0x2A00 +#define CS42L42_PAGE_30		0x3000 + +#define CS42L42_CHIP_ID		0x42A42 + +/* Page 0x10 Global Registers */ +#define CS42L42_DEVID_AB		(CS42L42_PAGE_10 + 0x01) +#define CS42L42_DEVID_CD		(CS42L42_PAGE_10 + 0x02) +#define CS42L42_DEVID_E			(CS42L42_PAGE_10 + 0x03) +#define CS42L42_FABID			(CS42L42_PAGE_10 + 0x04) +#define CS42L42_REVID			(CS42L42_PAGE_10 + 0x05) +#define CS42L42_FRZ_CTL			(CS42L42_PAGE_10 + 0x06) + +#define CS42L42_SRC_CTL			(CS42L42_PAGE_10 + 0x07) +#define CS42L42_SRC_BYPASS_DAC_SHIFT	1 +#define CS42L42_SRC_BYPASS_DAC_MASK	(1 << CS42L42_SRC_BYPASS_DAC_SHIFT) + +#define CS42L42_MCLK_STATUS		(CS42L42_PAGE_10 + 0x08) + +#define CS42L42_MCLK_CTL		(CS42L42_PAGE_10 + 0x09) +#define CS42L42_INTERNAL_FS_SHIFT	1 +#define CS42L42_INTERNAL_FS_MASK	(1 << CS42L42_INTERNAL_FS_SHIFT) + +#define CS42L42_SFTRAMP_RATE		(CS42L42_PAGE_10 + 0x0A) +#define CS42L42_I2C_DEBOUNCE		(CS42L42_PAGE_10 + 0x0E) +#define CS42L42_I2C_STRETCH		(CS42L42_PAGE_10 + 0x0F) +#define CS42L42_I2C_TIMEOUT		(CS42L42_PAGE_10 + 0x10) + +/* Page 0x11 Power and Headset Detect Registers */ +#define CS42L42_PWR_CTL1		(CS42L42_PAGE_11 + 0x01) +#define CS42L42_ASP_DAO_PDN_SHIFT	7 +#define CS42L42_ASP_DAO_PDN_MASK	(1 << CS42L42_ASP_DAO_PDN_SHIFT) +#define CS42L42_ASP_DAI_PDN_SHIFT	6 +#define CS42L42_ASP_DAI_PDN_MASK	(1 << CS42L42_ASP_DAI_PDN_SHIFT) +#define CS42L42_MIXER_PDN_SHIFT		5 +#define CS42L42_MIXER_PDN_MASK		(1 << CS42L42_MIXER_PDN_SHIFT) +#define CS42L42_EQ_PDN_SHIFT		4 +#define CS42L42_EQ_PDN_MASK		(1 << CS42L42_EQ_PDN_SHIFT) +#define CS42L42_HP_PDN_SHIFT		3 +#define CS42L42_HP_PDN_MASK		(1 << CS42L42_HP_PDN_SHIFT) +#define CS42L42_ADC_PDN_SHIFT		2 +#define CS42L42_ADC_PDN_MASK		(1 << CS42L42_HP_PDN_SHIFT) +#define CS42L42_PDN_ALL_SHIFT		0 +#define CS42L42_PDN_ALL_MASK		(1 << CS42L42_PDN_ALL_SHIFT) + +#define CS42L42_PWR_CTL2		(CS42L42_PAGE_11 + 0x02) +#define CS42L42_ADC_SRC_PDNB_SHIFT	0 +#define CS42L42_ADC_SRC_PDNB_MASK	(1 << CS42L42_ADC_SRC_PDNB_SHIFT) +#define CS42L42_DAC_SRC_PDNB_SHIFT	1 +#define CS42L42_DAC_SRC_PDNB_MASK	(1 << CS42L42_DAC_SRC_PDNB_SHIFT) +#define CS42L42_ASP_DAI1_PDN_SHIFT	2 +#define CS42L42_ASP_DAI1_PDN_MASK	(1 << CS42L42_ASP_DAI1_PDN_SHIFT) +#define CS42L42_SRC_PDN_OVERRIDE_SHIFT	3 +#define CS42L42_SRC_PDN_OVERRIDE_MASK	(1 << CS42L42_SRC_PDN_OVERRIDE_SHIFT) +#define CS42L42_DISCHARGE_FILT_SHIFT	4 +#define CS42L42_DISCHARGE_FILT_MASK	(1 << CS42L42_DISCHARGE_FILT_SHIFT) + +#define CS42L42_PWR_CTL3			(CS42L42_PAGE_11 + 0x03) +#define CS42L42_RING_SENSE_PDNB_SHIFT		1 +#define CS42L42_RING_SENSE_PDNB_MASK		(1 << \ +					CS42L42_RING_SENSE_PDNB_SHIFT) +#define CS42L42_VPMON_PDNB_SHIFT		2 +#define CS42L42_VPMON_PDNB_MASK			(1 << \ +					CS42L42_VPMON_PDNB_SHIFT) +#define CS42L42_SW_CLK_STP_STAT_SEL_SHIFT	5 +#define CS42L42_SW_CLK_STP_STAT_SEL_MASK	(3 << \ +					CS42L42_SW_CLK_STP_STAT_SEL_SHIFT) + +#define CS42L42_RSENSE_CTL1			(CS42L42_PAGE_11 + 0x04) +#define CS42L42_RS_TRIM_R_SHIFT			0 +#define CS42L42_RS_TRIM_R_MASK			(1 << \ +					CS42L42_RS_TRIM_R_SHIFT) +#define CS42L42_RS_TRIM_T_SHIFT			1 +#define CS42L42_RS_TRIM_T_MASK			(1 << \ +					CS42L42_RS_TRIM_T_SHIFT) +#define CS42L42_HPREF_RS_SHIFT			2 +#define CS42L42_HPREF_RS_MASK			(1 << \ +					CS42L42_HPREF_RS_SHIFT) +#define CS42L42_HSBIAS_FILT_REF_RS_SHIFT	3 +#define CS42L42_HSBIAS_FILT_REF_RS_MASK		(1 << \ +					CS42L42_HSBIAS_FILT_REF_RS_SHIFT) +#define CS42L42_RING_SENSE_PU_HIZ_SHIFT		6 +#define CS42L42_RING_SENSE_PU_HIZ_MASK		(1 << \ +					CS42L42_RING_SENSE_PU_HIZ_SHIFT) + +#define CS42L42_RSENSE_CTL2		(CS42L42_PAGE_11 + 0x05) +#define CS42L42_TS_RS_GATE_SHIFT	7 +#define CS42L42_TS_RS_GATE_MAS		(1 << CS42L42_TS_RS_GATE_SHIFT) + +#define CS42L42_OSC_SWITCH		(CS42L42_PAGE_11 + 0x07) +#define CS42L42_SCLK_PRESENT_SHIFT	0 +#define CS42L42_SCLK_PRESENT_MASK	(1 << CS42L42_SCLK_PRESENT_SHIFT) + +#define CS42L42_OSC_SWITCH_STATUS	(CS42L42_PAGE_11 + 0x09) +#define CS42L42_OSC_SW_SEL_STAT_SHIFT	0 +#define CS42L42_OSC_SW_SEL_STAT_MASK	(3 << CS42L42_OSC_SW_SEL_STAT_SHIFT) +#define CS42L42_OSC_PDNB_STAT_SHIFT	2 +#define CS42L42_OSC_PDNB_STAT_MASK	(1 << CS42L42_OSC_SW_SEL_STAT_SHIFT) + +#define CS42L42_RSENSE_CTL3			(CS42L42_PAGE_11 + 0x12) +#define CS42L42_RS_RISE_DBNCE_TIME_SHIFT	0 +#define CS42L42_RS_RISE_DBNCE_TIME_MASK		(7 << \ +					CS42L42_RS_RISE_DBNCE_TIME_SHIFT) +#define CS42L42_RS_FALL_DBNCE_TIME_SHIFT	3 +#define CS42L42_RS_FALL_DBNCE_TIME_MASK		(7 << \ +					CS42L42_RS_FALL_DBNCE_TIME_SHIFT) +#define CS42L42_RS_PU_EN_SHIFT			6 +#define CS42L42_RS_PU_EN_MASK			(1 << \ +					CS42L42_RS_PU_EN_SHIFT) +#define CS42L42_RS_INV_SHIFT			7 +#define CS42L42_RS_INV_MASK			(1 << \ +					CS42L42_RS_INV_SHIFT) + +#define CS42L42_TSENSE_CTL			(CS42L42_PAGE_11 + 0x13) +#define CS42L42_TS_RISE_DBNCE_TIME_SHIFT	0 +#define CS42L42_TS_RISE_DBNCE_TIME_MASK		(7 << \ +					CS42L42_TS_RISE_DBNCE_TIME_SHIFT) +#define CS42L42_TS_FALL_DBNCE_TIME_SHIFT	3 +#define CS42L42_TS_FALL_DBNCE_TIME_MASK		(7 << \ +					CS42L42_TS_FALL_DBNCE_TIME_SHIFT) +#define CS42L42_TS_INV_SHIFT			7 +#define CS42L42_TS_INV_MASK			(1 << \ +					CS42L42_TS_INV_SHIFT) + +#define CS42L42_TSRS_INT_DISABLE	(CS42L42_PAGE_11 + 0x14) +#define CS42L42_D_RS_PLUG_DBNC_SHIFT	0 +#define CS42L42_D_RS_PLUG_DBNC_MASK	(1 << CS42L42_D_RS_PLUG_DBNC_SHIFT) +#define CS42L42_D_RS_UNPLUG_DBNC_SHIFT	1 +#define CS42L42_D_RS_UNPLUG_DBNC_MASK	(1 << CS42L42_D_RS_UNPLUG_DBNC_SHIFT) +#define CS42L42_D_TS_PLUG_DBNC_SHIFT	2 +#define CS42L42_D_TS_PLUG_DBNC_MASK	(1 << CS42L42_D_TS_PLUG_DBNC_SHIFT) +#define CS42L42_D_TS_UNPLUG_DBNC_SHIFT	3 +#define CS42L42_D_TS_UNPLUG_DBNC_MASK	(1 << CS42L42_D_TS_UNPLUG_DBNC_SHIFT) + +#define CS42L42_TRSENSE_STATUS		(CS42L42_PAGE_11 + 0x15) +#define CS42L42_RS_PLUG_DBNC_SHIFT	0 +#define CS42L42_RS_PLUG_DBNC_MASK	(1 << CS42L42_RS_PLUG_DBNC_SHIFT) +#define CS42L42_RS_UNPLUG_DBNC_SHIFT	1 +#define CS42L42_RS_UNPLUG_DBNC_MASK	(1 << CS42L42_RS_UNPLUG_DBNC_SHIFT) +#define CS42L42_TS_PLUG_DBNC_SHIFT	2 +#define CS42L42_TS_PLUG_DBNC_MASK	(1 << CS42L42_TS_PLUG_DBNC_SHIFT) +#define CS42L42_TS_UNPLUG_DBNC_SHIFT	3 +#define CS42L42_TS_UNPLUG_DBNC_MASK	(1 << CS42L42_TS_UNPLUG_DBNC_SHIFT) + +#define CS42L42_HSDET_CTL1		(CS42L42_PAGE_11 + 0x1F) +#define CS42L42_HSDET_COMP1_LVL_SHIFT	0 +#define CS42L42_HSDET_COMP1_LVL_MASK	(15 << CS42L42_HSDET_COMP1_LVL_SHIFT) +#define CS42L42_HSDET_COMP2_LVL_SHIFT	4 +#define CS42L42_HSDET_COMP2_LVL_MASK	(15 << CS42L42_HSDET_COMP2_LVL_SHIFT) + +#define CS42L42_HSDET_CTL2		(CS42L42_PAGE_11 + 0x20) +#define CS42L42_HSDET_AUTO_TIME_SHIFT	0 +#define CS42L42_HSDET_AUTO_TIME_MASK	(3 << CS42L42_HSDET_AUTO_TIME_SHIFT) +#define CS42L42_HSBIAS_REF_SHIFT	3 +#define CS42L42_HSBIAS_REF_MASK		(1 << CS42L42_HSBIAS_REF_SHIFT) +#define CS42L42_HSDET_SET_SHIFT		4 +#define CS42L42_HSDET_SET_MASK		(3 << CS42L42_HSDET_SET_SHIFT) +#define CS42L42_HSDET_CTRL_SHIFT	6 +#define CS42L42_HSDET_CTRL_MASK		(3 << CS42L42_HSDET_CTRL_SHIFT) + +#define CS42L42_HS_SWITCH_CTL		(CS42L42_PAGE_11 + 0x21) +#define CS42L42_SW_GNDHS_HS4_SHIFT	0 +#define CS42L42_SW_GNDHS_HS4_MASK	(1 << CS42L42_SW_GNDHS_HS4_SHIFT) +#define CS42L42_SW_GNDHS_HS3_SHIFT	1 +#define CS42L42_SW_GNDHS_HS3_MASK	(1 << CS42L42_SW_GNDHS_HS3_SHIFT) +#define CS42L42_SW_HSB_HS4_SHIFT	2 +#define CS42L42_SW_HSB_HS4_MASK		(1 << CS42L42_SW_HSB_HS4_SHIFT) +#define CS42L42_SW_HSB_HS3_SHIFT	3 +#define CS42L42_SW_HSB_HS3_MASK		(1 << CS42L42_SW_HSB_HS3_SHIFT) +#define CS42L42_SW_HSB_FILT_HS4_SHIFT	4 +#define CS42L42_SW_HSB_FILT_HS4_MASK	(1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) +#define CS42L42_SW_HSB_FILT_HS3_SHIFT	5 +#define CS42L42_SW_HSB_FILT_HS3_MASK	(1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) +#define CS42L42_SW_REF_HS4_SHIFT	6 +#define CS42L42_SW_REF_HS4_MASK		(1 << CS42L42_SW_REF_HS4_SHIFT) +#define CS42L42_SW_REF_HS3_SHIFT	7 +#define CS42L42_SW_REF_HS3_MASK		(1 << CS42L42_SW_REF_HS3_SHIFT) + +#define CS42L42_HS_DET_STATUS		(CS42L42_PAGE_11 + 0x24) +#define CS42L42_HSDET_TYPE_SHIFT	0 +#define CS42L42_HSDET_TYPE_MASK		(3 << CS42L42_HSDET_TYPE_SHIFT) +#define CS42L42_HSDET_COMP1_OUT_SHIFT	6 +#define CS42L42_HSDET_COMP1_OUT_MASK	(1 << CS42L42_HSDET_COMP1_OUT_SHIFT) +#define CS42L42_HSDET_COMP2_OUT_SHIFT	7 +#define CS42L42_HSDET_COMP2_OUT_MASK	(1 << CS42L42_HSDET_COMP2_OUT_SHIFT) +#define CS42L42_PLUG_CTIA		0 +#define CS42L42_PLUG_OMTP		1 +#define CS42L42_PLUG_HEADPHONE		2 +#define CS42L42_PLUG_INVALID		3 + +#define CS42L42_HS_CLAMP_DISABLE	(CS42L42_PAGE_11 + 0x29) +#define CS42L42_HS_CLAMP_DISABLE_SHIFT	0 +#define CS42L42_HS_CLAMP_DISABLE_MASK	(1 << CS42L42_HS_CLAMP_DISABLE_SHIFT) + +/* Page 0x12 Clocking Registers */ +#define CS42L42_MCLK_SRC_SEL		(CS42L42_PAGE_12 + 0x01) +#define CS42L42_MCLKDIV_SHIFT		1 +#define CS42L42_MCLKDIV_MASK		(1 << CS42L42_MCLKDIV_SHIFT) +#define CS42L42_MCLK_SRC_SEL_SHIFT	0 +#define CS42L42_MCLK_SRC_SEL_MASK	(1 << CS42L42_MCLK_SRC_SEL_SHIFT) + +#define CS42L42_SPDIF_CLK_CFG		(CS42L42_PAGE_12 + 0x02) +#define CS42L42_FSYNC_PW_LOWER		(CS42L42_PAGE_12 + 0x03) + +#define CS42L42_FSYNC_PW_UPPER			(CS42L42_PAGE_12 + 0x04) +#define CS42L42_FSYNC_PULSE_WIDTH_SHIFT		0 +#define CS42L42_FSYNC_PULSE_WIDTH_MASK		(0xff << \ +					CS42L42_FSYNC_PULSE_WIDTH_SHIFT) + +#define CS42L42_FSYNC_P_LOWER		(CS42L42_PAGE_12 + 0x05) + +#define CS42L42_FSYNC_P_UPPER		(CS42L42_PAGE_12 + 0x06) +#define CS42L42_FSYNC_PERIOD_SHIFT	0 +#define CS42L42_FSYNC_PERIOD_MASK	(0xff << CS42L42_FSYNC_PERIOD_SHIFT) + +#define CS42L42_ASP_CLK_CFG		(CS42L42_PAGE_12 + 0x07) +#define CS42L42_ASP_SCLK_EN_SHIFT	5 +#define CS42L42_ASP_SCLK_EN_MASK	(1 << CS42L42_ASP_SCLK_EN_SHIFT) +#define CS42L42_ASP_MASTER_MODE		0x01 +#define CS42L42_ASP_SLAVE_MODE		0x00 +#define CS42L42_ASP_MODE_SHIFT		4 +#define CS42L42_ASP_MODE_MASK		(1 << CS42L42_ASP_MODE_SHIFT) +#define CS42L42_ASP_SCPOL_IN_DAC_SHIFT	2 +#define CS42L42_ASP_SCPOL_IN_DAC_MASK	(1 << CS42L42_ASP_SCPOL_IN_DAC_SHIFT) +#define CS42L42_ASP_LCPOL_IN_SHIFT	0 +#define CS42L42_ASP_LCPOL_IN_MASK	(1 << CS42L42_ASP_LCPOL_IN_SHIFT) +#define CS42L42_ASP_POL_INV		1 + +#define CS42L42_ASP_FRM_CFG		(CS42L42_PAGE_12 + 0x08) +#define CS42L42_ASP_STP_SHIFT		4 +#define CS42L42_ASP_STP_MASK		(1 << CS42L42_ASP_STP_SHIFT) +#define CS42L42_ASP_5050_SHIFT		3 +#define CS42L42_ASP_5050_MASK		(1 << CS42L42_ASP_5050_SHIFT) +#define CS42L42_ASP_FSD_SHIFT		0 +#define CS42L42_ASP_FSD_MASK		(7 << CS42L42_ASP_FSD_SHIFT) +#define CS42L42_ASP_FSD_0_5		1 +#define CS42L42_ASP_FSD_1_0		2 +#define CS42L42_ASP_FSD_1_5		3 +#define CS42L42_ASP_FSD_2_0		4 + +#define CS42L42_FS_RATE_EN		(CS42L42_PAGE_12 + 0x09) +#define CS42L42_FS_EN_SHIFT		0 +#define CS42L42_FS_EN_MASK		(0xf << CS42L42_FS_EN_SHIFT) +#define CS42L42_FS_EN_IASRC_96K		0x1 +#define CS42L42_FS_EN_OASRC_96K		0x2 + +#define CS42L42_IN_ASRC_CLK		(CS42L42_PAGE_12 + 0x0A) +#define CS42L42_CLK_IASRC_SEL_SHIFT	0 +#define CS42L42_CLK_IASRC_SEL_MASK	(1 << CS42L42_CLK_IASRC_SEL_SHIFT) +#define CS42L42_CLK_IASRC_SEL_12	1 + +#define CS42L42_OUT_ASRC_CLK		(CS42L42_PAGE_12 + 0x0B) +#define CS42L42_CLK_OASRC_SEL_SHIFT	0 +#define CS42L42_CLK_OASRC_SEL_MASK	(1 << CS42L42_CLK_OASRC_SEL_SHIFT) +#define CS42L42_CLK_OASRC_SEL_12	1 + +#define CS42L42_PLL_DIV_CFG1		(CS42L42_PAGE_12 + 0x0C) +#define CS42L42_SCLK_PREDIV_SHIFT	0 +#define CS42L42_SCLK_PREDIV_MASK	(3 << CS42L42_SCLK_PREDIV_SHIFT) + +/* Page 0x13 Interrupt Registers */ +/* Interrupts */ +#define CS42L42_ADC_OVFL_STATUS		(CS42L42_PAGE_13 + 0x01) +#define CS42L42_MIXER_STATUS		(CS42L42_PAGE_13 + 0x02) +#define CS42L42_SRC_STATUS		(CS42L42_PAGE_13 + 0x03) +#define CS42L42_ASP_RX_STATUS		(CS42L42_PAGE_13 + 0x04) +#define CS42L42_ASP_TX_STATUS		(CS42L42_PAGE_13 + 0x05) +#define CS42L42_CODEC_STATUS		(CS42L42_PAGE_13 + 0x08) +#define CS42L42_DET_INT_STATUS1		(CS42L42_PAGE_13 + 0x09) +#define CS42L42_DET_INT_STATUS2		(CS42L42_PAGE_13 + 0x0A) +#define CS42L42_SRCPL_INT_STATUS	(CS42L42_PAGE_13 + 0x0B) +#define CS42L42_VPMON_STATUS		(CS42L42_PAGE_13 + 0x0D) +#define CS42L42_PLL_LOCK_STATUS		(CS42L42_PAGE_13 + 0x0E) +#define CS42L42_TSRS_PLUG_STATUS	(CS42L42_PAGE_13 + 0x0F) +/* Masks */ +#define CS42L42_ADC_OVFL_INT_MASK	(CS42L42_PAGE_13 + 0x16) +#define CS42L42_ADC_OVFL_SHIFT		0 +#define CS42L42_ADC_OVFL_MASK		(1 << CS42L42_ADC_OVFL_SHIFT) +#define CS42L42_ADC_OVFL_VAL_MASK	CS42L42_ADC_OVFL_MASK + +#define CS42L42_MIXER_INT_MASK		(CS42L42_PAGE_13 + 0x17) +#define CS42L42_MIX_CHB_OVFL_SHIFT	0 +#define CS42L42_MIX_CHB_OVFL_MASK	(1 << CS42L42_MIX_CHB_OVFL_SHIFT) +#define CS42L42_MIX_CHA_OVFL_SHIFT	1 +#define CS42L42_MIX_CHA_OVFL_MASK	(1 << CS42L42_MIX_CHA_OVFL_SHIFT) +#define CS42L42_EQ_OVFL_SHIFT		2 +#define CS42L42_EQ_OVFL_MASK		(1 << CS42L42_EQ_OVFL_SHIFT) +#define CS42L42_EQ_BIQUAD_OVFL_SHIFT	3 +#define CS42L42_EQ_BIQUAD_OVFL_MASK	(1 << CS42L42_EQ_BIQUAD_OVFL_SHIFT) +#define CS42L42_MIXER_VAL_MASK		(CS42L42_MIX_CHB_OVFL_MASK | \ +					CS42L42_MIX_CHA_OVFL_MASK | \ +					CS42L42_EQ_OVFL_MASK | \ +					CS42L42_EQ_BIQUAD_OVFL_MASK) + +#define CS42L42_SRC_INT_MASK		(CS42L42_PAGE_13 + 0x18) +#define CS42L42_SRC_ILK_SHIFT		0 +#define CS42L42_SRC_ILK_MASK		(1 << CS42L42_SRC_ILK_SHIFT) +#define CS42L42_SRC_OLK_SHIFT		1 +#define CS42L42_SRC_OLK_MASK		(1 << CS42L42_SRC_OLK_SHIFT) +#define CS42L42_SRC_IUNLK_SHIFT		2 +#define CS42L42_SRC_IUNLK_MASK		(1 << CS42L42_SRC_IUNLK_SHIFT) +#define CS42L42_SRC_OUNLK_SHIFT		3 +#define CS42L42_SRC_OUNLK_MASK		(1 << CS42L42_SRC_OUNLK_SHIFT) +#define CS42L42_SRC_VAL_MASK		(CS42L42_SRC_ILK_MASK | \ +					CS42L42_SRC_OLK_MASK | \ +					CS42L42_SRC_IUNLK_MASK | \ +					CS42L42_SRC_OUNLK_MASK) + +#define CS42L42_ASP_RX_INT_MASK		(CS42L42_PAGE_13 + 0x19) +#define CS42L42_ASPRX_NOLRCK_SHIFT	0 +#define CS42L42_ASPRX_NOLRCK_MASK	(1 << CS42L42_ASPRX_NOLRCK_SHIFT) +#define CS42L42_ASPRX_EARLY_SHIFT	1 +#define CS42L42_ASPRX_EARLY_MASK	(1 << CS42L42_ASPRX_EARLY_SHIFT) +#define CS42L42_ASPRX_LATE_SHIFT	2 +#define CS42L42_ASPRX_LATE_MASK		(1 << CS42L42_ASPRX_LATE_SHIFT) +#define CS42L42_ASPRX_ERROR_SHIFT	3 +#define CS42L42_ASPRX_ERROR_MASK	(1 << CS42L42_ASPRX_ERROR_SHIFT) +#define CS42L42_ASPRX_OVLD_SHIFT	4 +#define CS42L42_ASPRX_OVLD_MASK		(1 << CS42L42_ASPRX_OVLD_SHIFT) +#define CS42L42_ASP_RX_VAL_MASK		(CS42L42_ASPRX_NOLRCK_MASK | \ +					CS42L42_ASPRX_EARLY_MASK | \ +					CS42L42_ASPRX_LATE_MASK | \ +					CS42L42_ASPRX_ERROR_MASK | \ +					CS42L42_ASPRX_OVLD_MASK) + +#define CS42L42_ASP_TX_INT_MASK		(CS42L42_PAGE_13 + 0x1A) +#define CS42L42_ASPTX_NOLRCK_SHIFT	0 +#define CS42L42_ASPTX_NOLRCK_MASK	(1 << CS42L42_ASPTX_NOLRCK_SHIFT) +#define CS42L42_ASPTX_EARLY_SHIFT	1 +#define CS42L42_ASPTX_EARLY_MASK	(1 << CS42L42_ASPTX_EARLY_SHIFT) +#define CS42L42_ASPTX_LATE_SHIFT	2 +#define CS42L42_ASPTX_LATE_MASK		(1 << CS42L42_ASPTX_LATE_SHIFT) +#define CS42L42_ASPTX_SMERROR_SHIFT	3 +#define CS42L42_ASPTX_SMERROR_MASK	(1 << CS42L42_ASPTX_SMERROR_SHIFT) +#define CS42L42_ASP_TX_VAL_MASK		(CS42L42_ASPTX_NOLRCK_MASK | \ +					CS42L42_ASPTX_EARLY_MASK | \ +					CS42L42_ASPTX_LATE_MASK | \ +					CS42L42_ASPTX_SMERROR_MASK) + +#define CS42L42_CODEC_INT_MASK		(CS42L42_PAGE_13 + 0x1B) +#define CS42L42_PDN_DONE_SHIFT		0 +#define CS42L42_PDN_DONE_MASK		(1 << CS42L42_PDN_DONE_SHIFT) +#define CS42L42_HSDET_AUTO_DONE_SHIFT	1 +#define CS42L42_HSDET_AUTO_DONE_MASK	(1 << CS42L42_HSDET_AUTO_DONE_SHIFT) +#define CS42L42_CODEC_VAL_MASK		(CS42L42_PDN_DONE_MASK | \ +					CS42L42_HSDET_AUTO_DONE_MASK) + +#define CS42L42_SRCPL_INT_MASK		(CS42L42_PAGE_13 + 0x1C) +#define CS42L42_SRCPL_ADC_LK_SHIFT	0 +#define CS42L42_SRCPL_ADC_LK_MASK	(1 << CS42L42_SRCPL_ADC_LK_SHIFT) +#define CS42L42_SRCPL_DAC_LK_SHIFT	2 +#define CS42L42_SRCPL_DAC_LK_MASK	(1 << CS42L42_SRCPL_DAC_LK_SHIFT) +#define CS42L42_SRCPL_ADC_UNLK_SHIFT	5 +#define CS42L42_SRCPL_ADC_UNLK_MASK	(1 << CS42L42_SRCPL_ADC_UNLK_SHIFT) +#define CS42L42_SRCPL_DAC_UNLK_SHIFT	6 +#define CS42L42_SRCPL_DAC_UNLK_MASK	(1 << CS42L42_SRCPL_DAC_UNLK_SHIFT) +#define CS42L42_SRCPL_VAL_MASK		(CS42L42_SRCPL_ADC_LK_MASK | \ +					CS42L42_SRCPL_DAC_LK_MASK | \ +					CS42L42_SRCPL_ADC_UNLK_MASK | \ +					CS42L42_SRCPL_DAC_UNLK_MASK) + +#define CS42L42_VPMON_INT_MASK		(CS42L42_PAGE_13 + 0x1E) +#define CS42L42_VPMON_SHIFT		0 +#define CS42L42_VPMON_MASK		(1 << CS42L42_VPMON_SHIFT) +#define CS42L42_VPMON_VAL_MASK		CS42L42_VPMON_MASK + +#define CS42L42_PLL_LOCK_INT_MASK	(CS42L42_PAGE_13 + 0x1F) +#define CS42L42_PLL_LOCK_SHIFT		0 +#define CS42L42_PLL_LOCK_MASK		(1 << CS42L42_PLL_LOCK_SHIFT) +#define CS42L42_PLL_LOCK_VAL_MASK	CS42L42_PLL_LOCK_MASK + +#define CS42L42_TSRS_PLUG_INT_MASK	(CS42L42_PAGE_13 + 0x20) +#define CS42L42_RS_PLUG_SHIFT		0 +#define CS42L42_RS_PLUG_MASK		(1 << CS42L42_RS_PLUG_SHIFT) +#define CS42L42_RS_UNPLUG_SHIFT		1 +#define CS42L42_RS_UNPLUG_MASK		(1 << CS42L42_RS_UNPLUG_SHIFT) +#define CS42L42_TS_PLUG_SHIFT		2 +#define CS42L42_TS_PLUG_MASK		(1 << CS42L42_TS_PLUG_SHIFT) +#define CS42L42_TS_UNPLUG_SHIFT		3 +#define CS42L42_TS_UNPLUG_MASK		(1 << CS42L42_TS_UNPLUG_SHIFT) +#define CS42L42_TSRS_PLUG_VAL_MASK	(CS42L42_RS_PLUG_MASK | \ +					CS42L42_RS_UNPLUG_MASK | \ +					CS42L42_TS_PLUG_MASK | \ +					CS42L42_TS_UNPLUG_MASK) +#define CS42L42_TS_PLUG			3 +#define CS42L42_TS_UNPLUG		0 +#define CS42L42_TS_TRANS		1 + +/* Page 0x15 Fractional-N PLL Registers */ +#define CS42L42_PLL_CTL1		(CS42L42_PAGE_15 + 0x01) +#define CS42L42_PLL_START_SHIFT		0 +#define CS42L42_PLL_START_MASK		(1 << CS42L42_PLL_START_SHIFT) + +#define CS42L42_PLL_DIV_FRAC0		(CS42L42_PAGE_15 + 0x02) +#define CS42L42_PLL_DIV_FRAC_SHIFT	0 +#define CS42L42_PLL_DIV_FRAC_MASK	(0xff << CS42L42_PLL_DIV_FRAC_SHIFT) + +#define CS42L42_PLL_DIV_FRAC1		(CS42L42_PAGE_15 + 0x03) +#define CS42L42_PLL_DIV_FRAC2		(CS42L42_PAGE_15 + 0x04) + +#define CS42L42_PLL_DIV_INT		(CS42L42_PAGE_15 + 0x05) +#define CS42L42_PLL_DIV_INT_SHIFT	0 +#define CS42L42_PLL_DIV_INT_MASK	(0xff << CS42L42_PLL_DIV_INT_SHIFT) + +#define CS42L42_PLL_CTL3		(CS42L42_PAGE_15 + 0x08) +#define CS42L42_PLL_DIVOUT_SHIFT	0 +#define CS42L42_PLL_DIVOUT_MASK		(0xff << CS42L42_PLL_DIVOUT_SHIFT) + +#define CS42L42_PLL_CAL_RATIO		(CS42L42_PAGE_15 + 0x0A) +#define CS42L42_PLL_CAL_RATIO_SHIFT	0 +#define CS42L42_PLL_CAL_RATIO_MASK	(0xff << CS42L42_PLL_CAL_RATIO_SHIFT) + +#define CS42L42_PLL_CTL4		(CS42L42_PAGE_15 + 0x1B) +#define CS42L42_PLL_MODE_SHIFT		0 +#define CS42L42_PLL_MODE_MASK		(3 << CS42L42_PLL_MODE_SHIFT) + +/* Page 0x19 HP Load Detect Registers */ +#define CS42L42_LOAD_DET_RCSTAT		(CS42L42_PAGE_19 + 0x25) +#define CS42L42_RLA_STAT_SHIFT		0 +#define CS42L42_RLA_STAT_MASK		(3 << CS42L42_RLA_STAT_SHIFT) +#define CS42L42_RLA_STAT_15_OHM		0 + +#define CS42L42_LOAD_DET_DONE		(CS42L42_PAGE_19 + 0x26) +#define CS42L42_HPLOAD_DET_DONE_SHIFT	0 +#define CS42L42_HPLOAD_DET_DONE_MASK	(1 << CS42L42_HPLOAD_DET_DONE_SHIFT) + +#define CS42L42_LOAD_DET_EN		(CS42L42_PAGE_19 + 0x27) +#define CS42L42_HP_LD_EN_SHIFT		0 +#define CS42L42_HP_LD_EN_MASK		(1 << CS42L42_HP_LD_EN_SHIFT) + +/* Page 0x1B Headset Interface Registers */ +#define CS42L42_HSBIAS_SC_AUTOCTL		(CS42L42_PAGE_1B + 0x70) +#define CS42L42_HSBIAS_SENSE_TRIP_SHIFT		0 +#define CS42L42_HSBIAS_SENSE_TRIP_MASK		(7 << \ +					CS42L42_HSBIAS_SENSE_TRIP_SHIFT) +#define CS42L42_TIP_SENSE_EN_SHIFT		5 +#define CS42L42_TIP_SENSE_EN_MASK		(1 << \ +					CS42L42_TIP_SENSE_EN_SHIFT) +#define CS42L42_AUTO_HSBIAS_HIZ_SHIFT		6 +#define CS42L42_AUTO_HSBIAS_HIZ_MASK		(1 << \ +					CS42L42_AUTO_HSBIAS_HIZ_SHIFT) +#define CS42L42_HSBIAS_SENSE_EN_SHIFT		7 +#define CS42L42_HSBIAS_SENSE_EN_MASK		(1 << \ +					CS42L42_HSBIAS_SENSE_EN_SHIFT) + +#define CS42L42_WAKE_CTL		(CS42L42_PAGE_1B + 0x71) +#define CS42L42_WAKEB_CLEAR_SHIFT	0 +#define CS42L42_WAKEB_CLEAR_MASK	(1 << CS42L42_WAKEB_CLEAR_SHIFT) +#define CS42L42_WAKEB_MODE_SHIFT	5 +#define CS42L42_WAKEB_MODE_MASK		(1 << CS42L42_WAKEB_MODE_SHIFT) +#define CS42L42_M_HP_WAKE_SHIFT		6 +#define CS42L42_M_HP_WAKE_MASK		(1 << CS42L42_M_HP_WAKE_SHIFT) +#define CS42L42_M_MIC_WAKE_SHIFT	7 +#define CS42L42_M_MIC_WAKE_MASK		(1 << CS42L42_M_MIC_WAKE_SHIFT) + +#define CS42L42_ADC_DISABLE_MUTE		(CS42L42_PAGE_1B + 0x72) +#define CS42L42_ADC_DISABLE_S0_MUTE_SHIFT	7 +#define CS42L42_ADC_DISABLE_S0_MUTE_MASK	(1 << \ +					CS42L42_ADC_DISABLE_S0_MUTE_SHIFT) + +#define CS42L42_TIPSENSE_CTL			(CS42L42_PAGE_1B + 0x73) +#define CS42L42_TIP_SENSE_DEBOUNCE_SHIFT	0 +#define CS42L42_TIP_SENSE_DEBOUNCE_MASK		(3 << \ +					CS42L42_TIP_SENSE_DEBOUNCE_SHIFT) +#define CS42L42_TIP_SENSE_INV_SHIFT		5 +#define CS42L42_TIP_SENSE_INV_MASK		(1 << \ +					CS42L42_TIP_SENSE_INV_SHIFT) +#define CS42L42_TIP_SENSE_CTRL_SHIFT		6 +#define CS42L42_TIP_SENSE_CTRL_MASK		(3 << \ +					CS42L42_TIP_SENSE_CTRL_SHIFT) + +#define CS42L42_MISC_DET_CTL		(CS42L42_PAGE_1B + 0x74) +#define CS42L42_PDN_MIC_LVL_DET_SHIFT	0 +#define CS42L42_PDN_MIC_LVL_DET_MASK	(1 << CS42L42_PDN_MIC_LVL_DET_SHIFT) +#define CS42L42_HSBIAS_CTL_SHIFT	1 +#define CS42L42_HSBIAS_CTL_MASK		(3 << CS42L42_HSBIAS_CTL_SHIFT) +#define CS42L42_DETECT_MODE_SHIFT	3 +#define CS42L42_DETECT_MODE_MASK	(3 << CS42L42_DETECT_MODE_SHIFT) + +#define CS42L42_MIC_DET_CTL1		(CS42L42_PAGE_1B + 0x75) +#define CS42L42_HS_DET_LEVEL_SHIFT	0 +#define CS42L42_HS_DET_LEVEL_MASK	(0x3F << CS42L42_HS_DET_LEVEL_SHIFT) +#define CS42L42_EVENT_STAT_SEL_SHIFT	6 +#define CS42L42_EVENT_STAT_SEL_MASK	(1 << CS42L42_EVENT_STAT_SEL_SHIFT) +#define CS42L42_LATCH_TO_VP_SHIFT	7 +#define CS42L42_LATCH_TO_VP_MASK	(1 << CS42L42_LATCH_TO_VP_SHIFT) + +#define CS42L42_MIC_DET_CTL2		(CS42L42_PAGE_1B + 0x76) +#define CS42L42_DEBOUNCE_TIME_SHIFT	5 +#define CS42L42_DEBOUNCE_TIME_MASK	(0x07 << CS42L42_DEBOUNCE_TIME_SHIFT) + +#define CS42L42_DET_STATUS1		(CS42L42_PAGE_1B + 0x77) +#define CS42L42_HSBIAS_HIZ_MODE_SHIFT	6 +#define CS42L42_HSBIAS_HIZ_MODE_MASK	(1 << CS42L42_HSBIAS_HIZ_MODE_SHIFT) +#define CS42L42_TIP_SENSE_SHIFT		7 +#define CS42L42_TIP_SENSE_MASK		(1 << CS42L42_TIP_SENSE_SHIFT) + +#define CS42L42_DET_STATUS2		(CS42L42_PAGE_1B + 0x78) +#define CS42L42_SHORT_TRUE_SHIFT	0 +#define CS42L42_SHORT_TRUE_MASK		(1 << CS42L42_SHORT_TRUE_SHIFT) +#define CS42L42_HS_TRUE_SHIFT	1 +#define CS42L42_HS_TRUE_MASK		(1 << CS42L42_HS_TRUE_SHIFT) + +#define CS42L42_DET_INT1_MASK		(CS42L42_PAGE_1B + 0x79) +#define CS42L42_TIP_SENSE_UNPLUG_SHIFT	5 +#define CS42L42_TIP_SENSE_UNPLUG_MASK	(1 << CS42L42_TIP_SENSE_UNPLUG_SHIFT) +#define CS42L42_TIP_SENSE_PLUG_SHIFT	6 +#define CS42L42_TIP_SENSE_PLUG_MASK	(1 << CS42L42_TIP_SENSE_PLUG_SHIFT) +#define CS42L42_HSBIAS_SENSE_SHIFT	7 +#define CS42L42_HSBIAS_SENSE_MASK	(1 << CS42L42_HSBIAS_SENSE_SHIFT) +#define CS42L42_DET_INT_VAL1_MASK	(CS42L42_TIP_SENSE_UNPLUG_MASK | \ +					CS42L42_TIP_SENSE_PLUG_MASK | \ +					CS42L42_HSBIAS_SENSE_MASK) + +#define CS42L42_DET_INT2_MASK		(CS42L42_PAGE_1B + 0x7A) +#define CS42L42_M_SHORT_DET_SHIFT	0 +#define CS42L42_M_SHORT_DET_MASK	(1 << \ +					CS42L42_M_SHORT_DET_SHIFT) +#define CS42L42_M_SHORT_RLS_SHIFT	1 +#define CS42L42_M_SHORT_RLS_MASK	(1 << \ +					CS42L42_M_SHORT_RLS_SHIFT) +#define CS42L42_M_HSBIAS_HIZ_SHIFT	2 +#define CS42L42_M_HSBIAS_HIZ_MASK	(1 << \ +					CS42L42_M_HSBIAS_HIZ_SHIFT) +#define CS42L42_M_DETECT_FT_SHIFT	6 +#define CS42L42_M_DETECT_FT_MASK	(1 << \ +					CS42L42_M_DETECT_FT_SHIFT) +#define CS42L42_M_DETECT_TF_SHIFT	7 +#define CS42L42_M_DETECT_TF_MASK	(1 << \ +					CS42L42_M_DETECT_TF_SHIFT) +#define CS42L42_DET_INT_VAL2_MASK	(CS42L42_M_SHORT_DET_MASK | \ +					CS42L42_M_SHORT_RLS_MASK | \ +					CS42L42_M_HSBIAS_HIZ_MASK | \ +					CS42L42_M_DETECT_FT_MASK | \ +					CS42L42_M_DETECT_TF_MASK) + +/* Page 0x1C Headset Bias Registers */ +#define CS42L42_HS_BIAS_CTL		(CS42L42_PAGE_1C + 0x03) +#define CS42L42_HSBIAS_RAMP_SHIFT	0 +#define CS42L42_HSBIAS_RAMP_MASK	(3 << CS42L42_HSBIAS_RAMP_SHIFT) +#define CS42L42_HSBIAS_PD_SHIFT		4 +#define CS42L42_HSBIAS_PD_MASK		(1 << CS42L42_HSBIAS_PD_SHIFT) +#define CS42L42_HSBIAS_CAPLESS_SHIFT	7 +#define CS42L42_HSBIAS_CAPLESS_MASK	(1 << CS42L42_HSBIAS_CAPLESS_SHIFT) + +/* Page 0x1D ADC Registers */ +#define CS42L42_ADC_CTL			(CS42L42_PAGE_1D + 0x01) +#define CS42L42_ADC_NOTCH_DIS_SHIFT		5 +#define CS42L42_ADC_FORCE_WEAK_VCM_SHIFT	4 +#define CS42L42_ADC_INV_SHIFT			2 +#define CS42L42_ADC_DIG_BOOST_SHIFT		0 + +#define CS42L42_ADC_VOLUME		(CS42L42_PAGE_1D + 0x03) +#define CS42L42_ADC_VOL_SHIFT		0 + +#define CS42L42_ADC_WNF_HPF_CTL		(CS42L42_PAGE_1D + 0x04) +#define CS42L42_ADC_WNF_CF_SHIFT	4 +#define CS42L42_ADC_WNF_EN_SHIFT	3 +#define CS42L42_ADC_HPF_CF_SHIFT	1 +#define CS42L42_ADC_HPF_EN_SHIFT	0 + +/* Page 0x1F DAC Registers */ +#define CS42L42_DAC_CTL1		(CS42L42_PAGE_1F + 0x01) +#define CS42L42_DACB_INV_SHIFT		1 +#define CS42L42_DACA_INV_SHIFT		0 + +#define CS42L42_DAC_CTL2		(CS42L42_PAGE_1F + 0x06) +#define CS42L42_HPOUT_PULLDOWN_SHIFT	4 +#define CS42L42_HPOUT_PULLDOWN_MASK	(15 << CS42L42_HPOUT_PULLDOWN_SHIFT) +#define CS42L42_HPOUT_LOAD_SHIFT	3 +#define CS42L42_HPOUT_LOAD_MASK		(1 << CS42L42_HPOUT_LOAD_SHIFT) +#define CS42L42_HPOUT_CLAMP_SHIFT	2 +#define CS42L42_HPOUT_CLAMP_MASK	(1 << CS42L42_HPOUT_CLAMP_SHIFT) +#define CS42L42_DAC_HPF_EN_SHIFT	1 +#define CS42L42_DAC_HPF_EN_MASK		(1 << CS42L42_DAC_HPF_EN_SHIFT) +#define CS42L42_DAC_MON_EN_SHIFT	0 +#define CS42L42_DAC_MON_EN_MASK		(1 << CS42L42_DAC_MON_EN_SHIFT) + +/* Page 0x20 HP CTL Registers */ +#define CS42L42_HP_CTL			(CS42L42_PAGE_20 + 0x01) +#define CS42L42_HP_ANA_BMUTE_SHIFT	3 +#define CS42L42_HP_ANA_BMUTE_MASK	(1 << CS42L42_HP_ANA_BMUTE_SHIFT) +#define CS42L42_HP_ANA_AMUTE_SHIFT	2 +#define CS42L42_HP_ANA_AMUTE_MASK	(1 << CS42L42_HP_ANA_AMUTE_SHIFT) +#define CS42L42_HP_FULL_SCALE_VOL_SHIFT	1 +#define CS42L42_HP_FULL_SCALE_VOL_MASK	(1 << CS42L42_HP_FULL_SCALE_VOL_SHIFT) + +/* Page 0x21 Class H Registers */ +#define CS42L42_CLASSH_CTL		(CS42L42_PAGE_21 + 0x01) + +/* Page 0x23 Mixer Volume Registers */ +#define CS42L42_MIXER_CHA_VOL		(CS42L42_PAGE_23 + 0x01) +#define CS42L42_MIXER_ADC_VOL		(CS42L42_PAGE_23 + 0x02) + +#define CS42L42_MIXER_CHB_VOL		(CS42L42_PAGE_23 + 0x03) +#define CS42L42_MIXER_CH_VOL_SHIFT	0 +#define CS42L42_MIXER_CH_VOL_MASK	(0x3f << CS42L42_MIXER_CH_VOL_SHIFT) + +/* Page 0x24 EQ Registers */ +#define CS42L42_EQ_COEF_IN0		(CS42L42_PAGE_24 + 0x01) +#define CS42L42_EQ_COEF_IN1		(CS42L42_PAGE_24 + 0x02) +#define CS42L42_EQ_COEF_IN2		(CS42L42_PAGE_24 + 0x03) +#define CS42L42_EQ_COEF_IN3		(CS42L42_PAGE_24 + 0x04) +#define CS42L42_EQ_COEF_RW		(CS42L42_PAGE_24 + 0x06) +#define CS42L42_EQ_COEF_OUT0		(CS42L42_PAGE_24 + 0x07) +#define CS42L42_EQ_COEF_OUT1		(CS42L42_PAGE_24 + 0x08) +#define CS42L42_EQ_COEF_OUT2		(CS42L42_PAGE_24 + 0x09) +#define CS42L42_EQ_COEF_OUT3		(CS42L42_PAGE_24 + 0x0A) +#define CS42L42_EQ_INIT_STAT		(CS42L42_PAGE_24 + 0x0B) +#define CS42L42_EQ_START_FILT		(CS42L42_PAGE_24 + 0x0C) +#define CS42L42_EQ_MUTE_CTL		(CS42L42_PAGE_24 + 0x0E) + +/* Page 0x25 Audio Port Registers */ +#define CS42L42_SP_RX_CH_SEL		(CS42L42_PAGE_25 + 0x01) + +#define CS42L42_SP_RX_ISOC_CTL		(CS42L42_PAGE_25 + 0x02) +#define CS42L42_SP_RX_RSYNC_SHIFT	6 +#define CS42L42_SP_RX_RSYNC_MASK	(1 << CS42L42_SP_RX_RSYNC_SHIFT) +#define CS42L42_SP_RX_NSB_POS_SHIFT	3 +#define CS42L42_SP_RX_NSB_POS_MASK	(7 << CS42L42_SP_RX_NSB_POS_SHIFT) +#define CS42L42_SP_RX_NFS_NSBB_SHIFT	2 +#define CS42L42_SP_RX_NFS_NSBB_MASK	(1 << CS42L42_SP_RX_NFS_NSBB_SHIFT) +#define CS42L42_SP_RX_ISOC_MODE_SHIFT	0 +#define CS42L42_SP_RX_ISOC_MODE_MASK	(3 << CS42L42_SP_RX_ISOC_MODE_SHIFT) + +#define CS42L42_SP_RX_FS		(CS42L42_PAGE_25 + 0x03) +#define CS42l42_SPDIF_CH_SEL		(CS42L42_PAGE_25 + 0x04) +#define CS42L42_SP_TX_ISOC_CTL		(CS42L42_PAGE_25 + 0x05) +#define CS42L42_SP_TX_FS		(CS42L42_PAGE_25 + 0x06) +#define CS42L42_SPDIF_SW_CTL1		(CS42L42_PAGE_25 + 0x07) + +/* Page 0x26 SRC Registers */ +#define CS42L42_SRC_SDIN_FS		(CS42L42_PAGE_26 + 0x01) +#define CS42L42_SRC_SDIN_FS_SHIFT	0 +#define CS42L42_SRC_SDIN_FS_MASK	(0x1f << CS42L42_SRC_SDIN_FS_SHIFT) + +#define CS42L42_SRC_SDOUT_FS		(CS42L42_PAGE_26 + 0x09) + +/* Page 0x28 S/PDIF Registers */ +#define CS42L42_SPDIF_CTL1		(CS42L42_PAGE_28 + 0x01) +#define CS42L42_SPDIF_CTL2		(CS42L42_PAGE_28 + 0x02) +#define CS42L42_SPDIF_CTL3		(CS42L42_PAGE_28 + 0x03) +#define CS42L42_SPDIF_CTL4		(CS42L42_PAGE_28 + 0x04) + +/* Page 0x29 Serial Port TX Registers */ +#define CS42L42_ASP_TX_SZ_EN		(CS42L42_PAGE_29 + 0x01) +#define CS42L42_ASP_TX_CH_EN		(CS42L42_PAGE_29 + 0x02) +#define CS42L42_ASP_TX_CH_AP_RES	(CS42L42_PAGE_29 + 0x03) +#define CS42L42_ASP_TX_CH1_BIT_MSB	(CS42L42_PAGE_29 + 0x04) +#define CS42L42_ASP_TX_CH1_BIT_LSB	(CS42L42_PAGE_29 + 0x05) +#define CS42L42_ASP_TX_HIZ_DLY_CFG	(CS42L42_PAGE_29 + 0x06) +#define CS42L42_ASP_TX_CH2_BIT_MSB	(CS42L42_PAGE_29 + 0x0A) +#define CS42L42_ASP_TX_CH2_BIT_LSB	(CS42L42_PAGE_29 + 0x0B) + +/* Page 0x2A Serial Port RX Registers */ +#define CS42L42_ASP_RX_DAI0_EN		(CS42L42_PAGE_2A + 0x01) +#define CS42L42_ASP_RX0_CH_EN_SHIFT	2 +#define CS42L42_ASP_RX0_CH_EN_MASK	(0xf << CS42L42_ASP_RX0_CH_EN_SHIFT) +#define CS42L42_ASP_RX0_CH1_EN		1 +#define CS42L42_ASP_RX0_CH2_EN		2 +#define CS42L42_ASP_RX0_CH3_EN		4 +#define CS42L42_ASP_RX0_CH4_EN		8 + +#define CS42L42_ASP_RX_DAI0_CH1_AP_RES	(CS42L42_PAGE_2A + 0x02) +#define CS42L42_ASP_RX_DAI0_CH1_BIT_MSB	(CS42L42_PAGE_2A + 0x03) +#define CS42L42_ASP_RX_DAI0_CH1_BIT_LSB	(CS42L42_PAGE_2A + 0x04) +#define CS42L42_ASP_RX_DAI0_CH2_AP_RES	(CS42L42_PAGE_2A + 0x05) +#define CS42L42_ASP_RX_DAI0_CH2_BIT_MSB	(CS42L42_PAGE_2A + 0x06) +#define CS42L42_ASP_RX_DAI0_CH2_BIT_LSB	(CS42L42_PAGE_2A + 0x07) +#define CS42L42_ASP_RX_DAI0_CH3_AP_RES	(CS42L42_PAGE_2A + 0x08) +#define CS42L42_ASP_RX_DAI0_CH3_BIT_MSB	(CS42L42_PAGE_2A + 0x09) +#define CS42L42_ASP_RX_DAI0_CH3_BIT_LSB	(CS42L42_PAGE_2A + 0x0A) +#define CS42L42_ASP_RX_DAI0_CH4_AP_RES	(CS42L42_PAGE_2A + 0x0B) +#define CS42L42_ASP_RX_DAI0_CH4_BIT_MSB	(CS42L42_PAGE_2A + 0x0C) +#define CS42L42_ASP_RX_DAI0_CH4_BIT_LSB	(CS42L42_PAGE_2A + 0x0D) +#define CS42L42_ASP_RX_DAI1_CH1_AP_RES	(CS42L42_PAGE_2A + 0x0E) +#define CS42L42_ASP_RX_DAI1_CH1_BIT_MSB	(CS42L42_PAGE_2A + 0x0F) +#define CS42L42_ASP_RX_DAI1_CH1_BIT_LSB	(CS42L42_PAGE_2A + 0x10) +#define CS42L42_ASP_RX_DAI1_CH2_AP_RES	(CS42L42_PAGE_2A + 0x11) +#define CS42L42_ASP_RX_DAI1_CH2_BIT_MSB	(CS42L42_PAGE_2A + 0x12) +#define CS42L42_ASP_RX_DAI1_CH2_BIT_LSB	(CS42L42_PAGE_2A + 0x13) + +#define CS42L42_ASP_RX_CH_AP_SHIFT	6 +#define CS42L42_ASP_RX_CH_AP_MASK	(1 << CS42L42_ASP_RX_CH_AP_SHIFT) +#define CS42L42_ASP_RX_CH_AP_LOW	0 +#define CS42L42_ASP_RX_CH_AP_HI		1 +#define CS42L42_ASP_RX_CH_RES_SHIFT	0 +#define CS42L42_ASP_RX_CH_RES_MASK	(3 << CS42L42_ASP_RX_CH_RES_SHIFT) +#define CS42L42_ASP_RX_CH_RES_32	3 +#define CS42L42_ASP_RX_CH_RES_16	1 +#define CS42L42_ASP_RX_CH_BIT_ST_SHIFT	0 +#define CS42L42_ASP_RX_CH_BIT_ST_MASK	(0xff << CS42L42_ASP_RX_CH_BIT_ST_SHIFT) + +/* Page 0x30 ID Registers */ +#define CS42L42_SUB_REVID		(CS42L42_PAGE_30 + 0x14) +#define CS42L42_MAX_REGISTER		(CS42L42_PAGE_30 + 0x14) + +/* Defines for fracturing values spread across multiple registers */ +#define CS42L42_FRAC0_VAL(val)	((val) & 0x0000ff) +#define CS42L42_FRAC1_VAL(val)	(((val) & 0x00ff00) >> 8) +#define CS42L42_FRAC2_VAL(val)	(((val) & 0xff0000) >> 16) + +#define CS42L42_NUM_SUPPLIES	5 + +static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = { +	"VA", +	"VP", +	"VCP", +	"VD_FILT", +	"VL", +}; + +struct  cs42l42_private { +	struct regmap *regmap; +	struct snd_soc_codec *codec; +	struct regulator_bulk_data supplies[CS42L42_NUM_SUPPLIES]; +	struct gpio_desc *reset_gpio; +	struct completion pdn_done; +	u32 sclk; +	u32 srate; +	u32 swidth; +	u8 plug_state; +	u8 hs_type; +	u8 ts_inv; +	u8 ts_dbnc_rise; +	u8 ts_dbnc_fall; +	u8 btn_det_init_dbnce; +	u8 btn_det_event_dbnce; +	u8 bias_thresholds[CS42L42_NUM_BIASES]; +	u8 hs_bias_ramp_rate; +	u8 hs_bias_ramp_time; +}; + +#endif /* __CS42L42_H__ */ diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 54c1768bc818..cb6ca85f1536 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -64,8 +64,6 @@ struct  cs42l56_private {  };  static const struct reg_default cs42l56_reg_defaults[] = { -	{ 1, 0x56 },	/* r01	- ID 1 */ -	{ 2, 0x04 },	/* r02	- ID 2 */  	{ 3, 0x7f },	/* r03	- Power Ctl 1 */  	{ 4, 0xff },	/* r04	- Power Ctl 2 */  	{ 5, 0x00 },	/* ro5	- Clocking Ctl 1 */ @@ -1262,8 +1260,6 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client,  		return ret;  	} -	regcache_cache_bypass(cs42l56->regmap, true); -  	ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, ®);  	devid = reg & CS42L56_CHIP_ID_MASK;  	if (devid != CS42L56_DEVID) { @@ -1279,23 +1275,25 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client,  	dev_info(&i2c_client->dev, "Alpha Rev %X Metal Rev %X\n",  		 alpha_rev, metal_rev); -	regcache_cache_bypass(cs42l56->regmap, false); -  	if (cs42l56->pdata.ain1a_ref_cfg)  		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, -				   CS42L56_AIN1A_REF_MASK, 1); +				   CS42L56_AIN1A_REF_MASK, +				   CS42L56_AIN1A_REF_MASK);  	if (cs42l56->pdata.ain1b_ref_cfg)  		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, -				   CS42L56_AIN1B_REF_MASK, 1); +				   CS42L56_AIN1B_REF_MASK, +				   CS42L56_AIN1B_REF_MASK);  	if (cs42l56->pdata.ain2a_ref_cfg)  		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, -				   CS42L56_AIN2A_REF_MASK, 1); +				   CS42L56_AIN2A_REF_MASK, +				   CS42L56_AIN2A_REF_MASK);  	if (cs42l56->pdata.ain2b_ref_cfg)  		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, -				   CS42L56_AIN2B_REF_MASK, 1); +				   CS42L56_AIN2B_REF_MASK, +				   CS42L56_AIN2B_REF_MASK);  	if (cs42l56->pdata.micbias_lvl)  		regmap_update_bits(cs42l56->regmap, CS42L56_GAIN_BIAS_CTL, diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 71ba5605495f..3df2c473ab88 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1337,8 +1337,6 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,  		gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 1);  	} -	regcache_cache_bypass(cs42l73->regmap, true); -  	/* initialize codec */  	ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, ®);  	devid = (reg & 0xFF) << 12; @@ -1366,8 +1364,6 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,  	dev_info(&i2c_client->dev,  		 "Cirrus Logic CS42L73, Revision: %02X\n", reg & 0xFF); -	regcache_cache_bypass(cs42l73->regmap, false); -  	ret =  snd_soc_register_codec(&i2c_client->dev,  			&soc_codec_dev_cs42l73, cs42l73_dai,  			ARRAY_SIZE(cs42l73_dai)); diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index b4d87379d2bc..c1785bd4ff19 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -321,7 +321,6 @@ static struct snd_soc_dai_driver cs42xx8_dai = {  };  static const struct reg_default cs42xx8_reg[] = { -	{ 0x01, 0x01 },   /* Chip I.D. and Revision Register */  	{ 0x02, 0x00 },   /* Power Control */  	{ 0x03, 0xF0 },   /* Functional Mode */  	{ 0x04, 0x46 },   /* Interface Formats */ @@ -498,13 +497,6 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap)  	/* Make sure hardware reset done */  	msleep(5); -	/* -	 * We haven't marked the chip revision as volatile due to -	 * sharing a register with the right input volume; explicitly -	 * bypass the cache to read it. -	 */ -	regcache_cache_bypass(cs42xx8->regmap, true); -  	/* Validate the chip ID */  	ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);  	if (ret < 0) { @@ -523,8 +515,6 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap)  	dev_info(dev, "found device, revision %X\n",  			val & CS42XX8_CHIPID_REV_ID_MASK); -	regcache_cache_bypass(cs42xx8->regmap, false); -  	cs42xx8_dai.name = cs42xx8->drvdata->name;  	/* Each adc supports stereo input */ diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 5b22564f037c..73559ae864b6 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -335,9 +335,11 @@ static const struct snd_kcontrol_new cs47l24_aec_loopback_mux =  static const struct snd_soc_dapm_widget cs47l24_dapm_widgets[] = {  SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, -		    ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0), +		    ARIZONA_SYSCLK_ENA_SHIFT, 0, arizona_clk_ev, +		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),  SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, -		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), +		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev, +		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),  SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,  		    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),  SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, @@ -1064,7 +1066,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {  static int cs47l24_open(struct snd_compr_stream *stream)  {  	struct snd_soc_pcm_runtime *rtd = stream->private_data; -	struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(rtd->codec); +	struct cs47l24_priv *priv = snd_soc_platform_get_drvdata(rtd->platform);  	struct arizona *arizona = priv->core.arizona;  	int n_adsp; @@ -1113,8 +1115,8 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data)  static int cs47l24_codec_probe(struct snd_soc_codec *codec)  {  	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); +	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);  	struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec); -	struct arizona *arizona = priv->core.arizona;  	int ret;  	priv->core.arizona->dapm = dapm; @@ -1124,14 +1126,6 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)  	arizona_init_mono(codec);  	arizona_init_notifiers(codec); -	ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, -				  "ADSP2 Compressed IRQ", cs47l24_adsp2_irq, -				  priv); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret); -		return ret; -	} -  	ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec);  	if (ret)  		goto err_adsp2_codec_probe; @@ -1145,7 +1139,7 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)  	if (ret)  		goto err_adsp2_codec_probe; -	snd_soc_dapm_disable_pin(dapm, "HAPTICS"); +	snd_soc_component_disable_pin(component, "HAPTICS");  	return 0; @@ -1159,17 +1153,12 @@ err_adsp2_codec_probe:  static int cs47l24_codec_remove(struct snd_soc_codec *codec)  {  	struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec); -	struct arizona *arizona = priv->core.arizona;  	wm_adsp2_codec_remove(&priv->core.adsp[1], codec);  	wm_adsp2_codec_remove(&priv->core.adsp[2], codec);  	priv->core.arizona->dapm = NULL; -	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); - -	arizona_free_spk(codec); -  	return 0;  } @@ -1285,25 +1274,47 @@ static int cs47l24_probe(struct platform_device *pdev)  	pm_runtime_enable(&pdev->dev);  	pm_runtime_idle(&pdev->dev); +	ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, +				  "ADSP2 Compressed IRQ", cs47l24_adsp2_irq, +				  cs47l24); +	if (ret != 0) { +		dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); +		return ret; +	} + +	ret = arizona_init_spk_irqs(arizona); +	if (ret < 0) +		goto err_dsp_irq; +  	ret = snd_soc_register_platform(&pdev->dev, &cs47l24_compr_platform);  	if (ret < 0) {  		dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); -		return ret; +		goto err_spk_irqs;  	}  	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24,  				      cs47l24_dai, ARRAY_SIZE(cs47l24_dai));  	if (ret < 0) {  		dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); -		snd_soc_unregister_platform(&pdev->dev); +		goto err_platform;  	}  	return ret; + +err_platform: +	snd_soc_unregister_platform(&pdev->dev); +err_spk_irqs: +	arizona_free_spk_irqs(arizona); +err_dsp_irq: +	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, cs47l24); + +	return ret;  }  static int cs47l24_remove(struct platform_device *pdev)  {  	struct cs47l24_priv *cs47l24 = platform_get_drvdata(pdev); +	struct arizona *arizona = cs47l24->core.arizona;  	snd_soc_unregister_platform(&pdev->dev);  	snd_soc_unregister_codec(&pdev->dev); @@ -1312,6 +1323,10 @@ static int cs47l24_remove(struct platform_device *pdev)  	wm_adsp2_remove(&cs47l24->core.adsp[1]);  	wm_adsp2_remove(&cs47l24->core.adsp[2]); +	arizona_free_spk_irqs(arizona); + +	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, cs47l24); +  	return 0;  } diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index 2b8914dd5990..6274d79c1353 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -204,10 +204,19 @@ static void da7219_aad_hptest_work(struct work_struct *work)  	snd_soc_update_bits(codec, DA7219_MIXOUT_R_CTRL,  			    DA7219_MIXOUT_R_AMP_EN_MASK,  			    DA7219_MIXOUT_R_AMP_EN_MASK); -	snd_soc_write(codec, DA7219_HP_L_CTRL, -		      DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK); -	snd_soc_write(codec, DA7219_HP_R_CTRL, -		      DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK); +	snd_soc_update_bits(codec, DA7219_HP_L_CTRL, +			    DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK, +			    DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK); +	snd_soc_update_bits(codec, DA7219_HP_R_CTRL, +			    DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK, +			    DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK); +	msleep(DA7219_SETTLING_DELAY); +	snd_soc_update_bits(codec, DA7219_HP_L_CTRL, +			    DA7219_HP_L_AMP_MUTE_EN_MASK | +			    DA7219_HP_L_AMP_MIN_GAIN_EN_MASK, 0); +	snd_soc_update_bits(codec, DA7219_HP_R_CTRL, +			    DA7219_HP_R_AMP_MUTE_EN_MASK | +			    DA7219_HP_R_AMP_MIN_GAIN_EN_MASK, 0);  	/*  	 * If we're running from the internal oscillator then give audio paths @@ -244,6 +253,7 @@ static void da7219_aad_hptest_work(struct work_struct *work)  	regcache_mark_dirty(da7219->regmap);  	regcache_sync_region(da7219->regmap, DA7219_HP_L_CTRL,  			     DA7219_HP_R_CTRL); +	msleep(DA7219_SETTLING_DELAY);  	regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_CTRL,  			     DA7219_MIXOUT_R_CTRL);  	regcache_sync_region(da7219->regmap, DA7219_DROUTING_ST_OUTFILT_1L, diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index cf37936bfe3a..99601627f83c 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -823,6 +823,85 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w,  	}  } +static int da7219_settling_event(struct snd_soc_dapm_widget *w, +				 struct snd_kcontrol *kcontrol, int event) +{ +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +	case SND_SOC_DAPM_POST_PMD: +		msleep(DA7219_SETTLING_DELAY); +		break; +	default: +		break; +	} + +	return 0; +} + +static int da7219_mixout_event(struct snd_soc_dapm_widget *w, +			       struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); +	u8 hp_ctrl, min_gain_mask; + +	switch (w->reg) { +	case DA7219_MIXOUT_L_CTRL: +		hp_ctrl = DA7219_HP_L_CTRL; +		min_gain_mask = DA7219_HP_L_AMP_MIN_GAIN_EN_MASK; +		break; +	case DA7219_MIXOUT_R_CTRL: +		hp_ctrl = DA7219_HP_R_CTRL; +		min_gain_mask = DA7219_HP_R_AMP_MIN_GAIN_EN_MASK; +		break; +	default: +		return -EINVAL; +	} + +	switch (event) { +	case SND_SOC_DAPM_PRE_PMD: +		/* Enable minimum gain on HP to avoid pops */ +		snd_soc_update_bits(codec, hp_ctrl, min_gain_mask, +				    min_gain_mask); + +		msleep(DA7219_MIN_GAIN_DELAY); + +		break; +	case SND_SOC_DAPM_POST_PMU: +		/* Remove minimum gain on HP */ +		snd_soc_update_bits(codec, hp_ctrl, min_gain_mask, 0); + +		break; +	} + +	return 0; +} + +static int da7219_gain_ramp_event(struct snd_soc_dapm_widget *w, +				  struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); +	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); + +	switch (event) { +	case SND_SOC_DAPM_PRE_PMU: +	case SND_SOC_DAPM_PRE_PMD: +		/* Ensure nominal gain ramping for DAPM sequence */ +		da7219->gain_ramp_ctrl = +			snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL); +		snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, +			      DA7219_GAIN_RAMP_RATE_NOMINAL); +		break; +	case SND_SOC_DAPM_POST_PMU: +	case SND_SOC_DAPM_POST_PMD: +		/* Restore previous gain ramp settings */ +		snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, +			      da7219->gain_ramp_ctrl); +		break; +	} + +	return 0; +} +  /*   * DAPM Widgets @@ -907,30 +986,46 @@ static const struct snd_soc_dapm_widget da7219_dapm_widgets[] = {  			   ARRAY_SIZE(da7219_st_out_filtr_mix_controls)),  	/* DACs */ -	SND_SOC_DAPM_DAC("DACL", NULL, DA7219_DAC_L_CTRL, DA7219_DAC_L_EN_SHIFT, -			 DA7219_NO_INVERT), -	SND_SOC_DAPM_DAC("DACR", NULL, DA7219_DAC_R_CTRL, DA7219_DAC_R_EN_SHIFT, -			 DA7219_NO_INVERT), +	SND_SOC_DAPM_DAC_E("DACL", NULL, DA7219_DAC_L_CTRL, +			   DA7219_DAC_L_EN_SHIFT, DA7219_NO_INVERT, +			   da7219_settling_event, +			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_DAC_E("DACR", NULL, DA7219_DAC_R_CTRL, +			   DA7219_DAC_R_EN_SHIFT, DA7219_NO_INVERT, +			   da7219_settling_event, +			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),  	/* Output PGAs */ -	SND_SOC_DAPM_PGA("Mixout Left PGA", DA7219_MIXOUT_L_CTRL, -			 DA7219_MIXOUT_L_AMP_EN_SHIFT, DA7219_NO_INVERT, -			 NULL, 0), -	SND_SOC_DAPM_PGA("Mixout Right PGA", DA7219_MIXOUT_R_CTRL, -			 DA7219_MIXOUT_R_AMP_EN_SHIFT, DA7219_NO_INVERT, -			 NULL, 0), -	SND_SOC_DAPM_PGA("Headphone Left PGA", DA7219_HP_L_CTRL, -			 DA7219_HP_L_AMP_EN_SHIFT, DA7219_NO_INVERT, NULL, 0), -	SND_SOC_DAPM_PGA("Headphone Right PGA", DA7219_HP_R_CTRL, -			 DA7219_HP_R_AMP_EN_SHIFT, DA7219_NO_INVERT, NULL, 0), +	SND_SOC_DAPM_PGA_E("Mixout Left PGA", DA7219_MIXOUT_L_CTRL, +			   DA7219_MIXOUT_L_AMP_EN_SHIFT, DA7219_NO_INVERT, +			   NULL, 0, da7219_mixout_event, +			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +	SND_SOC_DAPM_PGA_E("Mixout Right PGA", DA7219_MIXOUT_R_CTRL, +			   DA7219_MIXOUT_R_AMP_EN_SHIFT, DA7219_NO_INVERT, +			   NULL, 0, da7219_mixout_event, +			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +	SND_SOC_DAPM_SUPPLY_S("Headphone Left PGA", 1, DA7219_HP_L_CTRL, +			      DA7219_HP_L_AMP_EN_SHIFT, DA7219_NO_INVERT, +			      da7219_settling_event, +			      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_SUPPLY_S("Headphone Right PGA", 1, DA7219_HP_R_CTRL, +			      DA7219_HP_R_AMP_EN_SHIFT, DA7219_NO_INVERT, +			      da7219_settling_event, +			      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),  	/* Output Supplies */ -	SND_SOC_DAPM_SUPPLY("Charge Pump", DA7219_CP_CTRL, DA7219_CP_EN_SHIFT, -			    DA7219_NO_INVERT, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("Charge Pump", 0, DA7219_CP_CTRL, +			      DA7219_CP_EN_SHIFT, DA7219_NO_INVERT, +			      da7219_settling_event, +			      SND_SOC_DAPM_POST_PMU),  	/* Outputs */  	SND_SOC_DAPM_OUTPUT("HPL"),  	SND_SOC_DAPM_OUTPUT("HPR"), + +	/* Pre/Post Power */ +	SND_SOC_DAPM_PRE("Pre Power Gain Ramp", da7219_gain_ramp_event), +	SND_SOC_DAPM_POST("Post Power Gain Ramp", da7219_gain_ramp_event),  }; @@ -1003,8 +1098,8 @@ static const struct snd_soc_dapm_route da7219_audio_map[] = {  	{"Mixout Left PGA", NULL, "DACL"},  	{"Mixout Right PGA", NULL, "DACR"}, -	{"Headphone Left PGA", NULL, "Mixout Left PGA"}, -	{"Headphone Right PGA", NULL, "Mixout Right PGA"}, +	{"HPL", NULL, "Mixout Left PGA"}, +	{"HPR", NULL, "Mixout Right PGA"},  	{"HPL", NULL, "Headphone Left PGA"},  	{"HPR", NULL, "Headphone Right PGA"}, @@ -1712,6 +1807,14 @@ static int da7219_probe(struct snd_soc_codec *codec)  			    DA7219_HP_R_AMP_RAMP_EN_MASK,  			    DA7219_HP_R_AMP_RAMP_EN_MASK); +	/* Default minimum gain on HP to avoid pops during DAPM sequencing */ +	snd_soc_update_bits(codec, DA7219_HP_L_CTRL, +			    DA7219_HP_L_AMP_MIN_GAIN_EN_MASK, +			    DA7219_HP_L_AMP_MIN_GAIN_EN_MASK); +	snd_soc_update_bits(codec, DA7219_HP_R_CTRL, +			    DA7219_HP_R_AMP_MIN_GAIN_EN_MASK, +			    DA7219_HP_R_AMP_MIN_GAIN_EN_MASK); +  	/* Default infinite tone gen, start/stop by Kcontrol */  	snd_soc_write(codec, DA7219_TONE_GEN_CYCLES, DA7219_BEEP_CYCLES_MASK); diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index 66d3bad86739..6baba7455fa1 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -777,6 +777,10 @@  #define DA7219_SYS_STAT_CHECK_RETRIES	6  #define DA7219_SYS_STAT_CHECK_DELAY	50 +/* Power up/down Delays */ +#define DA7219_SETTLING_DELAY	40 +#define DA7219_MIN_GAIN_DELAY	30 +  enum da7219_clk_src {  	DA7219_CLKSRC_MCLK = 0,  	DA7219_CLKSRC_MCLK_SQR, @@ -814,6 +818,7 @@ struct da7219_priv {  	bool master;  	bool alc_en; +	u8 gain_ramp_ctrl;  };  #endif /* __DA7219_H */ diff --git a/sound/soc/codecs/es8328.h b/sound/soc/codecs/es8328.h index 1a736e72a929..8930322d712b 100644 --- a/sound/soc/codecs/es8328.h +++ b/sound/soc/codecs/es8328.h @@ -278,43 +278,6 @@ int es8328_probe(struct device *dev, struct regmap *regmap);  #define ES8328_REG_MAX		0x35 -#define ES8328_PLL1		0 -#define ES8328_PLL2		1 - -/* clock inputs */ -#define ES8328_MCLK		0 -#define ES8328_PCMCLK		1 - -/* clock divider id's */ -#define ES8328_PCMDIV		0 -#define ES8328_BCLKDIV		1 -#define ES8328_VXCLKDIV		2 - -/* PCM clock dividers */ -#define ES8328_PCM_DIV_1	(0 << 6) -#define ES8328_PCM_DIV_3	(2 << 6) -#define ES8328_PCM_DIV_5_5	(3 << 6) -#define ES8328_PCM_DIV_2	(4 << 6) -#define ES8328_PCM_DIV_4	(5 << 6) -#define ES8328_PCM_DIV_6	(6 << 6) -#define ES8328_PCM_DIV_8	(7 << 6) - -/* BCLK clock dividers */ -#define ES8328_BCLK_DIV_1	(0 << 7) -#define ES8328_BCLK_DIV_2	(1 << 7) -#define ES8328_BCLK_DIV_4	(2 << 7) -#define ES8328_BCLK_DIV_8	(3 << 7) - -/* VXCLK clock dividers */ -#define ES8328_VXCLK_DIV_1	(0 << 6) -#define ES8328_VXCLK_DIV_2	(1 << 6) -#define ES8328_VXCLK_DIV_4	(2 << 6) -#define ES8328_VXCLK_DIV_8	(3 << 6) -#define ES8328_VXCLK_DIV_16	(4 << 6) - -#define ES8328_DAI_HIFI		0 -#define ES8328_DAI_VOICE	1 -  #define ES8328_1536FS		1536  #define ES8328_1024FS		1024  #define ES8328_768FS		768 diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c new file mode 100644 index 000000000000..d8e8590746af --- /dev/null +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -0,0 +1,890 @@ +#include <linux/module.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/regulator/consumer.h> +#include <linux/types.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/tlv.h> + +#define CDC_D_REVISION1			(0xf000) +#define CDC_D_PERPH_SUBTYPE		(0xf005) +#define CDC_D_CDC_RST_CTL		(0xf046) +#define RST_CTL_DIG_SW_RST_N_MASK	BIT(7) +#define RST_CTL_DIG_SW_RST_N_RESET	0 +#define RST_CTL_DIG_SW_RST_N_REMOVE_RESET BIT(7) + +#define CDC_D_CDC_TOP_CLK_CTL		(0xf048) +#define TOP_CLK_CTL_A_MCLK_MCLK2_EN_MASK (BIT(2) | BIT(3)) +#define TOP_CLK_CTL_A_MCLK_EN_ENABLE	 BIT(2) +#define TOP_CLK_CTL_A_MCLK2_EN_ENABLE	BIT(3) + +#define CDC_D_CDC_ANA_CLK_CTL		(0xf049) +#define ANA_CLK_CTL_EAR_HPHR_CLK_EN_MASK BIT(0) +#define ANA_CLK_CTL_EAR_HPHR_CLK_EN	BIT(0) +#define ANA_CLK_CTL_EAR_HPHL_CLK_EN	BIT(1) +#define ANA_CLK_CTL_SPKR_CLK_EN_MASK	BIT(4) +#define ANA_CLK_CTL_SPKR_CLK_EN	BIT(4) +#define ANA_CLK_CTL_TXA_CLK25_EN	BIT(5) + +#define CDC_D_CDC_DIG_CLK_CTL		(0xf04A) +#define DIG_CLK_CTL_RXD1_CLK_EN		BIT(0) +#define DIG_CLK_CTL_RXD2_CLK_EN		BIT(1) +#define DIG_CLK_CTL_RXD3_CLK_EN		BIT(3) +#define DIG_CLK_CTL_TXD_CLK_EN		BIT(4) +#define DIG_CLK_CTL_NCP_CLK_EN_MASK	BIT(6) +#define DIG_CLK_CTL_NCP_CLK_EN		BIT(6) +#define DIG_CLK_CTL_RXD_PDM_CLK_EN_MASK	BIT(7) +#define DIG_CLK_CTL_RXD_PDM_CLK_EN	BIT(7) + +#define CDC_D_CDC_CONN_TX1_CTL		(0xf050) +#define CONN_TX1_SERIAL_TX1_MUX		GENMASK(1, 0) +#define CONN_TX1_SERIAL_TX1_ADC_1	0x0 +#define CONN_TX1_SERIAL_TX1_RX_PDM_LB	0x1 +#define CONN_TX1_SERIAL_TX1_ZERO	0x2 + +#define CDC_D_CDC_CONN_TX2_CTL		(0xf051) +#define CONN_TX2_SERIAL_TX2_MUX		GENMASK(1, 0) +#define CONN_TX2_SERIAL_TX2_ADC_2	0x0 +#define CONN_TX2_SERIAL_TX2_RX_PDM_LB	0x1 +#define CONN_TX2_SERIAL_TX2_ZERO	0x2 +#define CDC_D_CDC_CONN_HPHR_DAC_CTL	(0xf052) +#define CDC_D_CDC_CONN_RX1_CTL		(0xf053) +#define CDC_D_CDC_CONN_RX2_CTL		(0xf054) +#define CDC_D_CDC_CONN_RX3_CTL		(0xf055) +#define CDC_D_CDC_CONN_RX_LB_CTL	(0xf056) +#define CDC_D_SEC_ACCESS		(0xf0D0) +#define CDC_D_PERPH_RESET_CTL3		(0xf0DA) +#define CDC_D_PERPH_RESET_CTL4		(0xf0DB) +#define CDC_A_REVISION1			(0xf100) +#define CDC_A_REVISION2			(0xf101) +#define CDC_A_REVISION3			(0xf102) +#define CDC_A_REVISION4			(0xf103) +#define CDC_A_PERPH_TYPE		(0xf104) +#define CDC_A_PERPH_SUBTYPE		(0xf105) +#define CDC_A_INT_RT_STS		(0xf110) +#define CDC_A_INT_SET_TYPE		(0xf111) +#define CDC_A_INT_POLARITY_HIGH		(0xf112) +#define CDC_A_INT_POLARITY_LOW		(0xf113) +#define CDC_A_INT_LATCHED_CLR		(0xf114) +#define CDC_A_INT_EN_SET		(0xf115) +#define CDC_A_INT_EN_CLR		(0xf116) +#define CDC_A_INT_LATCHED_STS		(0xf118) +#define CDC_A_INT_PENDING_STS		(0xf119) +#define CDC_A_INT_MID_SEL		(0xf11A) +#define CDC_A_INT_PRIORITY		(0xf11B) +#define CDC_A_MICB_1_EN			(0xf140) +#define MICB_1_EN_MICB_ENABLE		BIT(7) +#define MICB_1_EN_BYP_CAP_MASK		BIT(6) +#define MICB_1_EN_NO_EXT_BYP_CAP	BIT(6) +#define MICB_1_EN_EXT_BYP_CAP		0 +#define MICB_1_EN_PULL_DOWN_EN_MASK	BIT(5) +#define MICB_1_EN_PULL_DOWN_EN_ENABLE	BIT(5) +#define MICB_1_EN_OPA_STG2_TAIL_CURR_MASK GENMASK(3, 1) +#define MICB_1_EN_OPA_STG2_TAIL_CURR_1_60UA	(0x4) +#define MICB_1_EN_PULL_UP_EN_MASK	BIT(4) +#define MICB_1_EN_TX3_GND_SEL_MASK	BIT(0) +#define MICB_1_EN_TX3_GND_SEL_TX_GND	0 + +#define CDC_A_MICB_1_VAL		(0xf141) +#define MICB_1_VAL_MICB_OUT_VAL_MASK	GENMASK(7, 3) +#define MICB_1_VAL_MICB_OUT_VAL_V2P70V	((0x16)  << 3) +#define CDC_A_MICB_1_CTL		(0xf142) + +#define MICB_1_CTL_CFILT_REF_SEL_MASK		BIT(1) +#define MICB_1_CTL_CFILT_REF_SEL_HPF_REF	BIT(1) +#define MICB_1_CTL_EXT_PRECHARG_EN_MASK		BIT(5) +#define MICB_1_CTL_EXT_PRECHARG_EN_ENABLE	BIT(5) +#define MICB_1_CTL_INT_PRECHARG_BYP_MASK	BIT(6) +#define MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL	BIT(6) + +#define CDC_A_MICB_1_INT_RBIAS			(0xf143) +#define MICB_1_INT_TX1_INT_RBIAS_EN_MASK	BIT(7) +#define MICB_1_INT_TX1_INT_RBIAS_EN_ENABLE	BIT(7) +#define MICB_1_INT_TX1_INT_RBIAS_EN_DISABLE	0 + +#define MICB_1_INT_TX1_INT_PULLUP_EN_MASK	BIT(6) +#define MICB_1_INT_TX1_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(6) +#define MICB_1_INT_TX1_INT_PULLUP_EN_TX1N_TO_GND	0 + +#define MICB_1_INT_TX2_INT_RBIAS_EN_MASK	BIT(4) +#define MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE	BIT(4) +#define MICB_1_INT_TX2_INT_RBIAS_EN_DISABLE	0 +#define MICB_1_INT_TX2_INT_PULLUP_EN_MASK	BIT(3) +#define MICB_1_INT_TX2_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(3) +#define MICB_1_INT_TX2_INT_PULLUP_EN_TX1N_TO_GND	0 + +#define MICB_1_INT_TX3_INT_RBIAS_EN_MASK	BIT(1) +#define MICB_1_INT_TX3_INT_RBIAS_EN_ENABLE	BIT(1) +#define MICB_1_INT_TX3_INT_RBIAS_EN_DISABLE	0 +#define MICB_1_INT_TX3_INT_PULLUP_EN_MASK	BIT(0) +#define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(0) +#define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_GND	0 + +#define CDC_A_MICB_2_EN			(0xf144) +#define CDC_A_TX_1_2_ATEST_CTL_2	(0xf145) +#define CDC_A_MASTER_BIAS_CTL		(0xf146) +#define CDC_A_TX_1_EN			(0xf160) +#define CDC_A_TX_2_EN			(0xf161) +#define CDC_A_TX_1_2_TEST_CTL_1		(0xf162) +#define CDC_A_TX_1_2_TEST_CTL_2		(0xf163) +#define CDC_A_TX_1_2_ATEST_CTL		(0xf164) +#define CDC_A_TX_1_2_OPAMP_BIAS		(0xf165) +#define CDC_A_TX_3_EN			(0xf167) +#define CDC_A_NCP_EN			(0xf180) +#define CDC_A_NCP_CLK			(0xf181) +#define CDC_A_NCP_FBCTRL		(0xf183) +#define CDC_A_NCP_FBCTRL_FB_CLK_INV_MASK	BIT(5) +#define CDC_A_NCP_FBCTRL_FB_CLK_INV		BIT(5) +#define CDC_A_NCP_BIAS			(0xf184) +#define CDC_A_NCP_VCTRL			(0xf185) +#define CDC_A_NCP_TEST			(0xf186) +#define CDC_A_NCP_CLIM_ADDR		(0xf187) +#define CDC_A_RX_CLOCK_DIVIDER		(0xf190) +#define CDC_A_RX_COM_OCP_CTL		(0xf191) +#define CDC_A_RX_COM_OCP_COUNT		(0xf192) +#define CDC_A_RX_COM_BIAS_DAC		(0xf193) +#define RX_COM_BIAS_DAC_RX_BIAS_EN_MASK		BIT(7) +#define RX_COM_BIAS_DAC_RX_BIAS_EN_ENABLE	BIT(7) +#define RX_COM_BIAS_DAC_DAC_REF_EN_MASK		BIT(0) +#define RX_COM_BIAS_DAC_DAC_REF_EN_ENABLE	BIT(0) + +#define CDC_A_RX_HPH_BIAS_PA		(0xf194) +#define CDC_A_RX_HPH_BIAS_LDO_OCP	(0xf195) +#define CDC_A_RX_HPH_BIAS_CNP		(0xf196) +#define CDC_A_RX_HPH_CNP_EN		(0xf197) +#define CDC_A_RX_HPH_L_PA_DAC_CTL	(0xf19B) +#define RX_HPA_L_PA_DAC_CTL_DATA_RESET_MASK	BIT(1) +#define RX_HPA_L_PA_DAC_CTL_DATA_RESET_RESET	BIT(1) +#define CDC_A_RX_HPH_R_PA_DAC_CTL	(0xf19D) +#define RX_HPH_R_PA_DAC_CTL_DATA_RESET	BIT(1) +#define RX_HPH_R_PA_DAC_CTL_DATA_RESET_MASK BIT(1) + +#define CDC_A_RX_EAR_CTL			(0xf19E) +#define RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK		BIT(0) +#define RX_EAR_CTL_SPK_VBAT_LDO_EN_ENABLE	BIT(0) + +#define CDC_A_SPKR_DAC_CTL		(0xf1B0) +#define SPKR_DAC_CTL_DAC_RESET_MASK	BIT(4) +#define SPKR_DAC_CTL_DAC_RESET_NORMAL	0 + +#define CDC_A_SPKR_DRV_CTL		(0xf1B2) +#define SPKR_DRV_CTL_DEF_MASK		0xEF +#define SPKR_DRV_CLASSD_PA_EN_MASK	BIT(7) +#define SPKR_DRV_CLASSD_PA_EN_ENABLE	BIT(7) +#define SPKR_DRV_CAL_EN			BIT(6) +#define SPKR_DRV_SETTLE_EN		BIT(5) +#define SPKR_DRV_FW_EN			BIT(3) +#define SPKR_DRV_BOOST_SET		BIT(2) +#define SPKR_DRV_CMFB_SET		BIT(1) +#define SPKR_DRV_GAIN_SET		BIT(0) +#define SPKR_DRV_CTL_DEF_VAL (SPKR_DRV_CLASSD_PA_EN_ENABLE | \ +		SPKR_DRV_CAL_EN | SPKR_DRV_SETTLE_EN | \ +		SPKR_DRV_FW_EN | SPKR_DRV_BOOST_SET | \ +		SPKR_DRV_CMFB_SET | SPKR_DRV_GAIN_SET) +#define CDC_A_SPKR_OCP_CTL		(0xf1B4) +#define CDC_A_SPKR_PWRSTG_CTL		(0xf1B5) +#define SPKR_PWRSTG_CTL_DAC_EN_MASK	BIT(0) +#define SPKR_PWRSTG_CTL_DAC_EN		BIT(0) +#define SPKR_PWRSTG_CTL_MASK		0xE0 +#define SPKR_PWRSTG_CTL_BBM_MASK	BIT(7) +#define SPKR_PWRSTG_CTL_BBM_EN		BIT(7) +#define SPKR_PWRSTG_CTL_HBRDGE_EN_MASK	BIT(6) +#define SPKR_PWRSTG_CTL_HBRDGE_EN	BIT(6) +#define SPKR_PWRSTG_CTL_CLAMP_EN_MASK	BIT(5) +#define SPKR_PWRSTG_CTL_CLAMP_EN	BIT(5) + +#define CDC_A_SPKR_DRV_DBG		(0xf1B7) +#define CDC_A_CURRENT_LIMIT		(0xf1C0) +#define CDC_A_BOOST_EN_CTL		(0xf1C3) +#define CDC_A_SLOPE_COMP_IP_ZERO	(0xf1C4) +#define CDC_A_SEC_ACCESS		(0xf1D0) +#define CDC_A_PERPH_RESET_CTL3		(0xf1DA) +#define CDC_A_PERPH_RESET_CTL4		(0xf1DB) + +#define MSM8916_WCD_ANALOG_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ +			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000) +#define MSM8916_WCD_ANALOG_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ +				    SNDRV_PCM_FMTBIT_S24_LE) + +static const char * const supply_names[] = { +	"vdd-cdc-io", +	"vdd-cdc-tx-rx-cx", +}; + +struct pm8916_wcd_analog_priv { +	u16 pmic_rev; +	u16 codec_version; +	struct clk *mclk; +	struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; +	bool micbias1_cap_mode; +	bool micbias2_cap_mode; +}; + +static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" }; +static const char *const rdac2_mux_text[] = { "ZERO", "RX2", "RX1" }; +static const char *const hph_text[] = { "ZERO", "Switch", }; + +static const struct soc_enum hph_enum = SOC_ENUM_SINGLE_VIRT( +					ARRAY_SIZE(hph_text), hph_text); + +static const struct snd_kcontrol_new hphl_mux = SOC_DAPM_ENUM("HPHL", hph_enum); +static const struct snd_kcontrol_new hphr_mux = SOC_DAPM_ENUM("HPHR", hph_enum); + +/* ADC2 MUX */ +static const struct soc_enum adc2_enum = SOC_ENUM_SINGLE_VIRT( +			ARRAY_SIZE(adc2_mux_text), adc2_mux_text); + +/* RDAC2 MUX */ +static const struct soc_enum rdac2_mux_enum = SOC_ENUM_SINGLE( +			CDC_D_CDC_CONN_HPHR_DAC_CTL, 0, 3, rdac2_mux_text); + +static const struct snd_kcontrol_new spkr_switch[] = { +	SOC_DAPM_SINGLE("Switch", CDC_A_SPKR_DAC_CTL, 7, 1, 0) +}; + +static const struct snd_kcontrol_new rdac2_mux = SOC_DAPM_ENUM( +					"RDAC2 MUX Mux", rdac2_mux_enum); +static const struct snd_kcontrol_new tx_adc2_mux = SOC_DAPM_ENUM( +					"ADC2 MUX Mux", adc2_enum); + +/* Analog Gain control 0 dB to +24 dB in 6 dB steps */ +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 600, 0); + +static const struct snd_kcontrol_new pm8916_wcd_analog_snd_controls[] = { +	SOC_SINGLE_TLV("ADC1 Volume", CDC_A_TX_1_EN, 3, 8, 0, analog_gain), +	SOC_SINGLE_TLV("ADC2 Volume", CDC_A_TX_2_EN, 3, 8, 0, analog_gain), +	SOC_SINGLE_TLV("ADC3 Volume", CDC_A_TX_3_EN, 3, 8, 0, analog_gain), +}; + +static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec) +{ +	snd_soc_update_bits(codec, CDC_A_MICB_1_CTL, +			    MICB_1_CTL_EXT_PRECHARG_EN_MASK | +			    MICB_1_CTL_INT_PRECHARG_BYP_MASK, +			    MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL +			    | MICB_1_CTL_EXT_PRECHARG_EN_ENABLE); + +	snd_soc_write(codec, CDC_A_MICB_1_VAL, MICB_1_VAL_MICB_OUT_VAL_V2P70V); +	/* +	 * Special headset needs MICBIAS as 2.7V so wait for +	 * 50 msec for the MICBIAS to reach 2.7 volts. +	 */ +	msleep(50); +	snd_soc_update_bits(codec, CDC_A_MICB_1_CTL, +			    MICB_1_CTL_EXT_PRECHARG_EN_MASK | +			    MICB_1_CTL_INT_PRECHARG_BYP_MASK, 0); + +} + +static int pm8916_wcd_analog_enable_micbias_ext(struct snd_soc_codec +						 *codec, int event, +						 int reg, u32 cap_mode) +{ +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		pm8916_wcd_analog_micbias_enable(codec); +		snd_soc_update_bits(codec, CDC_A_MICB_1_EN, +				    MICB_1_EN_BYP_CAP_MASK, cap_mode); +		break; +	} + +	return 0; +} + +static int pm8916_wcd_analog_enable_micbias_int(struct snd_soc_codec +						 *codec, int event, +						 int reg, u32 cap_mode) +{ + +	switch (event) { +	case SND_SOC_DAPM_PRE_PMU: +		snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS, +				    MICB_1_INT_TX2_INT_RBIAS_EN_MASK, +				    MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE); +		snd_soc_update_bits(codec, reg, MICB_1_EN_PULL_DOWN_EN_MASK, 0); +		snd_soc_update_bits(codec, CDC_A_MICB_1_EN, +				    MICB_1_EN_OPA_STG2_TAIL_CURR_MASK, +				    MICB_1_EN_OPA_STG2_TAIL_CURR_1_60UA); + +		break; +	case SND_SOC_DAPM_POST_PMU: +		pm8916_wcd_analog_micbias_enable(codec); +		snd_soc_update_bits(codec, CDC_A_MICB_1_EN, +				    MICB_1_EN_BYP_CAP_MASK, cap_mode); +		break; +	} + +	return 0; +} + +static int pm8916_wcd_analog_enable_micbias_ext1(struct +						  snd_soc_dapm_widget +						  *w, struct snd_kcontrol +						  *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); +	struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); + +	return pm8916_wcd_analog_enable_micbias_ext(codec, event, w->reg, +						     wcd->micbias1_cap_mode); +} + +static int pm8916_wcd_analog_enable_micbias_ext2(struct +						  snd_soc_dapm_widget +						  *w, struct snd_kcontrol +						  *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); +	struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); + +	return pm8916_wcd_analog_enable_micbias_ext(codec, event, w->reg, +						     wcd->micbias2_cap_mode); + +} + +static int pm8916_wcd_analog_enable_micbias_int1(struct +						  snd_soc_dapm_widget +						  *w, struct snd_kcontrol +						  *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); +	struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); + +	return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg, +						     wcd->micbias1_cap_mode); +} + +static int pm8916_wcd_analog_enable_micbias_int2(struct +						  snd_soc_dapm_widget +						  *w, struct snd_kcontrol +						  *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); +	struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); + +	return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg, +						     wcd->micbias2_cap_mode); +} + +static int pm8916_wcd_analog_enable_adc(struct snd_soc_dapm_widget *w, +					 struct snd_kcontrol *kcontrol, +					 int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); +	u16 adc_reg = CDC_A_TX_1_2_TEST_CTL_2; +	u8 init_bit_shift; + +	if (w->reg == CDC_A_TX_1_EN) +		init_bit_shift = 5; +	else +		init_bit_shift = 4; + +	switch (event) { +	case SND_SOC_DAPM_PRE_PMU: +		if (w->reg == CDC_A_TX_2_EN) +			snd_soc_update_bits(codec, CDC_A_MICB_1_CTL, +					    MICB_1_CTL_CFILT_REF_SEL_MASK, +					    MICB_1_CTL_CFILT_REF_SEL_HPF_REF); +		/* +		 * Add delay of 10 ms to give sufficient time for the voltage +		 * to shoot up and settle so that the txfe init does not +		 * happen when the input voltage is changing too much. +		 */ +		usleep_range(10000, 10010); +		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, +				    1 << init_bit_shift); +		switch (w->reg) { +		case CDC_A_TX_1_EN: +			snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX1_CTL, +					    CONN_TX1_SERIAL_TX1_MUX, +					    CONN_TX1_SERIAL_TX1_ADC_1); +			break; +		case CDC_A_TX_2_EN: +		case CDC_A_TX_3_EN: +			snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX2_CTL, +					    CONN_TX2_SERIAL_TX2_MUX, +					    CONN_TX2_SERIAL_TX2_ADC_2); +			break; +		} +		break; +	case SND_SOC_DAPM_POST_PMU: +		/* +		 * Add delay of 12 ms before deasserting the init +		 * to reduce the tx pop +		 */ +		usleep_range(12000, 12010); +		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00); +		break; +	case SND_SOC_DAPM_POST_PMD: +		switch (w->reg) { +		case CDC_A_TX_1_EN: +			snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX1_CTL, +					    CONN_TX1_SERIAL_TX1_MUX, +					    CONN_TX1_SERIAL_TX1_ZERO); +			break; +		case CDC_A_TX_2_EN: +			snd_soc_update_bits(codec, CDC_A_MICB_1_CTL, +					    MICB_1_CTL_CFILT_REF_SEL_MASK, 0); +		case CDC_A_TX_3_EN: +			snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX2_CTL, +					    CONN_TX2_SERIAL_TX2_MUX, +					    CONN_TX2_SERIAL_TX2_ZERO); +			break; +		} + + +		break; +	} +	return 0; +} + +static int pm8916_wcd_analog_enable_spk_pa(struct snd_soc_dapm_widget *w, +					    struct snd_kcontrol *kcontrol, +					    int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + +	switch (event) { +	case SND_SOC_DAPM_PRE_PMU: +		snd_soc_update_bits(codec, CDC_A_SPKR_PWRSTG_CTL, +				    SPKR_PWRSTG_CTL_DAC_EN_MASK | +				    SPKR_PWRSTG_CTL_BBM_MASK | +				    SPKR_PWRSTG_CTL_HBRDGE_EN_MASK | +				    SPKR_PWRSTG_CTL_CLAMP_EN_MASK, +				    SPKR_PWRSTG_CTL_DAC_EN| +				    SPKR_PWRSTG_CTL_BBM_EN | +				    SPKR_PWRSTG_CTL_HBRDGE_EN | +				    SPKR_PWRSTG_CTL_CLAMP_EN); + +		snd_soc_update_bits(codec, CDC_A_RX_EAR_CTL, +				    RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK, +				    RX_EAR_CTL_SPK_VBAT_LDO_EN_ENABLE); +		break; +	case SND_SOC_DAPM_POST_PMU: +		snd_soc_update_bits(codec, CDC_A_SPKR_DRV_CTL, +				    SPKR_DRV_CTL_DEF_MASK, +				    SPKR_DRV_CTL_DEF_VAL); +		snd_soc_update_bits(codec, w->reg, +				    SPKR_DRV_CLASSD_PA_EN_MASK, +				    SPKR_DRV_CLASSD_PA_EN_ENABLE); +		break; +	case SND_SOC_DAPM_POST_PMD: +		snd_soc_update_bits(codec, CDC_A_SPKR_PWRSTG_CTL, +				    SPKR_PWRSTG_CTL_DAC_EN_MASK| +				    SPKR_PWRSTG_CTL_BBM_MASK | +				    SPKR_PWRSTG_CTL_HBRDGE_EN_MASK | +				    SPKR_PWRSTG_CTL_CLAMP_EN_MASK, 0); + +		snd_soc_update_bits(codec, CDC_A_SPKR_DAC_CTL, +				    SPKR_DAC_CTL_DAC_RESET_MASK, +				    SPKR_DAC_CTL_DAC_RESET_NORMAL); +		snd_soc_update_bits(codec, CDC_A_RX_EAR_CTL, +				    RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK, 0); +		break; +	} +	return 0; +} + +static const struct reg_default wcd_reg_defaults_2_0[] = { +	{CDC_A_RX_COM_OCP_CTL, 0xD1}, +	{CDC_A_RX_COM_OCP_COUNT, 0xFF}, +	{CDC_D_SEC_ACCESS, 0xA5}, +	{CDC_D_PERPH_RESET_CTL3, 0x0F}, +	{CDC_A_TX_1_2_OPAMP_BIAS, 0x4F}, +	{CDC_A_NCP_FBCTRL, 0x28}, +	{CDC_A_SPKR_DRV_CTL, 0x69}, +	{CDC_A_SPKR_DRV_DBG, 0x01}, +	{CDC_A_BOOST_EN_CTL, 0x5F}, +	{CDC_A_SLOPE_COMP_IP_ZERO, 0x88}, +	{CDC_A_SEC_ACCESS, 0xA5}, +	{CDC_A_PERPH_RESET_CTL3, 0x0F}, +	{CDC_A_CURRENT_LIMIT, 0x82}, +	{CDC_A_SPKR_DAC_CTL, 0x03}, +	{CDC_A_SPKR_OCP_CTL, 0xE1}, +	{CDC_A_MASTER_BIAS_CTL, 0x30}, +}; + +static int pm8916_wcd_analog_probe(struct snd_soc_codec *codec) +{ +	struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(codec->dev); +	int err, reg; + +	err = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); +	if (err != 0) { +		dev_err(codec->dev, "failed to enable regulators (%d)\n", err); +		return err; +	} + +	snd_soc_codec_set_drvdata(codec, priv); +	priv->pmic_rev = snd_soc_read(codec, CDC_D_REVISION1); +	priv->codec_version = snd_soc_read(codec, CDC_D_PERPH_SUBTYPE); + +	dev_info(codec->dev, "PMIC REV: %d\t CODEC Version: %d\n", +		 priv->pmic_rev, priv->codec_version); + +	snd_soc_write(codec, CDC_D_PERPH_RESET_CTL4, 0x01); +	snd_soc_write(codec, CDC_A_PERPH_RESET_CTL4, 0x01); + +	for (reg = 0; reg < ARRAY_SIZE(wcd_reg_defaults_2_0); reg++) +		snd_soc_write(codec, wcd_reg_defaults_2_0[reg].reg, +			      wcd_reg_defaults_2_0[reg].def); + +	return 0; +} + +static int pm8916_wcd_analog_remove(struct snd_soc_codec *codec) +{ +	struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(codec->dev); + +	return regulator_bulk_disable(ARRAY_SIZE(priv->supplies), +				      priv->supplies); +} + +static const struct snd_soc_dapm_route pm8916_wcd_analog_audio_map[] = { + +	{"PDM_RX1", NULL, "PDM Playback"}, +	{"PDM_RX2", NULL, "PDM Playback"}, +	{"PDM_RX3", NULL, "PDM Playback"}, +	{"PDM Capture", NULL, "PDM_TX"}, + +	/* ADC Connections */ +	{"PDM_TX", NULL, "ADC2"}, +	{"PDM_TX", NULL, "ADC3"}, +	{"ADC2", NULL, "ADC2 MUX"}, +	{"ADC3", NULL, "ADC2 MUX"}, +	{"ADC2 MUX", "INP2", "ADC2_INP2"}, +	{"ADC2 MUX", "INP3", "ADC2_INP3"}, + +	{"PDM_TX", NULL, "ADC1"}, +	{"ADC1", NULL, "AMIC1"}, +	{"ADC2_INP2", NULL, "AMIC2"}, +	{"ADC2_INP3", NULL, "AMIC3"}, + +	/* RDAC Connections */ +	{"HPHR DAC", NULL, "RDAC2 MUX"}, +	{"RDAC2 MUX", "RX1", "PDM_RX1"}, +	{"RDAC2 MUX", "RX2", "PDM_RX2"}, +	{"HPHL DAC", NULL, "PDM_RX1"}, +	{"PDM_RX1", NULL, "RXD1_CLK"}, +	{"PDM_RX2", NULL, "RXD2_CLK"}, +	{"PDM_RX3", NULL, "RXD3_CLK"}, + +	{"PDM_RX1", NULL, "RXD_PDM_CLK"}, +	{"PDM_RX2", NULL, "RXD_PDM_CLK"}, +	{"PDM_RX3", NULL, "RXD_PDM_CLK"}, + +	{"ADC1", NULL, "TXD_CLK"}, +	{"ADC2", NULL, "TXD_CLK"}, +	{"ADC3", NULL, "TXD_CLK"}, + +	{"ADC1", NULL, "TXA_CLK25"}, +	{"ADC2", NULL, "TXA_CLK25"}, +	{"ADC3", NULL, "TXA_CLK25"}, + +	{"PDM_RX1", NULL, "A_MCLK2"}, +	{"PDM_RX2", NULL, "A_MCLK2"}, +	{"PDM_RX3", NULL, "A_MCLK2"}, + +	{"PDM_TX", NULL, "A_MCLK2"}, +	{"A_MCLK2", NULL, "A_MCLK"}, + +	/* Headset (RX MIX1 and RX MIX2) */ +	{"HEADPHONE", NULL, "HPHL PA"}, +	{"HEADPHONE", NULL, "HPHR PA"}, + +	{"HPHL PA", NULL, "EAR_HPHL_CLK"}, +	{"HPHR PA", NULL, "EAR_HPHR_CLK"}, + +	{"CP", NULL, "NCP_CLK"}, + +	{"HPHL PA", NULL, "HPHL"}, +	{"HPHR PA", NULL, "HPHR"}, +	{"HPHL PA", NULL, "CP"}, +	{"HPHL PA", NULL, "RX_BIAS"}, +	{"HPHR PA", NULL, "CP"}, +	{"HPHR PA", NULL, "RX_BIAS"}, +	{"HPHL", "Switch", "HPHL DAC"}, +	{"HPHR", "Switch", "HPHR DAC"}, + +	{"RX_BIAS", NULL, "DAC_REF"}, + +	{"SPK_OUT", NULL, "SPK PA"}, +	{"SPK PA", NULL, "RX_BIAS"}, +	{"SPK PA", NULL, "SPKR_CLK"}, +	{"SPK PA", NULL, "SPK DAC"}, +	{"SPK DAC", "Switch", "PDM_RX3"}, + +	{"MIC BIAS Internal1", NULL, "INT_LDO_H"}, +	{"MIC BIAS Internal2", NULL, "INT_LDO_H"}, +	{"MIC BIAS External1", NULL, "INT_LDO_H"}, +	{"MIC BIAS External2", NULL, "INT_LDO_H"}, +	{"MIC BIAS Internal1", NULL, "vdd-micbias"}, +	{"MIC BIAS Internal2", NULL, "vdd-micbias"}, +	{"MIC BIAS External1", NULL, "vdd-micbias"}, +	{"MIC BIAS External2", NULL, "vdd-micbias"}, +}; + +static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = { + +	SND_SOC_DAPM_AIF_IN("PDM_RX1", NULL, 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_IN("PDM_RX2", NULL, 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_IN("PDM_RX3", NULL, 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("PDM_TX", NULL, 0, SND_SOC_NOPM, 0, 0), + +	SND_SOC_DAPM_INPUT("AMIC1"), +	SND_SOC_DAPM_INPUT("AMIC3"), +	SND_SOC_DAPM_INPUT("AMIC2"), +	SND_SOC_DAPM_OUTPUT("HEADPHONE"), + +	/* RX stuff */ +	SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0), + +	SND_SOC_DAPM_PGA("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0), +	SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, &hphl_mux), +	SND_SOC_DAPM_MIXER("HPHL DAC", CDC_A_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL, +			   0), +	SND_SOC_DAPM_PGA("HPHR PA", CDC_A_RX_HPH_CNP_EN, 4, 0, NULL, 0), +	SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0, &hphr_mux), +	SND_SOC_DAPM_MIXER("HPHR DAC", CDC_A_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL, +			   0), +	SND_SOC_DAPM_MIXER("SPK DAC", SND_SOC_NOPM, 0, 0, +			   spkr_switch, ARRAY_SIZE(spkr_switch)), + +	/* Speaker */ +	SND_SOC_DAPM_OUTPUT("SPK_OUT"), +	SND_SOC_DAPM_PGA_E("SPK PA", CDC_A_SPKR_DRV_CTL, +			   6, 0, NULL, 0, +			   pm8916_wcd_analog_enable_spk_pa, +			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | +			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_REGULATOR_SUPPLY("vdd-micbias", 0, 0), +	SND_SOC_DAPM_SUPPLY("CP", CDC_A_NCP_EN, 0, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("DAC_REF", CDC_A_RX_COM_BIAS_DAC, 0, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("RX_BIAS", CDC_A_RX_COM_BIAS_DAC, 7, 0, NULL, 0), + +	/* TX */ +	SND_SOC_DAPM_SUPPLY("MIC BIAS Internal1", CDC_A_MICB_1_EN, 7, 0, +			    pm8916_wcd_analog_enable_micbias_int1, +			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | +			    SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_SUPPLY("MIC BIAS Internal2", CDC_A_MICB_2_EN, 7, 0, +			    pm8916_wcd_analog_enable_micbias_int2, +			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | +			    SND_SOC_DAPM_POST_PMD), + +	SND_SOC_DAPM_SUPPLY("MIC BIAS External1", CDC_A_MICB_1_EN, 7, 0, +			    pm8916_wcd_analog_enable_micbias_ext1, +			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_SUPPLY("MIC BIAS External2", CDC_A_MICB_2_EN, 7, 0, +			    pm8916_wcd_analog_enable_micbias_ext2, +			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + +	SND_SOC_DAPM_ADC_E("ADC1", NULL, CDC_A_TX_1_EN, 7, 0, +			   pm8916_wcd_analog_enable_adc, +			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | +			   SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_ADC_E("ADC2_INP2", NULL, CDC_A_TX_2_EN, 7, 0, +			   pm8916_wcd_analog_enable_adc, +			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | +			   SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_ADC_E("ADC2_INP3", NULL, CDC_A_TX_3_EN, 7, 0, +			   pm8916_wcd_analog_enable_adc, +			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | +			   SND_SOC_DAPM_POST_PMD), + +	SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), + +	SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux), +	SND_SOC_DAPM_MUX("RDAC2 MUX", SND_SOC_NOPM, 0, 0, &rdac2_mux), + +	/* Analog path clocks */ +	SND_SOC_DAPM_SUPPLY("EAR_HPHR_CLK", CDC_D_CDC_ANA_CLK_CTL, 0, 0, NULL, +			    0), +	SND_SOC_DAPM_SUPPLY("EAR_HPHL_CLK", CDC_D_CDC_ANA_CLK_CTL, 1, 0, NULL, +			    0), +	SND_SOC_DAPM_SUPPLY("SPKR_CLK", CDC_D_CDC_ANA_CLK_CTL, 4, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("TXA_CLK25", CDC_D_CDC_ANA_CLK_CTL, 5, 0, NULL, 0), + +	/* Digital path clocks */ + +	SND_SOC_DAPM_SUPPLY("RXD1_CLK", CDC_D_CDC_DIG_CLK_CTL, 0, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("RXD2_CLK", CDC_D_CDC_DIG_CLK_CTL, 1, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("RXD3_CLK", CDC_D_CDC_DIG_CLK_CTL, 2, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("TXD_CLK", CDC_D_CDC_DIG_CLK_CTL, 4, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("NCP_CLK", CDC_D_CDC_DIG_CLK_CTL, 6, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("RXD_PDM_CLK", CDC_D_CDC_DIG_CLK_CTL, 7, 0, NULL, +			    0), + +	/* System Clock source */ +	SND_SOC_DAPM_SUPPLY("A_MCLK", CDC_D_CDC_TOP_CLK_CTL, 2, 0, NULL, 0), +	/* TX ADC and RX DAC Clock source. */ +	SND_SOC_DAPM_SUPPLY("A_MCLK2", CDC_D_CDC_TOP_CLK_CTL, 3, 0, NULL, 0), +}; + +static struct regmap *pm8916_get_regmap(struct device *dev) +{ +	return dev_get_regmap(dev->parent, NULL); +} + +static int pm8916_wcd_analog_startup(struct snd_pcm_substream *substream, +				      struct snd_soc_dai *dai) +{ +	snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL, +			    RST_CTL_DIG_SW_RST_N_MASK, +			    RST_CTL_DIG_SW_RST_N_REMOVE_RESET); + +	return 0; +} + +static void pm8916_wcd_analog_shutdown(struct snd_pcm_substream *substream, +					 struct snd_soc_dai *dai) +{ +	snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL, +			    RST_CTL_DIG_SW_RST_N_MASK, 0); +} + +static struct snd_soc_dai_ops pm8916_wcd_analog_dai_ops = { +	.startup = pm8916_wcd_analog_startup, +	.shutdown = pm8916_wcd_analog_shutdown, +}; + +static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = { +	[0] = { +	       .name = "pm8916_wcd_analog_pdm_rx", +	       .id = 0, +	       .playback = { +			    .stream_name = "PDM Playback", +			    .rates = MSM8916_WCD_ANALOG_RATES, +			    .formats = MSM8916_WCD_ANALOG_FORMATS, +			    .channels_min = 1, +			    .channels_max = 3, +			    }, +	       .ops = &pm8916_wcd_analog_dai_ops, +	       }, +	[1] = { +	       .name = "pm8916_wcd_analog_pdm_tx", +	       .id = 1, +	       .capture = { +			   .stream_name = "PDM Capture", +			   .rates = MSM8916_WCD_ANALOG_RATES, +			   .formats = MSM8916_WCD_ANALOG_FORMATS, +			   .channels_min = 1, +			   .channels_max = 4, +			   }, +	       .ops = &pm8916_wcd_analog_dai_ops, +	       }, +}; + +static struct snd_soc_codec_driver pm8916_wcd_analog = { +	.probe = pm8916_wcd_analog_probe, +	.remove = pm8916_wcd_analog_remove, +	.get_regmap = pm8916_get_regmap, +	.component_driver = { +		.controls = pm8916_wcd_analog_snd_controls, +		.num_controls = ARRAY_SIZE(pm8916_wcd_analog_snd_controls), +		.dapm_widgets = pm8916_wcd_analog_dapm_widgets, +		.num_dapm_widgets = ARRAY_SIZE(pm8916_wcd_analog_dapm_widgets), +		.dapm_routes = pm8916_wcd_analog_audio_map, +		.num_dapm_routes = ARRAY_SIZE(pm8916_wcd_analog_audio_map), +	}, +}; + +static int pm8916_wcd_analog_parse_dt(struct device *dev, +				       struct pm8916_wcd_analog_priv *priv) +{ + +	if (of_property_read_bool(dev->of_node, "qcom,micbias1-ext-cap")) +		priv->micbias1_cap_mode = MICB_1_EN_EXT_BYP_CAP; +	else +		priv->micbias1_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP; + +	if (of_property_read_bool(dev->of_node, "qcom,micbias2-ext-cap")) +		priv->micbias2_cap_mode = MICB_1_EN_EXT_BYP_CAP; +	else +		priv->micbias2_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP; + +	return 0; +} + +static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) +{ +	struct pm8916_wcd_analog_priv *priv; +	struct device *dev = &pdev->dev; +	int ret, i; + +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	ret = pm8916_wcd_analog_parse_dt(dev, priv); +	if (ret < 0) +		return ret; + +	priv->mclk = devm_clk_get(dev, "mclk"); +	if (IS_ERR(priv->mclk)) { +		dev_err(dev, "failed to get mclk\n"); +		return PTR_ERR(priv->mclk); +	} + +	for (i = 0; i < ARRAY_SIZE(supply_names); i++) +		priv->supplies[i].supply = supply_names[i]; + +	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies), +				    priv->supplies); +	if (ret) { +		dev_err(dev, "Failed to get regulator supplies %d\n", ret); +		return ret; +	} + +	ret = clk_prepare_enable(priv->mclk); +	if (ret < 0) { +		dev_err(dev, "failed to enable mclk %d\n", ret); +		return ret; +	} + +	dev_set_drvdata(dev, priv); + +	return snd_soc_register_codec(dev, &pm8916_wcd_analog, +				      pm8916_wcd_analog_dai, +				      ARRAY_SIZE(pm8916_wcd_analog_dai)); +} + +static int pm8916_wcd_analog_spmi_remove(struct platform_device *pdev) +{ +	struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(&pdev->dev); + +	snd_soc_unregister_codec(&pdev->dev); +	clk_disable_unprepare(priv->mclk); + +	return 0; +} + +static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = { +	{ .compatible = "qcom,pm8916-wcd-analog-codec", }, +	{ } +}; + +static struct platform_driver pm8916_wcd_analog_spmi_driver = { +	.driver = { +		   .name = "qcom,pm8916-wcd-spmi-codec", +		   .of_match_table = pm8916_wcd_analog_spmi_match_table, +	}, +	.probe = pm8916_wcd_analog_spmi_probe, +	.remove = pm8916_wcd_analog_spmi_remove, +}; + +module_platform_driver(pm8916_wcd_analog_spmi_driver); + +MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>"); +MODULE_DESCRIPTION("PMIC PM8916 WCD Analog Codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c new file mode 100644 index 000000000000..f690442af8c9 --- /dev/null +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -0,0 +1,923 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/types.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> +#include <sound/soc.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/tlv.h> + +#define LPASS_CDC_CLK_RX_RESET_CTL		(0x000) +#define LPASS_CDC_CLK_TX_RESET_B1_CTL		(0x004) +#define CLK_RX_RESET_B1_CTL_TX1_RESET_MASK	BIT(0) +#define CLK_RX_RESET_B1_CTL_TX2_RESET_MASK	BIT(1) +#define LPASS_CDC_CLK_DMIC_B1_CTL		(0x008) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_MASK		GENMASK(3, 1) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV2		(0x0 << 1) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3		(0x1 << 1) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV4		(0x2 << 1) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV6		(0x3 << 1) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV16		(0x4 << 1) +#define DMIC_B1_CTL_DMIC0_CLK_EN_MASK		BIT(0) +#define DMIC_B1_CTL_DMIC0_CLK_EN_ENABLE		BIT(0) + +#define LPASS_CDC_CLK_RX_I2S_CTL		(0x00C) +#define RX_I2S_CTL_RX_I2S_MODE_MASK		BIT(5) +#define RX_I2S_CTL_RX_I2S_MODE_16		BIT(5) +#define RX_I2S_CTL_RX_I2S_MODE_32		0 +#define RX_I2S_CTL_RX_I2S_FS_RATE_MASK		GENMASK(2, 0) +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_8_KHZ	0x0 +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_16_KHZ	0x1 +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_32_KHZ	0x2 +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_48_KHZ	0x3 +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_96_KHZ	0x4 +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_192_KHZ	0x5 +#define LPASS_CDC_CLK_TX_I2S_CTL		(0x010) +#define TX_I2S_CTL_TX_I2S_MODE_MASK		BIT(5) +#define TX_I2S_CTL_TX_I2S_MODE_16		BIT(5) +#define TX_I2S_CTL_TX_I2S_MODE_32		0 +#define TX_I2S_CTL_TX_I2S_FS_RATE_MASK		GENMASK(2, 0) +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_8_KHZ	0x0 +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_16_KHZ	0x1 +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_32_KHZ	0x2 +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_48_KHZ	0x3 +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_96_KHZ	0x4 +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_192_KHZ	0x5 + +#define LPASS_CDC_CLK_OTHR_RESET_B1_CTL		(0x014) +#define LPASS_CDC_CLK_TX_CLK_EN_B1_CTL		(0x018) +#define LPASS_CDC_CLK_OTHR_CTL			(0x01C) +#define LPASS_CDC_CLK_RX_B1_CTL			(0x020) +#define LPASS_CDC_CLK_MCLK_CTL			(0x024) +#define MCLK_CTL_MCLK_EN_MASK			BIT(0) +#define MCLK_CTL_MCLK_EN_ENABLE			BIT(0) +#define MCLK_CTL_MCLK_EN_DISABLE		0 +#define LPASS_CDC_CLK_PDM_CTL			(0x028) +#define LPASS_CDC_CLK_PDM_CTL_PDM_EN_MASK	BIT(0) +#define LPASS_CDC_CLK_PDM_CTL_PDM_EN		BIT(0) +#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK	BIT(1) +#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB	BIT(1) +#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_PDM_CLK	0 + +#define LPASS_CDC_CLK_SD_CTL			(0x02C) +#define LPASS_CDC_RX1_B1_CTL			(0x040) +#define LPASS_CDC_RX2_B1_CTL			(0x060) +#define LPASS_CDC_RX3_B1_CTL			(0x080) +#define LPASS_CDC_RX1_B2_CTL			(0x044) +#define LPASS_CDC_RX2_B2_CTL			(0x064) +#define LPASS_CDC_RX3_B2_CTL			(0x084) +#define LPASS_CDC_RX1_B3_CTL			(0x048) +#define LPASS_CDC_RX2_B3_CTL			(0x068) +#define LPASS_CDC_RX3_B3_CTL			(0x088) +#define LPASS_CDC_RX1_B4_CTL			(0x04C) +#define LPASS_CDC_RX2_B4_CTL			(0x06C) +#define LPASS_CDC_RX3_B4_CTL			(0x08C) +#define LPASS_CDC_RX1_B5_CTL			(0x050) +#define LPASS_CDC_RX2_B5_CTL			(0x070) +#define LPASS_CDC_RX3_B5_CTL			(0x090) +#define LPASS_CDC_RX1_B6_CTL			(0x054) +#define RXn_B6_CTL_MUTE_MASK			BIT(0) +#define RXn_B6_CTL_MUTE_ENABLE			BIT(0) +#define RXn_B6_CTL_MUTE_DISABLE			0 +#define LPASS_CDC_RX2_B6_CTL			(0x074) +#define LPASS_CDC_RX3_B6_CTL			(0x094) +#define LPASS_CDC_RX1_VOL_CTL_B1_CTL		(0x058) +#define LPASS_CDC_RX2_VOL_CTL_B1_CTL		(0x078) +#define LPASS_CDC_RX3_VOL_CTL_B1_CTL		(0x098) +#define LPASS_CDC_RX1_VOL_CTL_B2_CTL		(0x05C) +#define LPASS_CDC_RX2_VOL_CTL_B2_CTL		(0x07C) +#define LPASS_CDC_RX3_VOL_CTL_B2_CTL		(0x09C) +#define LPASS_CDC_TOP_GAIN_UPDATE		(0x0A0) +#define LPASS_CDC_TOP_CTL			(0x0A4) +#define TOP_CTL_DIG_MCLK_FREQ_MASK		BIT(0) +#define TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ	0 +#define TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ		BIT(0) + +#define LPASS_CDC_DEBUG_DESER1_CTL		(0x0E0) +#define LPASS_CDC_DEBUG_DESER2_CTL		(0x0E4) +#define LPASS_CDC_DEBUG_B1_CTL_CFG		(0x0E8) +#define LPASS_CDC_DEBUG_B2_CTL_CFG		(0x0EC) +#define LPASS_CDC_DEBUG_B3_CTL_CFG		(0x0F0) +#define LPASS_CDC_IIR1_GAIN_B1_CTL		(0x100) +#define LPASS_CDC_IIR2_GAIN_B1_CTL		(0x140) +#define LPASS_CDC_IIR1_GAIN_B2_CTL		(0x104) +#define LPASS_CDC_IIR2_GAIN_B2_CTL		(0x144) +#define LPASS_CDC_IIR1_GAIN_B3_CTL		(0x108) +#define LPASS_CDC_IIR2_GAIN_B3_CTL		(0x148) +#define LPASS_CDC_IIR1_GAIN_B4_CTL		(0x10C) +#define LPASS_CDC_IIR2_GAIN_B4_CTL		(0x14C) +#define LPASS_CDC_IIR1_GAIN_B5_CTL		(0x110) +#define LPASS_CDC_IIR2_GAIN_B5_CTL		(0x150) +#define LPASS_CDC_IIR1_GAIN_B6_CTL		(0x114) +#define LPASS_CDC_IIR2_GAIN_B6_CTL		(0x154) +#define LPASS_CDC_IIR1_GAIN_B7_CTL		(0x118) +#define LPASS_CDC_IIR2_GAIN_B7_CTL		(0x158) +#define LPASS_CDC_IIR1_GAIN_B8_CTL		(0x11C) +#define LPASS_CDC_IIR2_GAIN_B8_CTL		(0x15C) +#define LPASS_CDC_IIR1_CTL			(0x120) +#define LPASS_CDC_IIR2_CTL			(0x160) +#define LPASS_CDC_IIR1_GAIN_TIMER_CTL		(0x124) +#define LPASS_CDC_IIR2_GAIN_TIMER_CTL		(0x164) +#define LPASS_CDC_IIR1_COEF_B1_CTL		(0x128) +#define LPASS_CDC_IIR2_COEF_B1_CTL		(0x168) +#define LPASS_CDC_IIR1_COEF_B2_CTL		(0x12C) +#define LPASS_CDC_IIR2_COEF_B2_CTL		(0x16C) +#define LPASS_CDC_CONN_RX1_B1_CTL		(0x180) +#define LPASS_CDC_CONN_RX1_B2_CTL		(0x184) +#define LPASS_CDC_CONN_RX1_B3_CTL		(0x188) +#define LPASS_CDC_CONN_RX2_B1_CTL		(0x18C) +#define LPASS_CDC_CONN_RX2_B2_CTL		(0x190) +#define LPASS_CDC_CONN_RX2_B3_CTL		(0x194) +#define LPASS_CDC_CONN_RX3_B1_CTL		(0x198) +#define LPASS_CDC_CONN_RX3_B2_CTL		(0x19C) +#define LPASS_CDC_CONN_TX_B1_CTL		(0x1A0) +#define LPASS_CDC_CONN_EQ1_B1_CTL		(0x1A8) +#define LPASS_CDC_CONN_EQ1_B2_CTL		(0x1AC) +#define LPASS_CDC_CONN_EQ1_B3_CTL		(0x1B0) +#define LPASS_CDC_CONN_EQ1_B4_CTL		(0x1B4) +#define LPASS_CDC_CONN_EQ2_B1_CTL		(0x1B8) +#define LPASS_CDC_CONN_EQ2_B2_CTL		(0x1BC) +#define LPASS_CDC_CONN_EQ2_B3_CTL		(0x1C0) +#define LPASS_CDC_CONN_EQ2_B4_CTL		(0x1C4) +#define LPASS_CDC_CONN_TX_I2S_SD1_CTL		(0x1C8) +#define LPASS_CDC_TX1_VOL_CTL_TIMER		(0x280) +#define LPASS_CDC_TX2_VOL_CTL_TIMER		(0x2A0) +#define LPASS_CDC_TX1_VOL_CTL_GAIN		(0x284) +#define LPASS_CDC_TX2_VOL_CTL_GAIN		(0x2A4) +#define LPASS_CDC_TX1_VOL_CTL_CFG		(0x288) +#define TX_VOL_CTL_CFG_MUTE_EN_MASK		BIT(0) +#define TX_VOL_CTL_CFG_MUTE_EN_ENABLE		BIT(0) + +#define LPASS_CDC_TX2_VOL_CTL_CFG		(0x2A8) +#define LPASS_CDC_TX1_MUX_CTL			(0x28C) +#define TX_MUX_CTL_CUT_OFF_FREQ_MASK		GENMASK(5, 4) +#define TX_MUX_CTL_CUT_OFF_FREQ_SHIFT		4 +#define TX_MUX_CTL_CF_NEG_3DB_4HZ		(0x0 << 4) +#define TX_MUX_CTL_CF_NEG_3DB_75HZ		(0x1 << 4) +#define TX_MUX_CTL_CF_NEG_3DB_150HZ		(0x2 << 4) +#define TX_MUX_CTL_HPF_BP_SEL_MASK		BIT(3) +#define TX_MUX_CTL_HPF_BP_SEL_BYPASS		BIT(3) +#define TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS		0 + +#define LPASS_CDC_TX2_MUX_CTL			(0x2AC) +#define LPASS_CDC_TX1_CLK_FS_CTL		(0x290) +#define LPASS_CDC_TX2_CLK_FS_CTL		(0x2B0) +#define LPASS_CDC_TX1_DMIC_CTL			(0x294) +#define LPASS_CDC_TX2_DMIC_CTL			(0x2B4) +#define TXN_DMIC_CTL_CLK_SEL_MASK		GENMASK(2, 0) +#define TXN_DMIC_CTL_CLK_SEL_DIV2		0x0 +#define TXN_DMIC_CTL_CLK_SEL_DIV3		0x1 +#define TXN_DMIC_CTL_CLK_SEL_DIV4		0x2 +#define TXN_DMIC_CTL_CLK_SEL_DIV6		0x3 +#define TXN_DMIC_CTL_CLK_SEL_DIV16		0x4 + +#define MSM8916_WCD_DIGITAL_RATES (SNDRV_PCM_RATE_8000 | \ +				   SNDRV_PCM_RATE_16000 | \ +				   SNDRV_PCM_RATE_32000 | \ +				   SNDRV_PCM_RATE_48000) +#define MSM8916_WCD_DIGITAL_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ +				     SNDRV_PCM_FMTBIT_S24_LE) + +struct msm8916_wcd_digital_priv { +	struct clk *ahbclk, *mclk; +}; + +static const unsigned long rx_gain_reg[] = { +	LPASS_CDC_RX1_VOL_CTL_B2_CTL, +	LPASS_CDC_RX2_VOL_CTL_B2_CTL, +	LPASS_CDC_RX3_VOL_CTL_B2_CTL, +}; + +static const unsigned long tx_gain_reg[] = { +	LPASS_CDC_TX1_VOL_CTL_GAIN, +	LPASS_CDC_TX2_VOL_CTL_GAIN, +}; + +static const char *const rx_mix1_text[] = { +	"ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3" +}; + +static const char *const dec_mux_text[] = { +	"ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2" +}; +static const char *const rx_mix2_text[] = { "ZERO", "IIR1", "IIR2" }; +static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" }; + +/* RX1 MIX1 */ +static const struct soc_enum rx_mix1_inp_enum[] = { +	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text), +	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B1_CTL, 3, 6, rx_mix1_text), +	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text), +}; + +/* RX1 MIX2 */ +static const struct soc_enum rx_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( +				LPASS_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text); + +/* RX2 MIX1 */ +static const struct soc_enum rx2_mix1_inp_enum[] = { +	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text), +	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text), +	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text), +}; + +/* RX2 MIX2 */ +static const struct soc_enum rx2_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( +				LPASS_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text); + +/* RX3 MIX1 */ +static const struct soc_enum rx3_mix1_inp_enum[] = { +	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text), +	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text), +	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text), +}; + +/* DEC */ +static const struct soc_enum dec1_mux_enum = SOC_ENUM_SINGLE( +				LPASS_CDC_CONN_TX_B1_CTL, 0, 6, dec_mux_text); +static const struct soc_enum dec2_mux_enum = SOC_ENUM_SINGLE( +				LPASS_CDC_CONN_TX_B1_CTL, 3, 6, dec_mux_text); + +/* RDAC2 MUX */ +static const struct snd_kcontrol_new dec1_mux = SOC_DAPM_ENUM( +				"DEC1 MUX Mux", dec1_mux_enum); +static const struct snd_kcontrol_new dec2_mux = SOC_DAPM_ENUM( +				"DEC2 MUX Mux",	dec2_mux_enum); +static const struct snd_kcontrol_new rx_mix1_inp1_mux = SOC_DAPM_ENUM( +				"RX1 MIX1 INP1 Mux", rx_mix1_inp_enum[0]); +static const struct snd_kcontrol_new rx_mix1_inp2_mux = SOC_DAPM_ENUM( +				"RX1 MIX1 INP2 Mux", rx_mix1_inp_enum[1]); +static const struct snd_kcontrol_new rx_mix1_inp3_mux = SOC_DAPM_ENUM( +				"RX1 MIX1 INP3 Mux", rx_mix1_inp_enum[2]); +static const struct snd_kcontrol_new rx2_mix1_inp1_mux = SOC_DAPM_ENUM( +				"RX2 MIX1 INP1 Mux", rx2_mix1_inp_enum[0]); +static const struct snd_kcontrol_new rx2_mix1_inp2_mux = SOC_DAPM_ENUM( +				"RX2 MIX1 INP2 Mux", rx2_mix1_inp_enum[1]); +static const struct snd_kcontrol_new rx2_mix1_inp3_mux = SOC_DAPM_ENUM( +				"RX2 MIX1 INP3 Mux", rx2_mix1_inp_enum[2]); +static const struct snd_kcontrol_new rx3_mix1_inp1_mux = SOC_DAPM_ENUM( +				"RX3 MIX1 INP1 Mux", rx3_mix1_inp_enum[0]); +static const struct snd_kcontrol_new rx3_mix1_inp2_mux = SOC_DAPM_ENUM( +				"RX3 MIX1 INP2 Mux", rx3_mix1_inp_enum[1]); +static const struct snd_kcontrol_new rx3_mix1_inp3_mux = SOC_DAPM_ENUM( +				"RX3 MIX1 INP3 Mux", rx3_mix1_inp_enum[2]); + +/* Digital Gain control -38.4 dB to +38.4 dB in 0.3 dB steps */ +static const DECLARE_TLV_DB_SCALE(digital_gain, -3840, 30, 0); + +/* Cutoff Freq for High Pass Filter at -3dB */ +static const char * const hpf_cutoff_text[] = { +	"4Hz", "75Hz", "150Hz", +}; + +static SOC_ENUM_SINGLE_DECL(tx1_hpf_cutoff_enum, LPASS_CDC_TX1_MUX_CTL, 4, +			    hpf_cutoff_text); +static SOC_ENUM_SINGLE_DECL(tx2_hpf_cutoff_enum, LPASS_CDC_TX2_MUX_CTL, 4, +			    hpf_cutoff_text); + +/* cut off for dc blocker inside rx chain */ +static const char * const dc_blocker_cutoff_text[] = { +	"4Hz", "75Hz", "150Hz", +}; + +static SOC_ENUM_SINGLE_DECL(rx1_dcb_cutoff_enum, LPASS_CDC_RX1_B4_CTL, 0, +			    dc_blocker_cutoff_text); +static SOC_ENUM_SINGLE_DECL(rx2_dcb_cutoff_enum, LPASS_CDC_RX2_B4_CTL, 0, +			    dc_blocker_cutoff_text); +static SOC_ENUM_SINGLE_DECL(rx3_dcb_cutoff_enum, LPASS_CDC_RX3_B4_CTL, 0, +			    dc_blocker_cutoff_text); + +static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = { +	SOC_SINGLE_S8_TLV("RX1 Digital Volume", LPASS_CDC_RX1_VOL_CTL_B2_CTL, +			  -128, 127, digital_gain), +	SOC_SINGLE_S8_TLV("RX2 Digital Volume", LPASS_CDC_RX2_VOL_CTL_B2_CTL, +			  -128, 127, digital_gain), +	SOC_SINGLE_S8_TLV("RX3 Digital Volume", LPASS_CDC_RX3_VOL_CTL_B2_CTL, +			  -128, 127, digital_gain), +	SOC_SINGLE_S8_TLV("TX1 Digital Volume", LPASS_CDC_TX1_VOL_CTL_GAIN, +			  -128, 127, digital_gain), +	SOC_SINGLE_S8_TLV("TX2 Digital Volume", LPASS_CDC_TX2_VOL_CTL_GAIN, +			  -128, 127, digital_gain), +	SOC_ENUM("TX1 HPF Cutoff", tx1_hpf_cutoff_enum), +	SOC_ENUM("TX2 HPF Cutoff", tx2_hpf_cutoff_enum), +	SOC_SINGLE("TX1 HPF Switch", LPASS_CDC_TX1_MUX_CTL, 3, 1, 0), +	SOC_SINGLE("TX2 HPF Switch", LPASS_CDC_TX2_MUX_CTL, 3, 1, 0), +	SOC_ENUM("RX1 DCB Cutoff", rx1_dcb_cutoff_enum), +	SOC_ENUM("RX2 DCB Cutoff", rx2_dcb_cutoff_enum), +	SOC_ENUM("RX3 DCB Cutoff", rx3_dcb_cutoff_enum), +	SOC_SINGLE("RX1 DCB Switch", LPASS_CDC_RX1_B5_CTL, 2, 1, 0), +	SOC_SINGLE("RX2 DCB Switch", LPASS_CDC_RX2_B5_CTL, 2, 1, 0), +	SOC_SINGLE("RX3 DCB Switch", LPASS_CDC_RX3_B5_CTL, 2, 1, 0), +	SOC_SINGLE("RX1 Mute Switch", LPASS_CDC_RX1_B6_CTL, 0, 1, 0), +	SOC_SINGLE("RX2 Mute Switch", LPASS_CDC_RX2_B6_CTL, 0, 1, 0), +	SOC_SINGLE("RX3 Mute Switch", LPASS_CDC_RX3_B6_CTL, 0, 1, 0), +}; + +static int msm8916_wcd_digital_enable_interpolator( +						struct snd_soc_dapm_widget *w, +						struct snd_kcontrol *kcontrol, +						int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		/* apply the digital gain after the interpolator is enabled */ +		usleep_range(10000, 10100); +		snd_soc_write(codec, rx_gain_reg[w->shift], +			      snd_soc_read(codec, rx_gain_reg[w->shift])); +		break; +	} +	return 0; +} + +static int msm8916_wcd_digital_enable_dec(struct snd_soc_dapm_widget *w, +					  struct snd_kcontrol *kcontrol, +					  int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); +	unsigned int decimator = w->shift + 1; +	u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg; +	u8 dec_hpf_cut_of_freq; + +	dec_reset_reg = LPASS_CDC_CLK_TX_RESET_B1_CTL; +	tx_vol_ctl_reg = LPASS_CDC_TX1_VOL_CTL_CFG + 32 * (decimator - 1); +	tx_mux_ctl_reg = LPASS_CDC_TX1_MUX_CTL + 32 * (decimator - 1); + +	switch (event) { +	case SND_SOC_DAPM_PRE_PMU: +		/* Enable TX digital mute */ +		snd_soc_update_bits(codec, tx_vol_ctl_reg, +				    TX_VOL_CTL_CFG_MUTE_EN_MASK, +				    TX_VOL_CTL_CFG_MUTE_EN_ENABLE); +		dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg) & +					TX_MUX_CTL_CUT_OFF_FREQ_MASK; +		dec_hpf_cut_of_freq >>= TX_MUX_CTL_CUT_OFF_FREQ_SHIFT; +		if (dec_hpf_cut_of_freq != TX_MUX_CTL_CF_NEG_3DB_150HZ) { +			/* set cut of freq to CF_MIN_3DB_150HZ (0x1) */ +			snd_soc_update_bits(codec, tx_mux_ctl_reg, +					    TX_MUX_CTL_CUT_OFF_FREQ_MASK, +					    TX_MUX_CTL_CF_NEG_3DB_150HZ); +		} +		break; +	case SND_SOC_DAPM_POST_PMU: +		/* enable HPF */ +		snd_soc_update_bits(codec, tx_mux_ctl_reg, +				    TX_MUX_CTL_HPF_BP_SEL_MASK, +				    TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS); +		/* apply the digital gain after the decimator is enabled */ +		snd_soc_write(codec, tx_gain_reg[w->shift], +			      snd_soc_read(codec, tx_gain_reg[w->shift])); +		snd_soc_update_bits(codec, tx_vol_ctl_reg, +				    TX_VOL_CTL_CFG_MUTE_EN_MASK, 0); +		break; +	case SND_SOC_DAPM_PRE_PMD: +		snd_soc_update_bits(codec, tx_vol_ctl_reg, +				    TX_VOL_CTL_CFG_MUTE_EN_MASK, +				    TX_VOL_CTL_CFG_MUTE_EN_ENABLE); +		snd_soc_update_bits(codec, tx_mux_ctl_reg, +				    TX_MUX_CTL_HPF_BP_SEL_MASK, +				    TX_MUX_CTL_HPF_BP_SEL_BYPASS); +		break; +	case SND_SOC_DAPM_POST_PMD: +		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, +				    1 << w->shift); +		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0); +		snd_soc_update_bits(codec, tx_mux_ctl_reg, +				    TX_MUX_CTL_HPF_BP_SEL_MASK, +				    TX_MUX_CTL_HPF_BP_SEL_BYPASS); +		snd_soc_update_bits(codec, tx_vol_ctl_reg, +				    TX_VOL_CTL_CFG_MUTE_EN_MASK, 0); +		break; +	} + +	return 0; +} + +static int msm8916_wcd_digital_enable_dmic(struct snd_soc_dapm_widget *w, +					   struct snd_kcontrol *kcontrol, +					   int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); +	unsigned int dmic; +	int ret; +	/* get dmic number out of widget name */ +	char *dmic_num = strpbrk(w->name, "12"); + +	if (dmic_num == NULL) { +		dev_err(codec->dev, "Invalid DMIC\n"); +		return -EINVAL; +	} +	ret = kstrtouint(dmic_num, 10, &dmic); +	if (ret < 0 || dmic > 2) { +		dev_err(codec->dev, "Invalid DMIC line on the codec\n"); +		return -EINVAL; +	} + +	switch (event) { +	case SND_SOC_DAPM_PRE_PMU: +		snd_soc_update_bits(codec, LPASS_CDC_CLK_DMIC_B1_CTL, +				    DMIC_B1_CTL_DMIC0_CLK_SEL_MASK, +				    DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3); +		switch (dmic) { +		case 1: +			snd_soc_update_bits(codec, LPASS_CDC_TX1_DMIC_CTL, +					    TXN_DMIC_CTL_CLK_SEL_MASK, +					    TXN_DMIC_CTL_CLK_SEL_DIV3); +			break; +		case 2: +			snd_soc_update_bits(codec, LPASS_CDC_TX2_DMIC_CTL, +					    TXN_DMIC_CTL_CLK_SEL_MASK, +					    TXN_DMIC_CTL_CLK_SEL_DIV3); +			break; +		} +		break; +	} + +	return 0; +} + +static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = { +	/*RX stuff */ +	SND_SOC_DAPM_AIF_IN("I2S RX1", NULL, 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_IN("I2S RX2", NULL, 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_IN("I2S RX3", NULL, 0, SND_SOC_NOPM, 0, 0), + +	SND_SOC_DAPM_OUTPUT("PDM_RX1"), +	SND_SOC_DAPM_OUTPUT("PDM_RX2"), +	SND_SOC_DAPM_OUTPUT("PDM_RX3"), + +	SND_SOC_DAPM_INPUT("LPASS_PDM_TX"), + +	SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_MIXER("RX3 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + +	/* Interpolator */ +	SND_SOC_DAPM_MIXER_E("RX1 INT", LPASS_CDC_CLK_RX_B1_CTL, 0, 0, NULL, +			     0, msm8916_wcd_digital_enable_interpolator, +			     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_MIXER_E("RX2 INT", LPASS_CDC_CLK_RX_B1_CTL, 1, 0, NULL, +			     0, msm8916_wcd_digital_enable_interpolator, +			     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_MIXER_E("RX3 INT", LPASS_CDC_CLK_RX_B1_CTL, 2, 0, NULL, +			     0, msm8916_wcd_digital_enable_interpolator, +			     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0, +			 &rx_mix1_inp1_mux), +	SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0, +			 &rx_mix1_inp2_mux), +	SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0, +			 &rx_mix1_inp3_mux), +	SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0, +			 &rx2_mix1_inp1_mux), +	SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0, +			 &rx2_mix1_inp2_mux), +	SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0, +			 &rx2_mix1_inp3_mux), +	SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0, +			 &rx3_mix1_inp1_mux), +	SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0, +			 &rx3_mix1_inp2_mux), +	SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0, +			 &rx3_mix1_inp3_mux), + +	/* TX */ +	SND_SOC_DAPM_MIXER("ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), + +	SND_SOC_DAPM_MUX_E("DEC1 MUX", LPASS_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0, +			   &dec1_mux, msm8916_wcd_digital_enable_dec, +			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | +			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_MUX_E("DEC2 MUX", LPASS_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0, +			   &dec2_mux, msm8916_wcd_digital_enable_dec, +			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | +			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_AIF_OUT("I2S TX1", NULL, 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("I2S TX2", NULL, 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("I2S TX3", NULL, 0, SND_SOC_NOPM, 0, 0), + +	/* Digital Mic Inputs */ +	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, +			   msm8916_wcd_digital_enable_dmic, +			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0, +			   msm8916_wcd_digital_enable_dmic, +			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +	SND_SOC_DAPM_SUPPLY("DMIC_CLK", LPASS_CDC_CLK_DMIC_B1_CTL, 0, 0, +			    NULL, 0), +	SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", LPASS_CDC_CLK_RX_I2S_CTL, +			    4, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", LPASS_CDC_CLK_TX_I2S_CTL, 4, 0, +			    NULL, 0), + +	SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("PDM_CLK", LPASS_CDC_CLK_PDM_CTL, 0, 0, NULL, 0), +	/* Connectivity Clock */ +	SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, LPASS_CDC_CLK_OTHR_CTL, 2, 0, +			      NULL, 0), + +}; + +static int msm8916_wcd_digital_get_clks(struct platform_device *pdev, +					struct msm8916_wcd_digital_priv	*priv) +{ +	struct device *dev = &pdev->dev; + +	priv->ahbclk = devm_clk_get(dev, "ahbix-clk"); +	if (IS_ERR(priv->ahbclk)) { +		dev_err(dev, "failed to get ahbix clk\n"); +		return PTR_ERR(priv->ahbclk); +	} + +	priv->mclk = devm_clk_get(dev, "mclk"); +	if (IS_ERR(priv->mclk)) { +		dev_err(dev, "failed to get mclk\n"); +		return PTR_ERR(priv->mclk); +	} + +	return 0; +} + +static int msm8916_wcd_digital_codec_probe(struct snd_soc_codec *codec) +{ +	struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(codec->dev); + +	snd_soc_codec_set_drvdata(codec, priv); + +	return 0; +} + +static int msm8916_wcd_digital_hw_params(struct snd_pcm_substream *substream, +					 struct snd_pcm_hw_params *params, +					 struct snd_soc_dai *dai) +{ +	u8 tx_fs_rate; +	u8 rx_fs_rate; + +	switch (params_rate(params)) { +	case 8000: +		tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_8_KHZ; +		rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_8_KHZ; +		break; +	case 16000: +		tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_16_KHZ; +		rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_16_KHZ; +		break; +	case 32000: +		tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_32_KHZ; +		rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_32_KHZ; +		break; +	case 48000: +		tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_48_KHZ; +		rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_48_KHZ; +		break; +	default: +		dev_err(dai->codec->dev, "Invalid sampling rate %d\n", +			params_rate(params)); +		return -EINVAL; +	} + +	switch (substream->stream) { +	case SNDRV_PCM_STREAM_CAPTURE: +		snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL, +				    TX_I2S_CTL_TX_I2S_FS_RATE_MASK, tx_fs_rate); +		break; +	case SNDRV_PCM_STREAM_PLAYBACK: +		snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL, +				    RX_I2S_CTL_RX_I2S_FS_RATE_MASK, rx_fs_rate); +		break; +	default: +		return -EINVAL; +	} + +	switch (params_format(params)) { +	case SNDRV_PCM_FORMAT_S16_LE: +		snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL, +				    TX_I2S_CTL_TX_I2S_MODE_MASK, +				    TX_I2S_CTL_TX_I2S_MODE_16); +		snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL, +				    RX_I2S_CTL_RX_I2S_MODE_MASK, +				    RX_I2S_CTL_RX_I2S_MODE_16); +		break; +	case SNDRV_PCM_FORMAT_S24_LE: +		snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL, +				    TX_I2S_CTL_TX_I2S_MODE_MASK, +				    TX_I2S_CTL_TX_I2S_MODE_32); +		snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL, +				    RX_I2S_CTL_RX_I2S_MODE_MASK, +				    RX_I2S_CTL_RX_I2S_MODE_32); +		break; +	default: +		dev_err(dai->dev, "%s: wrong format selected\n", __func__); +		return -EINVAL; +	} + +	return 0; +} + +static const struct snd_soc_dapm_route msm8916_wcd_digital_audio_map[] = { + +	{"I2S RX1",  NULL, "AIF1 Playback"}, +	{"I2S RX2",  NULL, "AIF1 Playback"}, +	{"I2S RX3",  NULL, "AIF1 Playback"}, + +	{"AIF1 Capture", NULL, "I2S TX1"}, +	{"AIF1 Capture", NULL, "I2S TX2"}, +	{"AIF1 Capture", NULL, "I2S TX3"}, + +	/* Decimator Inputs */ +	{"DEC1 MUX", "DMIC1", "DMIC1"}, +	{"DEC1 MUX", "DMIC2", "DMIC2"}, +	{"DEC1 MUX", "ADC1", "ADC1"}, +	{"DEC1 MUX", "ADC2", "ADC2"}, +	{"DEC1 MUX", "ADC3", "ADC3"}, +	{"DEC1 MUX", NULL, "CDC_CONN"}, + +	{"DEC2 MUX", "DMIC1", "DMIC1"}, +	{"DEC2 MUX", "DMIC2", "DMIC2"}, +	{"DEC2 MUX", "ADC1", "ADC1"}, +	{"DEC2 MUX", "ADC2", "ADC2"}, +	{"DEC2 MUX", "ADC3", "ADC3"}, +	{"DEC2 MUX", NULL, "CDC_CONN"}, + +	{"DMIC1", NULL, "DMIC_CLK"}, +	{"DMIC2", NULL, "DMIC_CLK"}, + +	{"I2S TX1", NULL, "DEC1 MUX"}, +	{"I2S TX2", NULL, "DEC2 MUX"}, + +	{"I2S TX1", NULL, "TX_I2S_CLK"}, +	{"I2S TX2", NULL, "TX_I2S_CLK"}, + +	{"TX_I2S_CLK", NULL, "MCLK"}, +	{"TX_I2S_CLK", NULL, "PDM_CLK"}, + +	{"ADC1", NULL, "LPASS_PDM_TX"}, +	{"ADC2", NULL, "LPASS_PDM_TX"}, +	{"ADC3", NULL, "LPASS_PDM_TX"}, + +	{"I2S RX1", NULL, "RX_I2S_CLK"}, +	{"I2S RX2", NULL, "RX_I2S_CLK"}, +	{"I2S RX3", NULL, "RX_I2S_CLK"}, + +	{"RX_I2S_CLK", NULL, "PDM_CLK"}, +	{"RX_I2S_CLK", NULL, "MCLK"}, +	{"RX_I2S_CLK", NULL, "CDC_CONN"}, + +	/* RX1 PATH.. */ +	{"PDM_RX1", NULL, "RX1 INT"}, +	{"RX1 INT", NULL, "RX1 MIX1"}, + +	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"}, +	{"RX1 MIX1", NULL, "RX1 MIX1 INP2"}, +	{"RX1 MIX1", NULL, "RX1 MIX1 INP3"}, + +	{"RX1 MIX1 INP1", "RX1", "I2S RX1"}, +	{"RX1 MIX1 INP1", "RX2", "I2S RX2"}, +	{"RX1 MIX1 INP1", "RX3", "I2S RX3"}, + +	{"RX1 MIX1 INP2", "RX1", "I2S RX1"}, +	{"RX1 MIX1 INP2", "RX2", "I2S RX2"}, +	{"RX1 MIX1 INP2", "RX3", "I2S RX3"}, + +	{"RX1 MIX1 INP3", "RX1", "I2S RX1"}, +	{"RX1 MIX1 INP3", "RX2", "I2S RX2"}, +	{"RX1 MIX1 INP3", "RX3", "I2S RX3"}, + +	/* RX2 PATH */ +	{"PDM_RX2", NULL, "RX2 INT"}, +	{"RX2 INT", NULL, "RX2 MIX1"}, + +	{"RX2 MIX1", NULL, "RX2 MIX1 INP1"}, +	{"RX2 MIX1", NULL, "RX2 MIX1 INP2"}, +	{"RX2 MIX1", NULL, "RX2 MIX1 INP3"}, + +	{"RX2 MIX1 INP1", "RX1", "I2S RX1"}, +	{"RX2 MIX1 INP1", "RX2", "I2S RX2"}, +	{"RX2 MIX1 INP1", "RX3", "I2S RX3"}, + +	{"RX2 MIX1 INP2", "RX1", "I2S RX1"}, +	{"RX2 MIX1 INP2", "RX2", "I2S RX2"}, +	{"RX2 MIX1 INP2", "RX3", "I2S RX3"}, + +	{"RX2 MIX1 INP3", "RX1", "I2S RX1"}, +	{"RX2 MIX1 INP3", "RX2", "I2S RX2"}, +	{"RX2 MIX1 INP3", "RX3", "I2S RX3"}, + +	/* RX3 PATH */ +	{"PDM_RX3", NULL, "RX3 INT"}, +	{"RX3 INT", NULL, "RX3 MIX1"}, + +	{"RX3 MIX1", NULL, "RX3 MIX1 INP1"}, +	{"RX3 MIX1", NULL, "RX3 MIX1 INP2"}, +	{"RX3 MIX1", NULL, "RX3 MIX1 INP3"}, + +	{"RX3 MIX1 INP1", "RX1", "I2S RX1"}, +	{"RX3 MIX1 INP1", "RX2", "I2S RX2"}, +	{"RX3 MIX1 INP1", "RX3", "I2S RX3"}, + +	{"RX3 MIX1 INP2", "RX1", "I2S RX1"}, +	{"RX3 MIX1 INP2", "RX2", "I2S RX2"}, +	{"RX3 MIX1 INP2", "RX3", "I2S RX3"}, + +	{"RX3 MIX1 INP3", "RX1", "I2S RX1"}, +	{"RX3 MIX1 INP3", "RX2", "I2S RX2"}, +	{"RX3 MIX1 INP3", "RX3", "I2S RX3"}, + +}; + +static int msm8916_wcd_digital_startup(struct snd_pcm_substream *substream, +				       struct snd_soc_dai *dai) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct msm8916_wcd_digital_priv *msm8916_wcd; +	unsigned long mclk_rate; + +	msm8916_wcd = snd_soc_codec_get_drvdata(codec); +	snd_soc_update_bits(codec, LPASS_CDC_CLK_MCLK_CTL, +			    MCLK_CTL_MCLK_EN_MASK, +			    MCLK_CTL_MCLK_EN_ENABLE); +	snd_soc_update_bits(codec, LPASS_CDC_CLK_PDM_CTL, +			    LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, +			    LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB); + +	mclk_rate = clk_get_rate(msm8916_wcd->mclk); +	switch (mclk_rate) { +	case 12288000: +		snd_soc_update_bits(codec, LPASS_CDC_TOP_CTL, +				    TOP_CTL_DIG_MCLK_FREQ_MASK, +				    TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ); +		break; +	case 9600000: +		snd_soc_update_bits(codec, LPASS_CDC_TOP_CTL, +				    TOP_CTL_DIG_MCLK_FREQ_MASK, +				    TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ); +		break; +	default: +		dev_err(codec->dev, "Invalid mclk rate %ld\n", mclk_rate); +		break; +	} +	return 0; +} + +static void msm8916_wcd_digital_shutdown(struct snd_pcm_substream *substream, +					 struct snd_soc_dai *dai) +{ +	snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_PDM_CTL, +			    LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, 0); +} + +static struct snd_soc_dai_ops msm8916_wcd_digital_dai_ops = { +	.startup = msm8916_wcd_digital_startup, +	.shutdown = msm8916_wcd_digital_shutdown, +	.hw_params = msm8916_wcd_digital_hw_params, +}; + +static struct snd_soc_dai_driver msm8916_wcd_digital_dai[] = { +	[0] = { +	       .name = "msm8916_wcd_digital_i2s_rx1", +	       .id = 0, +	       .playback = { +			    .stream_name = "AIF1 Playback", +			    .rates = MSM8916_WCD_DIGITAL_RATES, +			    .formats = MSM8916_WCD_DIGITAL_FORMATS, +			    .channels_min = 1, +			    .channels_max = 3, +			    }, +	       .ops = &msm8916_wcd_digital_dai_ops, +	       }, +	[1] = { +	       .name = "msm8916_wcd_digital_i2s_tx1", +	       .id = 1, +	       .capture = { +			   .stream_name = "AIF1 Capture", +			   .rates = MSM8916_WCD_DIGITAL_RATES, +			   .formats = MSM8916_WCD_DIGITAL_FORMATS, +			   .channels_min = 1, +			   .channels_max = 4, +			   }, +	       .ops = &msm8916_wcd_digital_dai_ops, +	       }, +}; + +static struct snd_soc_codec_driver msm8916_wcd_digital = { +	.probe = msm8916_wcd_digital_codec_probe, +	.component_driver = { +		.controls = msm8916_wcd_digital_snd_controls, +		.num_controls = ARRAY_SIZE(msm8916_wcd_digital_snd_controls), +		.dapm_widgets = msm8916_wcd_digital_dapm_widgets, +		.num_dapm_widgets = +				 ARRAY_SIZE(msm8916_wcd_digital_dapm_widgets), +		.dapm_routes = msm8916_wcd_digital_audio_map, +		.num_dapm_routes = ARRAY_SIZE(msm8916_wcd_digital_audio_map), +	}, +}; + +static const struct regmap_config msm8916_codec_regmap_config = { +	.reg_bits = 32, +	.reg_stride = 4, +	.val_bits = 32, +	.max_register = LPASS_CDC_TX2_DMIC_CTL, +	.cache_type = REGCACHE_FLAT, +}; + +static int msm8916_wcd_digital_probe(struct platform_device *pdev) +{ +	struct msm8916_wcd_digital_priv *priv; +	struct device *dev = &pdev->dev; +	void __iomem *base; +	struct resource *mem_res; +	struct regmap *digital_map; +	int ret; + +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	base = devm_ioremap_resource(&pdev->dev, mem_res); +	if (IS_ERR(base)) +		return PTR_ERR(base); + +	digital_map = +	    devm_regmap_init_mmio(&pdev->dev, base, +				  &msm8916_codec_regmap_config); +	if (IS_ERR(digital_map)) +		return PTR_ERR(digital_map); + +	ret = msm8916_wcd_digital_get_clks(pdev, priv); +	if (ret < 0) +		return ret; + +	ret = clk_prepare_enable(priv->ahbclk); +	if (ret < 0) { +		dev_err(dev, "failed to enable ahbclk %d\n", ret); +		return ret; +	} + +	ret = clk_prepare_enable(priv->mclk); +	if (ret < 0) { +		dev_err(dev, "failed to enable mclk %d\n", ret); +		return ret; +	} + +	dev_set_drvdata(dev, priv); + +	return snd_soc_register_codec(dev, &msm8916_wcd_digital, +				      msm8916_wcd_digital_dai, +				      ARRAY_SIZE(msm8916_wcd_digital_dai)); +} + +static int msm8916_wcd_digital_remove(struct platform_device *pdev) +{ +	struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(&pdev->dev); + +	snd_soc_unregister_codec(&pdev->dev); +	clk_disable_unprepare(priv->mclk); +	clk_disable_unprepare(priv->ahbclk); + +	return 0; +} + +static const struct of_device_id msm8916_wcd_digital_match_table[] = { +	{ .compatible = "qcom,msm8916-wcd-digital-codec" }, +	{ } +}; + +MODULE_DEVICE_TABLE(of, msm8916_wcd_digital_match_table); + +static struct platform_driver msm8916_wcd_digital_driver = { +	.driver = { +		   .name = "msm8916-wcd-digital-codec", +		   .of_match_table = msm8916_wcd_digital_match_table, +	}, +	.probe = msm8916_wcd_digital_probe, +	.remove = msm8916_wcd_digital_remove, +}; + +module_platform_driver(msm8916_wcd_digital_driver); + +MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>"); +MODULE_DESCRIPTION("MSM8916 WCD Digital Codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index e643be91d762..efe3a44658d5 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -43,6 +43,8 @@  #define GAIN_AUGMENT 22500  #define SIDETONE_BASE 207000 +/* the maximum frequency of CLK_ADC and CLK_DAC */ +#define CLK_DA_AD_MAX 6144000  static int nau8825_configure_sysclk(struct nau8825 *nau8825,  		int clk_id, unsigned int freq); @@ -95,6 +97,27 @@ static const struct nau8825_fll_attr fll_pre_scalar[] = {  	{ 8, 0x3 },  }; +/* over sampling rate */ +struct nau8825_osr_attr { +	unsigned int osr; +	unsigned int clk_src; +}; + +static const struct nau8825_osr_attr osr_dac_sel[] = { +	{ 64, 2 },	/* OSR 64, SRC 1/4 */ +	{ 256, 0 },	/* OSR 256, SRC 1 */ +	{ 128, 1 },	/* OSR 128, SRC 1/2 */ +	{ 0, 0 }, +	{ 32, 3 },	/* OSR 32, SRC 1/8 */ +}; + +static const struct nau8825_osr_attr osr_adc_sel[] = { +	{ 32, 3 },	/* OSR 32, SRC 1/8 */ +	{ 64, 2 },	/* OSR 64, SRC 1/4 */ +	{ 128, 1 },	/* OSR 128, SRC 1/2 */ +	{ 256, 0 },	/* OSR 256, SRC 1 */ +}; +  static const struct reg_default nau8825_reg_defaults[] = {  	{ NAU8825_REG_ENA_CTRL, 0x00ff },  	{ NAU8825_REG_IIC_ADDR_SET, 0x0 }, @@ -1179,15 +1202,64 @@ static const struct snd_soc_dapm_route nau8825_dapm_routes[] = {  	{"HPOR", NULL, "Class G"},  }; +static int nau8825_clock_check(struct nau8825 *nau8825, +	int stream, int rate, int osr) +{ +	int osrate; + +	if (stream == SNDRV_PCM_STREAM_PLAYBACK) { +		if (osr >= ARRAY_SIZE(osr_dac_sel)) +			return -EINVAL; +		osrate = osr_dac_sel[osr].osr; +	} else { +		if (osr >= ARRAY_SIZE(osr_adc_sel)) +			return -EINVAL; +		osrate = osr_adc_sel[osr].osr; +	} + +	if (!osrate || rate * osr > CLK_DA_AD_MAX) { +		dev_err(nau8825->dev, "exceed the maximum frequency of CLK_ADC or CLK_DAC\n"); +		return -EINVAL; +	} + +	return 0; +} +  static int nau8825_hw_params(struct snd_pcm_substream *substream,  				struct snd_pcm_hw_params *params,  				struct snd_soc_dai *dai)  {  	struct snd_soc_codec *codec = dai->codec;  	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); -	unsigned int val_len = 0; +	unsigned int val_len = 0, osr; + +	nau8825_sema_acquire(nau8825, 3 * HZ); -	nau8825_sema_acquire(nau8825, 2 * HZ); +	/* CLK_DAC or CLK_ADC = OSR * FS +	 * DAC or ADC clock frequency is defined as Over Sampling Rate (OSR) +	 * multiplied by the audio sample rate (Fs). Note that the OSR and Fs +	 * values must be selected such that the maximum frequency is less +	 * than 6.144 MHz. +	 */ +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { +		regmap_read(nau8825->regmap, NAU8825_REG_DAC_CTRL1, &osr); +		osr &= NAU8825_DAC_OVERSAMPLE_MASK; +		if (nau8825_clock_check(nau8825, substream->stream, +			params_rate(params), osr)) +			return -EINVAL; +		regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, +			NAU8825_CLK_DAC_SRC_MASK, +			osr_dac_sel[osr].clk_src << NAU8825_CLK_DAC_SRC_SFT); +	} else { +		regmap_read(nau8825->regmap, NAU8825_REG_ADC_RATE, &osr); +		osr &= NAU8825_ADC_SYNC_DOWN_MASK; +		if (nau8825_clock_check(nau8825, substream->stream, +			params_rate(params), osr)) +			return -EINVAL; +		regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, +			NAU8825_CLK_ADC_SRC_MASK, +			osr_adc_sel[osr].clk_src << NAU8825_CLK_ADC_SRC_SFT); +	}  	switch (params_width(params)) {  	case 16: @@ -1221,7 +1293,7 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)  	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);  	unsigned int ctrl1_val = 0, ctrl2_val = 0; -	nau8825_sema_acquire(nau8825, 2 * HZ); +	nau8825_sema_acquire(nau8825, 3 * HZ);  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {  	case SND_SOC_DAIFMT_CBM_CFM: @@ -1774,9 +1846,10 @@ static void nau8825_init_regs(struct nau8825 *nau8825)  	 * (audible hiss). Set it to something better.  	 */  	regmap_update_bits(regmap, NAU8825_REG_ADC_RATE, -		NAU8825_ADC_SYNC_DOWN_MASK, NAU8825_ADC_SYNC_DOWN_128); +		NAU8825_ADC_SYNC_DOWN_MASK | NAU8825_ADC_SINC4_EN, +		NAU8825_ADC_SYNC_DOWN_64);  	regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1, -		NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_128); +		NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_64);  	/* Disable DACR/L power */  	regmap_update_bits(regmap, NAU8825_REG_CHARGE_PUMP,  		NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, @@ -1811,6 +1884,9 @@ static void nau8825_init_regs(struct nau8825 *nau8825)  		NAU8825_DACL_CH_SEL_MASK, NAU8825_DACL_CH_SEL_L);  	regmap_update_bits(nau8825->regmap, NAU8825_REG_DACR_CTRL,  		NAU8825_DACL_CH_SEL_MASK, NAU8825_DACL_CH_SEL_R); +	/* Disable short Frame Sync detection logic */ +	regmap_update_bits(regmap, NAU8825_REG_LEFT_TIME_SLOT, +		NAU8825_DIS_FS_SHORT_DET, NAU8825_DIS_FS_SHORT_DET);  }  static const struct regmap_config nau8825_regmap_config = { @@ -1919,8 +1995,10 @@ static void nau8825_fll_apply(struct nau8825 *nau8825,  	regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,  		NAU8825_CLK_SRC_MASK | NAU8825_CLK_MCLK_SRC_MASK,  		NAU8825_CLK_SRC_MCLK | fll_param->mclk_src); +	/* Make DSP operate at high speed for better performance. */  	regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL1, -			NAU8825_FLL_RATIO_MASK, fll_param->ratio); +		NAU8825_FLL_RATIO_MASK | NAU8825_ICTRL_LATCH_MASK, +		fll_param->ratio | (0x6 << NAU8825_ICTRL_LATCH_SFT));  	/* FLL 16-bit fractional input */  	regmap_write(nau8825->regmap, NAU8825_REG_FLL2, fll_param->fll_frac);  	/* FLL 10-bit integer input */ @@ -1936,19 +2014,22 @@ static void nau8825_fll_apply(struct nau8825 *nau8825,  	regmap_update_bits(nau8825->regmap,  		NAU8825_REG_FLL6, NAU8825_DCO_EN, 0);  	if (fll_param->fll_frac) { +		/* set FLL loop filter enable and cutoff frequency at 500Khz */  		regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5,  			NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN |  			NAU8825_FLL_FTR_SW_MASK,  			NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN |  			NAU8825_FLL_FTR_SW_FILTER);  		regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6, -			NAU8825_SDM_EN, NAU8825_SDM_EN); +			NAU8825_SDM_EN | NAU8825_CUTOFF500, +			NAU8825_SDM_EN | NAU8825_CUTOFF500);  	} else { +		/* disable FLL loop filter and cutoff frequency */  		regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5,  			NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN |  			NAU8825_FLL_FTR_SW_MASK, NAU8825_FLL_FTR_SW_ACCU); -		regmap_update_bits(nau8825->regmap, -			NAU8825_REG_FLL6, NAU8825_SDM_EN, 0); +		regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6, +			NAU8825_SDM_EN | NAU8825_CUTOFF500, 0);  	}  } @@ -2014,6 +2095,9 @@ static void nau8825_configure_mclk_as_sysclk(struct regmap *regmap)  		NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_MCLK);  	regmap_update_bits(regmap, NAU8825_REG_FLL6,  		NAU8825_DCO_EN, 0); +	/* Make DSP operate as default setting for power saving. */ +	regmap_update_bits(regmap, NAU8825_REG_FLL1, +		NAU8825_ICTRL_LATCH_MASK, 0);  }  static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, @@ -2038,7 +2122,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,  		 * fered by cross talk process, the driver make the playback  		 * preparation halted until cross talk process finish.  		 */ -		nau8825_sema_acquire(nau8825, 2 * HZ); +		nau8825_sema_acquire(nau8825, 3 * HZ);  		nau8825_configure_mclk_as_sysclk(regmap);  		/* MCLK not changed by clock tree */  		regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER, @@ -2057,10 +2141,13 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,  				NAU8825_DCO_EN, NAU8825_DCO_EN);  			regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,  				NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_VCO); -			/* Decrease the VCO frequency for power saving */ +			/* Decrease the VCO frequency and make DSP operate +			 * as default setting for power saving. +			 */  			regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,  				NAU8825_CLK_MCLK_SRC_MASK, 0xf);  			regmap_update_bits(regmap, NAU8825_REG_FLL1, +				NAU8825_ICTRL_LATCH_MASK |  				NAU8825_FLL_RATIO_MASK, 0x10);  			regmap_update_bits(regmap, NAU8825_REG_FLL6,  				NAU8825_SDM_EN, NAU8825_SDM_EN); @@ -2083,9 +2170,14 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,  		 * fered by cross talk process, the driver make the playback  		 * preparation halted until cross talk process finish.  		 */ -		nau8825_sema_acquire(nau8825, 2 * HZ); +		nau8825_sema_acquire(nau8825, 3 * HZ); +		/* Higher FLL reference input frequency can only set lower +		 * gain error, such as 0000 for input reference from MCLK +		 * 12.288Mhz. +		 */  		regmap_update_bits(regmap, NAU8825_REG_FLL3, -			NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_MCLK); +			NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK, +			NAU8825_FLL_CLK_SRC_MCLK | 0);  		/* Release the semaphone. */  		nau8825_sema_release(nau8825); @@ -2100,9 +2192,17 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,  		 * fered by cross talk process, the driver make the playback  		 * preparation halted until cross talk process finish.  		 */ -		nau8825_sema_acquire(nau8825, 2 * HZ); +		nau8825_sema_acquire(nau8825, 3 * HZ); +		/* If FLL reference input is from low frequency source, +		 * higher error gain can apply such as 0xf which has +		 * the most sensitive gain error correction threshold, +		 * Therefore, FLL has the most accurate DCO to +		 * target frequency. +		 */  		regmap_update_bits(regmap, NAU8825_REG_FLL3, -			NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_BLK); +			NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK, +			NAU8825_FLL_CLK_SRC_BLK | +			(0xf << NAU8825_GAIN_ERR_SFT));  		/* Release the semaphone. */  		nau8825_sema_release(nau8825); @@ -2118,9 +2218,17 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,  		 * fered by cross talk process, the driver make the playback  		 * preparation halted until cross talk process finish.  		 */ -		nau8825_sema_acquire(nau8825, 2 * HZ); +		nau8825_sema_acquire(nau8825, 3 * HZ); +		/* If FLL reference input is from low frequency source, +		 * higher error gain can apply such as 0xf which has +		 * the most sensitive gain error correction threshold, +		 * Therefore, FLL has the most accurate DCO to +		 * target frequency. +		 */  		regmap_update_bits(regmap, NAU8825_REG_FLL3, -			NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_FS); +			NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK, +			NAU8825_FLL_CLK_SRC_FS | +			(0xf << NAU8825_GAIN_ERR_SFT));  		/* Release the semaphone. */  		nau8825_sema_release(nau8825); diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 1c63e2abafa9..5d1704e73241 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -115,12 +115,20 @@  #define NAU8825_CLK_SRC_MASK			(1 << NAU8825_CLK_SRC_SFT)  #define NAU8825_CLK_SRC_VCO			(1 << NAU8825_CLK_SRC_SFT)  #define NAU8825_CLK_SRC_MCLK			(0 << NAU8825_CLK_SRC_SFT) +#define NAU8825_CLK_ADC_SRC_SFT		6 +#define NAU8825_CLK_ADC_SRC_MASK		(0x3 << NAU8825_CLK_ADC_SRC_SFT) +#define NAU8825_CLK_DAC_SRC_SFT		4 +#define NAU8825_CLK_DAC_SRC_MASK		(0x3 << NAU8825_CLK_DAC_SRC_SFT)  #define NAU8825_CLK_MCLK_SRC_MASK		(0xf << 0)  /* FLL1 (0x04) */ +#define NAU8825_ICTRL_LATCH_SFT	10 +#define NAU8825_ICTRL_LATCH_MASK	(0x7 << NAU8825_ICTRL_LATCH_SFT)  #define NAU8825_FLL_RATIO_MASK			(0x7f << 0)  /* FLL3 (0x06) */ +#define NAU8825_GAIN_ERR_SFT			12 +#define NAU8825_GAIN_ERR_MASK			(0xf << NAU8825_GAIN_ERR_SFT)  #define NAU8825_FLL_INTEGER_MASK		(0x3ff << 0)  #define NAU8825_FLL_CLK_SRC_SFT		10  #define NAU8825_FLL_CLK_SRC_MASK		(0x3 << NAU8825_FLL_CLK_SRC_SFT) @@ -144,6 +152,7 @@  /* FLL6 (0x9) */  #define NAU8825_DCO_EN				(0x1 << 15)  #define NAU8825_SDM_EN				(0x1 << 14) +#define NAU8825_CUTOFF500			(0x1 << 13)  /* HSD_CTRL (0xc) */  #define NAU8825_HSD_AUTO_MODE	(1 << 6) @@ -246,6 +255,11 @@  #define NAU8825_I2S_MS_SLAVE	(0 << NAU8825_I2S_MS_SFT)  #define NAU8825_I2S_BLK_DIV_MASK	0x7 +/* LEFT_TIME_SLOT (0x1e) */ +#define NAU8825_FS_ERR_CMP_SEL_SFT	14 +#define NAU8825_FS_ERR_CMP_SEL_MASK	(0x3 << NAU8825_FS_ERR_CMP_SEL_SFT) +#define NAU8825_DIS_FS_SHORT_DET	(1 << 13) +  /* BIQ_CTRL (0x20) */  #define NAU8825_BIQ_WRT_SFT   4  #define NAU8825_BIQ_WRT_EN     (1 << NAU8825_BIQ_WRT_SFT) @@ -255,6 +269,8 @@  #define NAU8825_BIQ_PATH_DAC   (1 << NAU8825_BIQ_PATH_SFT)  /* ADC_RATE (0x2b) */ +#define NAU8825_ADC_SINC4_SFT		4 +#define NAU8825_ADC_SINC4_EN		(1 << NAU8825_ADC_SINC4_SFT)  #define NAU8825_ADC_SYNC_DOWN_SFT	0  #define NAU8825_ADC_SYNC_DOWN_MASK	0x3  #define NAU8825_ADC_SYNC_DOWN_32	0 diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c index 1dc68ab08a17..7b447d0b173a 100644 --- a/sound/soc/codecs/rl6231.c +++ b/sound/soc/codecs/rl6231.c @@ -102,6 +102,7 @@ struct pll_calc_map {  };  static const struct pll_calc_map pll_preset_table[] = { +	{19200000,  4096000,  23, 14, 1, false},  	{19200000,  24576000,  3, 30, 3, false},  }; diff --git a/sound/soc/codecs/rl6347a.c b/sound/soc/codecs/rl6347a.c index a4b910efbd45..8f571cf8edd4 100644 --- a/sound/soc/codecs/rl6347a.c +++ b/sound/soc/codecs/rl6347a.c @@ -51,7 +51,7 @@ int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value)  	if (ret == 4)  		return 0;  	else -		pr_err("ret=%d\n", ret); +		dev_err(&client->dev, "I2C error %d\n", ret);  	if (ret < 0)  		return ret;  	else diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 2db8179047ae..7150a407ffd9 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -326,11 +326,31 @@ static void rt298_jack_detect_work(struct work_struct *work)  int rt298_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)  {  	struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); +	struct snd_soc_dapm_context *dapm; +	bool hp = false; +	bool mic = false; +	int status = 0; + +	/* If jack in NULL, disable HS jack */ +	if (!jack) { +		regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x0); +		dapm = snd_soc_codec_get_dapm(codec); +		snd_soc_dapm_disable_pin(dapm, "LDO1"); +		snd_soc_dapm_sync(dapm); +		return 0; +	}  	rt298->jack = jack; +	regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2); -	/* Send an initial empty report */ -	snd_soc_jack_report(rt298->jack, 0, +	rt298_jack_detect(rt298, &hp, &mic); +	if (hp == true) +		status |= SND_JACK_HEADPHONE; + +	if (mic == true) +		status |= SND_JACK_MICROPHONE; + +	snd_soc_jack_report(rt298->jack, status,  		SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);  	return 0; diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 09103aab0cb2..0901e25d6db6 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -20,7 +20,6 @@  #include <linux/slab.h>  #include <linux/gpio.h>  #include <linux/sched.h> -#include <linux/kthread.h>  #include <linux/uaccess.h>  #include <linux/miscdevice.h>  #include <linux/regulator/consumer.h> diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index f24b7cfd3a89..b281a46d769d 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -452,6 +452,9 @@ static int rt5514_set_dmic_clk(struct snd_soc_dapm_widget *w,  			RT5514_CLK_DMIC_OUT_SEL_MASK,  			idx << RT5514_CLK_DMIC_OUT_SEL_SFT); +	if (rt5514->pdata.dmic_init_delay) +		msleep(rt5514->pdata.dmic_init_delay); +  	return idx;  } @@ -1073,9 +1076,18 @@ static const struct of_device_id rt5514_of_match[] = {  MODULE_DEVICE_TABLE(of, rt5514_of_match);  #endif +static int rt5514_parse_dt(struct rt5514_priv *rt5514, struct device *dev) +{ +	device_property_read_u32(dev, "realtek,dmic-init-delay-ms", +		&rt5514->pdata.dmic_init_delay); + +	return 0; +} +  static int rt5514_i2c_probe(struct i2c_client *i2c,  		    const struct i2c_device_id *id)  { +	struct rt5514_platform_data *pdata = dev_get_platdata(&i2c->dev);  	struct rt5514_priv *rt5514;  	int ret;  	unsigned int val; @@ -1087,6 +1099,11 @@ static int rt5514_i2c_probe(struct i2c_client *i2c,  	i2c_set_clientdata(i2c, rt5514); +	if (pdata) +		rt5514->pdata = *pdata; +	else if (i2c->dev.of_node) +		rt5514_parse_dt(rt5514, &i2c->dev); +  	rt5514->i2c_regmap = devm_regmap_init_i2c(i2c, &rt5514_i2c_regmap);  	if (IS_ERR(rt5514->i2c_regmap)) {  		ret = PTR_ERR(rt5514->i2c_regmap); diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h index 229de0e2c88c..5d343fb6d125 100644 --- a/sound/soc/codecs/rt5514.h +++ b/sound/soc/codecs/rt5514.h @@ -13,6 +13,7 @@  #define __RT5514_H__  #include <linux/clk.h> +#include <sound/rt5514.h>  #define RT5514_DEVICE_ID			0x10ec5514 @@ -243,6 +244,7 @@ enum {  };  struct rt5514_priv { +	struct rt5514_platform_data pdata;  	struct snd_soc_codec *codec;  	struct regmap *i2c_regmap, *regmap;  	struct clk *mclk; diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index d1f273b24991..7d6e0823f98f 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -960,8 +960,7 @@ static int rt5616_hw_params(struct snd_pcm_substream *substream,  			    struct snd_pcm_hw_params *params,  			    struct snd_soc_dai *dai)  { -	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct snd_soc_codec *codec = rtd->codec; +	struct snd_soc_codec *codec = dai->codec;  	struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);  	unsigned int val_len = 0, val_clk, mask_clk;  	int pre_div, bclk_ms, frame_size; diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 3cc1135fc2cd..e29a6defefa0 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -423,6 +423,8 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = {  	SOC_DOUBLE_TLV("ADC Capture Volume", RT5640_ADC_DIG_VOL,  			RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,  			127, 0, adc_vol_tlv), +	SOC_DOUBLE("Mono ADC Capture Switch", RT5640_DUMMY1, +		RT5640_M_MONO_ADC_L_SFT, RT5640_M_MONO_ADC_R_SFT, 1, 1),  	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5640_ADC_DATA,  			RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,  			127, 0, adc_vol_tlv), @@ -2407,6 +2409,9 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,  	if (ret != 0)  		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); +	regmap_update_bits(rt5640->regmap, RT5640_DUMMY1, +				RT5640_MCLK_DET, RT5640_MCLK_DET); +  	if (rt5640->pdata.in1_diff)  		regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2,  					RT5640_IN_DF1, RT5640_IN_DF1); diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 90c88711c72a..b8a811732a52 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -1970,6 +1970,12 @@  #define RT5640_ZCD_HP_DIS			(0x0 << 15)  #define RT5640_ZCD_HP_EN			(0x1 << 15) +/* General Control 1 (0xfa) */ +#define RT5640_M_MONO_ADC_L			(0x1 << 13) +#define RT5640_M_MONO_ADC_L_SFT			13 +#define RT5640_M_MONO_ADC_R			(0x1 << 12) +#define RT5640_M_MONO_ADC_R_SFT			12 +#define RT5640_MCLK_DET				(0x1 << 11)  /* Codec Private Register definition */  /* 3D Speaker Control (0x63) */ diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index 9f0933ced804..76cf76a2e9b6 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -1311,6 +1311,10 @@ static int rt5660_i2c_probe(struct i2c_client *i2c,  	if (ret != 0)  		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); +	regmap_update_bits(rt5660->regmap, RT5660_GEN_CTRL1, +		RT5660_AUTO_DIS_AMP | RT5660_MCLK_DET | RT5660_POW_CLKDET, +		RT5660_AUTO_DIS_AMP | RT5660_MCLK_DET | RT5660_POW_CLKDET); +  	if (rt5660->pdata.dmic1_data_pin) {  		regmap_update_bits(rt5660->regmap, RT5660_GPIO_CTRL1,  			RT5660_GP1_PIN_MASK, RT5660_GP1_PIN_DMIC1_SCL); diff --git a/sound/soc/codecs/rt5660.h b/sound/soc/codecs/rt5660.h index 6cdb9269ec9e..bba18fb66b6f 100644 --- a/sound/soc/codecs/rt5660.h +++ b/sound/soc/codecs/rt5660.h @@ -810,6 +810,9 @@  /* General Control 1 (0xfa) */  #define RT5660_PWR_VREF_HP			(0x1 << 11)  #define RT5660_PWR_VREF_HP_SFT			11 +#define RT5660_AUTO_DIS_AMP			(0x1 << 6) +#define RT5660_MCLK_DET				(0x1 << 5) +#define RT5660_POW_CLKDET			(0x1 << 1)  #define RT5660_DIG_GATE_CTRL			(0x1)  #define RT5660_DIG_GATE_CTRL_SFT		0 diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 00ff2788879e..a32508d7dcfd 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -1,5 +1,5 @@  /* - * rt5663.c  --  RT5668/RT5663 ALSA SoC audio codec driver + * rt5663.c  --  RT5663 ALSA SoC audio codec driver   *   * Copyright 2016 Realtek Semiconductor Corp.   * Author: Jack Yu <jack.yu@realtek.com> @@ -30,12 +30,12 @@  #include "rt5663.h"  #include "rl6231.h" -#define RT5668_DEVICE_ID 0x6451 -#define RT5663_DEVICE_ID 0x6406 +#define RT5663_DEVICE_ID_2 0x6451 +#define RT5663_DEVICE_ID_1 0x6406  enum { -	CODEC_TYPE_RT5668, -	CODEC_TYPE_RT5663, +	CODEC_VER_1, +	CODEC_VER_0,  };  struct rt5663_priv { @@ -45,7 +45,7 @@ struct rt5663_priv {  	struct snd_soc_jack *hs_jack;  	struct timer_list btn_check_timer; -	int codec_type; +	int codec_ver;  	int sysclk;  	int sysclk_src;  	int lrck; @@ -57,7 +57,7 @@ struct rt5663_priv {  	int jack_type;  }; -static const struct reg_default rt5668_reg[] = { +static const struct reg_default rt5663_v2_reg[] = {  	{ 0x0000, 0x0000 },  	{ 0x0001, 0xc8c8 },  	{ 0x0002, 0x8080 }, @@ -730,7 +730,7 @@ static bool rt5663_volatile_register(struct device *dev, unsigned int reg)  	case RT5663_ADC_EQ_1:  	case RT5663_INT_ST_1:  	case RT5663_INT_ST_2: -	case RT5663_GPIO_STA: +	case RT5663_GPIO_STA1:  	case RT5663_SIN_GEN_1:  	case RT5663_IL_CMD_1:  	case RT5663_IL_CMD_5: @@ -846,7 +846,7 @@ static bool rt5663_readable_register(struct device *dev, unsigned int reg)  	case RT5663_INT_ST_2:  	case RT5663_GPIO_1:  	case RT5663_GPIO_2: -	case RT5663_GPIO_STA: +	case RT5663_GPIO_STA1:  	case RT5663_SIN_GEN_1:  	case RT5663_SIN_GEN_2:  	case RT5663_SIN_GEN_3: @@ -1036,23 +1036,23 @@ static bool rt5663_readable_register(struct device *dev, unsigned int reg)  	}  } -static bool rt5668_volatile_register(struct device *dev, unsigned int reg) +static bool rt5663_v2_volatile_register(struct device *dev, unsigned int reg)  {  	switch (reg) {  	case RT5663_RESET: -	case RT5668_CBJ_TYPE_2: -	case RT5668_PDM_OUT_CTL: -	case RT5668_PDM_I2C_DATA_CTL1: -	case RT5668_PDM_I2C_DATA_CTL4: -	case RT5668_ALC_BK_GAIN: +	case RT5663_CBJ_TYPE_2: +	case RT5663_PDM_OUT_CTL: +	case RT5663_PDM_I2C_DATA_CTL1: +	case RT5663_PDM_I2C_DATA_CTL4: +	case RT5663_ALC_BK_GAIN:  	case RT5663_PLL_2:  	case RT5663_MICBIAS_1:  	case RT5663_ADC_EQ_1:  	case RT5663_INT_ST_1: -	case RT5668_GPIO_STA: +	case RT5663_GPIO_STA2:  	case RT5663_IL_CMD_1:  	case RT5663_IL_CMD_5: -	case RT5668_A_JD_CTRL: +	case RT5663_A_JD_CTRL:  	case RT5663_JD_CTRL2:  	case RT5663_VENDOR_ID:  	case RT5663_VENDOR_ID_1: @@ -1061,15 +1061,15 @@ static bool rt5668_volatile_register(struct device *dev, unsigned int reg)  	case RT5663_STO_DRE_5:  	case RT5663_STO_DRE_6:  	case RT5663_STO_DRE_7: -	case RT5668_MONO_DYNA_6: -	case RT5668_STO1_SIL_DET: -	case RT5668_MONOL_SIL_DET: -	case RT5668_MONOR_SIL_DET: -	case RT5668_STO2_DAC_SIL: -	case RT5668_MONO_AMP_CAL_ST1: -	case RT5668_MONO_AMP_CAL_ST2: -	case RT5668_MONO_AMP_CAL_ST3: -	case RT5668_MONO_AMP_CAL_ST4: +	case RT5663_MONO_DYNA_6: +	case RT5663_STO1_SIL_DET: +	case RT5663_MONOL_SIL_DET: +	case RT5663_MONOR_SIL_DET: +	case RT5663_STO2_DAC_SIL: +	case RT5663_MONO_AMP_CAL_ST1: +	case RT5663_MONO_AMP_CAL_ST2: +	case RT5663_MONO_AMP_CAL_ST3: +	case RT5663_MONO_AMP_CAL_ST4:  	case RT5663_HP_IMP_SEN_2:  	case RT5663_HP_IMP_SEN_3:  	case RT5663_HP_IMP_SEN_4: @@ -1083,218 +1083,218 @@ static bool rt5668_volatile_register(struct device *dev, unsigned int reg)  	case RT5663_HP_CALIB_ST7:  	case RT5663_HP_CALIB_ST8:  	case RT5663_HP_CALIB_ST9: -	case RT5668_HP_CALIB_ST10: -	case RT5668_HP_CALIB_ST11: +	case RT5663_HP_CALIB_ST10: +	case RT5663_HP_CALIB_ST11:  		return true;  	default:  		return false;  	}  } -static bool rt5668_readable_register(struct device *dev, unsigned int reg) +static bool rt5663_v2_readable_register(struct device *dev, unsigned int reg)  {  	switch (reg) { -	case RT5668_LOUT_CTRL: -	case RT5668_HP_AMP_2: -	case RT5668_MONO_OUT: -	case RT5668_MONO_GAIN: -	case RT5668_AEC_BST: -	case RT5668_IN1_IN2: -	case RT5668_IN3_IN4: -	case RT5668_INL1_INR1: -	case RT5668_CBJ_TYPE_2: -	case RT5668_CBJ_TYPE_3: -	case RT5668_CBJ_TYPE_4: -	case RT5668_CBJ_TYPE_5: -	case RT5668_CBJ_TYPE_8: -	case RT5668_DAC3_DIG_VOL: -	case RT5668_DAC3_CTRL: -	case RT5668_MONO_ADC_DIG_VOL: -	case RT5668_STO2_ADC_DIG_VOL: -	case RT5668_MONO_ADC_BST_GAIN: -	case RT5668_STO2_ADC_BST_GAIN: -	case RT5668_SIDETONE_CTRL: -	case RT5668_MONO1_ADC_MIXER: -	case RT5668_STO2_ADC_MIXER: -	case RT5668_MONO_DAC_MIXER: -	case RT5668_DAC2_SRC_CTRL: -	case RT5668_IF_3_4_DATA_CTL: -	case RT5668_IF_5_DATA_CTL: -	case RT5668_PDM_OUT_CTL: -	case RT5668_PDM_I2C_DATA_CTL1: -	case RT5668_PDM_I2C_DATA_CTL2: -	case RT5668_PDM_I2C_DATA_CTL3: -	case RT5668_PDM_I2C_DATA_CTL4: -	case RT5668_RECMIX1_NEW: -	case RT5668_RECMIX1L_0: -	case RT5668_RECMIX1L: -	case RT5668_RECMIX1R_0: -	case RT5668_RECMIX1R: -	case RT5668_RECMIX2_NEW: -	case RT5668_RECMIX2_L_2: -	case RT5668_RECMIX2_R: -	case RT5668_RECMIX2_R_2: -	case RT5668_CALIB_REC_LR: -	case RT5668_ALC_BK_GAIN: -	case RT5668_MONOMIX_GAIN: -	case RT5668_MONOMIX_IN_GAIN: -	case RT5668_OUT_MIXL_GAIN: -	case RT5668_OUT_LMIX_IN_GAIN: -	case RT5668_OUT_RMIX_IN_GAIN: -	case RT5668_OUT_RMIX_IN_GAIN1: -	case RT5668_LOUT_MIXER_CTRL: -	case RT5668_PWR_VOL: -	case RT5668_ADCDAC_RST: -	case RT5668_I2S34_SDP: -	case RT5668_I2S5_SDP: -	case RT5668_TDM_5: -	case RT5668_TDM_6: -	case RT5668_TDM_7: -	case RT5668_TDM_8: -	case RT5668_ASRC_3: -	case RT5668_ASRC_6: -	case RT5668_ASRC_7: -	case RT5668_PLL_TRK_13: -	case RT5668_I2S_M_CLK_CTL: -	case RT5668_FDIV_I2S34_M_CLK: -	case RT5668_FDIV_I2S34_M_CLK2: -	case RT5668_FDIV_I2S5_M_CLK: -	case RT5668_FDIV_I2S5_M_CLK2: -	case RT5668_IRQ_4: -	case RT5668_GPIO_3: -	case RT5668_GPIO_4: -	case RT5668_GPIO_STA: -	case RT5668_HP_AMP_DET1: -	case RT5668_HP_AMP_DET2: -	case RT5668_HP_AMP_DET3: -	case RT5668_MID_BD_HP_AMP: -	case RT5668_LOW_BD_HP_AMP: -	case RT5668_SOF_VOL_ZC2: -	case RT5668_ADC_STO2_ADJ1: -	case RT5668_ADC_STO2_ADJ2: -	case RT5668_A_JD_CTRL: -	case RT5668_JD1_TRES_CTRL: -	case RT5668_JD2_TRES_CTRL: -	case RT5668_JD_CTRL2: -	case RT5668_DUM_REG_2: -	case RT5668_DUM_REG_3: +	case RT5663_LOUT_CTRL: +	case RT5663_HP_AMP_2: +	case RT5663_MONO_OUT: +	case RT5663_MONO_GAIN: +	case RT5663_AEC_BST: +	case RT5663_IN1_IN2: +	case RT5663_IN3_IN4: +	case RT5663_INL1_INR1: +	case RT5663_CBJ_TYPE_2: +	case RT5663_CBJ_TYPE_3: +	case RT5663_CBJ_TYPE_4: +	case RT5663_CBJ_TYPE_5: +	case RT5663_CBJ_TYPE_8: +	case RT5663_DAC3_DIG_VOL: +	case RT5663_DAC3_CTRL: +	case RT5663_MONO_ADC_DIG_VOL: +	case RT5663_STO2_ADC_DIG_VOL: +	case RT5663_MONO_ADC_BST_GAIN: +	case RT5663_STO2_ADC_BST_GAIN: +	case RT5663_SIDETONE_CTRL: +	case RT5663_MONO1_ADC_MIXER: +	case RT5663_STO2_ADC_MIXER: +	case RT5663_MONO_DAC_MIXER: +	case RT5663_DAC2_SRC_CTRL: +	case RT5663_IF_3_4_DATA_CTL: +	case RT5663_IF_5_DATA_CTL: +	case RT5663_PDM_OUT_CTL: +	case RT5663_PDM_I2C_DATA_CTL1: +	case RT5663_PDM_I2C_DATA_CTL2: +	case RT5663_PDM_I2C_DATA_CTL3: +	case RT5663_PDM_I2C_DATA_CTL4: +	case RT5663_RECMIX1_NEW: +	case RT5663_RECMIX1L_0: +	case RT5663_RECMIX1L: +	case RT5663_RECMIX1R_0: +	case RT5663_RECMIX1R: +	case RT5663_RECMIX2_NEW: +	case RT5663_RECMIX2_L_2: +	case RT5663_RECMIX2_R: +	case RT5663_RECMIX2_R_2: +	case RT5663_CALIB_REC_LR: +	case RT5663_ALC_BK_GAIN: +	case RT5663_MONOMIX_GAIN: +	case RT5663_MONOMIX_IN_GAIN: +	case RT5663_OUT_MIXL_GAIN: +	case RT5663_OUT_LMIX_IN_GAIN: +	case RT5663_OUT_RMIX_IN_GAIN: +	case RT5663_OUT_RMIX_IN_GAIN1: +	case RT5663_LOUT_MIXER_CTRL: +	case RT5663_PWR_VOL: +	case RT5663_ADCDAC_RST: +	case RT5663_I2S34_SDP: +	case RT5663_I2S5_SDP: +	case RT5663_TDM_6: +	case RT5663_TDM_7: +	case RT5663_TDM_8: +	case RT5663_TDM_9: +	case RT5663_ASRC_3: +	case RT5663_ASRC_6: +	case RT5663_ASRC_7: +	case RT5663_PLL_TRK_13: +	case RT5663_I2S_M_CLK_CTL: +	case RT5663_FDIV_I2S34_M_CLK: +	case RT5663_FDIV_I2S34_M_CLK2: +	case RT5663_FDIV_I2S5_M_CLK: +	case RT5663_FDIV_I2S5_M_CLK2: +	case RT5663_V2_IRQ_4: +	case RT5663_GPIO_3: +	case RT5663_GPIO_4: +	case RT5663_GPIO_STA2: +	case RT5663_HP_AMP_DET1: +	case RT5663_HP_AMP_DET2: +	case RT5663_HP_AMP_DET3: +	case RT5663_MID_BD_HP_AMP: +	case RT5663_LOW_BD_HP_AMP: +	case RT5663_SOF_VOL_ZC2: +	case RT5663_ADC_STO2_ADJ1: +	case RT5663_ADC_STO2_ADJ2: +	case RT5663_A_JD_CTRL: +	case RT5663_JD1_TRES_CTRL: +	case RT5663_JD2_TRES_CTRL: +	case RT5663_V2_JD_CTRL2: +	case RT5663_DUM_REG_2: +	case RT5663_DUM_REG_3:  	case RT5663_VENDOR_ID:  	case RT5663_VENDOR_ID_1:  	case RT5663_VENDOR_ID_2: -	case RT5668_DACADC_DIG_VOL2: -	case RT5668_DIG_IN_PIN2: -	case RT5668_PAD_DRV_CTL1: -	case RT5668_SOF_RAM_DEPOP: -	case RT5668_VOL_TEST: -	case RT5668_TEST_MODE_3: -	case RT5668_TEST_MODE_4: +	case RT5663_DACADC_DIG_VOL2: +	case RT5663_DIG_IN_PIN2: +	case RT5663_PAD_DRV_CTL1: +	case RT5663_SOF_RAM_DEPOP: +	case RT5663_VOL_TEST: +	case RT5663_TEST_MODE_4: +	case RT5663_TEST_MODE_5:  	case RT5663_STO_DRE_9: -	case RT5668_MONO_DYNA_1: -	case RT5668_MONO_DYNA_2: -	case RT5668_MONO_DYNA_3: -	case RT5668_MONO_DYNA_4: -	case RT5668_MONO_DYNA_5: -	case RT5668_MONO_DYNA_6: -	case RT5668_STO1_SIL_DET: -	case RT5668_MONOL_SIL_DET: -	case RT5668_MONOR_SIL_DET: -	case RT5668_STO2_DAC_SIL: -	case RT5668_PWR_SAV_CTL1: -	case RT5668_PWR_SAV_CTL2: -	case RT5668_PWR_SAV_CTL3: -	case RT5668_PWR_SAV_CTL4: -	case RT5668_PWR_SAV_CTL5: -	case RT5668_PWR_SAV_CTL6: -	case RT5668_MONO_AMP_CAL1: -	case RT5668_MONO_AMP_CAL2: -	case RT5668_MONO_AMP_CAL3: -	case RT5668_MONO_AMP_CAL4: -	case RT5668_MONO_AMP_CAL5: -	case RT5668_MONO_AMP_CAL6: -	case RT5668_MONO_AMP_CAL7: -	case RT5668_MONO_AMP_CAL_ST1: -	case RT5668_MONO_AMP_CAL_ST2: -	case RT5668_MONO_AMP_CAL_ST3: -	case RT5668_MONO_AMP_CAL_ST4: -	case RT5668_MONO_AMP_CAL_ST5: -	case RT5668_HP_IMP_SEN_13: -	case RT5668_HP_IMP_SEN_14: -	case RT5668_HP_IMP_SEN_6: -	case RT5668_HP_IMP_SEN_7: -	case RT5668_HP_IMP_SEN_8: -	case RT5668_HP_IMP_SEN_9: -	case RT5668_HP_IMP_SEN_10: -	case RT5668_HP_LOGIC_3: -	case RT5668_HP_CALIB_ST10: -	case RT5668_HP_CALIB_ST11: -	case RT5668_PRO_REG_TBL_4: -	case RT5668_PRO_REG_TBL_5: -	case RT5668_PRO_REG_TBL_6: -	case RT5668_PRO_REG_TBL_7: -	case RT5668_PRO_REG_TBL_8: -	case RT5668_PRO_REG_TBL_9: -	case RT5668_SAR_ADC_INL_1: -	case RT5668_SAR_ADC_INL_2: -	case RT5668_SAR_ADC_INL_3: -	case RT5668_SAR_ADC_INL_4: -	case RT5668_SAR_ADC_INL_5: -	case RT5668_SAR_ADC_INL_6: -	case RT5668_SAR_ADC_INL_7: -	case RT5668_SAR_ADC_INL_8: -	case RT5668_SAR_ADC_INL_9: -	case RT5668_SAR_ADC_INL_10: -	case RT5668_SAR_ADC_INL_11: -	case RT5668_SAR_ADC_INL_12: -	case RT5668_DRC_CTRL_1: -	case RT5668_DRC1_CTRL_2: -	case RT5668_DRC1_CTRL_3: -	case RT5668_DRC1_CTRL_4: -	case RT5668_DRC1_CTRL_5: -	case RT5668_DRC1_CTRL_6: -	case RT5668_DRC1_HD_CTRL_1: -	case RT5668_DRC1_HD_CTRL_2: -	case RT5668_DRC1_PRI_REG_1: -	case RT5668_DRC1_PRI_REG_2: -	case RT5668_DRC1_PRI_REG_3: -	case RT5668_DRC1_PRI_REG_4: -	case RT5668_DRC1_PRI_REG_5: -	case RT5668_DRC1_PRI_REG_6: -	case RT5668_DRC1_PRI_REG_7: -	case RT5668_DRC1_PRI_REG_8: -	case RT5668_ALC_PGA_CTL_1: -	case RT5668_ALC_PGA_CTL_2: -	case RT5668_ALC_PGA_CTL_3: -	case RT5668_ALC_PGA_CTL_4: -	case RT5668_ALC_PGA_CTL_5: -	case RT5668_ALC_PGA_CTL_6: -	case RT5668_ALC_PGA_CTL_7: -	case RT5668_ALC_PGA_CTL_8: -	case RT5668_ALC_PGA_REG_1: -	case RT5668_ALC_PGA_REG_2: -	case RT5668_ALC_PGA_REG_3: -	case RT5668_ADC_EQ_RECOV_1: -	case RT5668_ADC_EQ_RECOV_2: -	case RT5668_ADC_EQ_RECOV_3: -	case RT5668_ADC_EQ_RECOV_4: -	case RT5668_ADC_EQ_RECOV_5: -	case RT5668_ADC_EQ_RECOV_6: -	case RT5668_ADC_EQ_RECOV_7: -	case RT5668_ADC_EQ_RECOV_8: -	case RT5668_ADC_EQ_RECOV_9: -	case RT5668_ADC_EQ_RECOV_10: -	case RT5668_ADC_EQ_RECOV_11: -	case RT5668_ADC_EQ_RECOV_12: -	case RT5668_ADC_EQ_RECOV_13: -	case RT5668_VID_HIDDEN: -	case RT5668_VID_CUSTOMER: -	case RT5668_SCAN_MODE: -	case RT5668_I2C_BYPA: +	case RT5663_MONO_DYNA_1: +	case RT5663_MONO_DYNA_2: +	case RT5663_MONO_DYNA_3: +	case RT5663_MONO_DYNA_4: +	case RT5663_MONO_DYNA_5: +	case RT5663_MONO_DYNA_6: +	case RT5663_STO1_SIL_DET: +	case RT5663_MONOL_SIL_DET: +	case RT5663_MONOR_SIL_DET: +	case RT5663_STO2_DAC_SIL: +	case RT5663_PWR_SAV_CTL1: +	case RT5663_PWR_SAV_CTL2: +	case RT5663_PWR_SAV_CTL3: +	case RT5663_PWR_SAV_CTL4: +	case RT5663_PWR_SAV_CTL5: +	case RT5663_PWR_SAV_CTL6: +	case RT5663_MONO_AMP_CAL1: +	case RT5663_MONO_AMP_CAL2: +	case RT5663_MONO_AMP_CAL3: +	case RT5663_MONO_AMP_CAL4: +	case RT5663_MONO_AMP_CAL5: +	case RT5663_MONO_AMP_CAL6: +	case RT5663_MONO_AMP_CAL7: +	case RT5663_MONO_AMP_CAL_ST1: +	case RT5663_MONO_AMP_CAL_ST2: +	case RT5663_MONO_AMP_CAL_ST3: +	case RT5663_MONO_AMP_CAL_ST4: +	case RT5663_MONO_AMP_CAL_ST5: +	case RT5663_V2_HP_IMP_SEN_13: +	case RT5663_V2_HP_IMP_SEN_14: +	case RT5663_V2_HP_IMP_SEN_6: +	case RT5663_V2_HP_IMP_SEN_7: +	case RT5663_V2_HP_IMP_SEN_8: +	case RT5663_V2_HP_IMP_SEN_9: +	case RT5663_V2_HP_IMP_SEN_10: +	case RT5663_HP_LOGIC_3: +	case RT5663_HP_CALIB_ST10: +	case RT5663_HP_CALIB_ST11: +	case RT5663_PRO_REG_TBL_4: +	case RT5663_PRO_REG_TBL_5: +	case RT5663_PRO_REG_TBL_6: +	case RT5663_PRO_REG_TBL_7: +	case RT5663_PRO_REG_TBL_8: +	case RT5663_PRO_REG_TBL_9: +	case RT5663_SAR_ADC_INL_1: +	case RT5663_SAR_ADC_INL_2: +	case RT5663_SAR_ADC_INL_3: +	case RT5663_SAR_ADC_INL_4: +	case RT5663_SAR_ADC_INL_5: +	case RT5663_SAR_ADC_INL_6: +	case RT5663_SAR_ADC_INL_7: +	case RT5663_SAR_ADC_INL_8: +	case RT5663_SAR_ADC_INL_9: +	case RT5663_SAR_ADC_INL_10: +	case RT5663_SAR_ADC_INL_11: +	case RT5663_SAR_ADC_INL_12: +	case RT5663_DRC_CTRL_1: +	case RT5663_DRC1_CTRL_2: +	case RT5663_DRC1_CTRL_3: +	case RT5663_DRC1_CTRL_4: +	case RT5663_DRC1_CTRL_5: +	case RT5663_DRC1_CTRL_6: +	case RT5663_DRC1_HD_CTRL_1: +	case RT5663_DRC1_HD_CTRL_2: +	case RT5663_DRC1_PRI_REG_1: +	case RT5663_DRC1_PRI_REG_2: +	case RT5663_DRC1_PRI_REG_3: +	case RT5663_DRC1_PRI_REG_4: +	case RT5663_DRC1_PRI_REG_5: +	case RT5663_DRC1_PRI_REG_6: +	case RT5663_DRC1_PRI_REG_7: +	case RT5663_DRC1_PRI_REG_8: +	case RT5663_ALC_PGA_CTL_1: +	case RT5663_ALC_PGA_CTL_2: +	case RT5663_ALC_PGA_CTL_3: +	case RT5663_ALC_PGA_CTL_4: +	case RT5663_ALC_PGA_CTL_5: +	case RT5663_ALC_PGA_CTL_6: +	case RT5663_ALC_PGA_CTL_7: +	case RT5663_ALC_PGA_CTL_8: +	case RT5663_ALC_PGA_REG_1: +	case RT5663_ALC_PGA_REG_2: +	case RT5663_ALC_PGA_REG_3: +	case RT5663_ADC_EQ_RECOV_1: +	case RT5663_ADC_EQ_RECOV_2: +	case RT5663_ADC_EQ_RECOV_3: +	case RT5663_ADC_EQ_RECOV_4: +	case RT5663_ADC_EQ_RECOV_5: +	case RT5663_ADC_EQ_RECOV_6: +	case RT5663_ADC_EQ_RECOV_7: +	case RT5663_ADC_EQ_RECOV_8: +	case RT5663_ADC_EQ_RECOV_9: +	case RT5663_ADC_EQ_RECOV_10: +	case RT5663_ADC_EQ_RECOV_11: +	case RT5663_ADC_EQ_RECOV_12: +	case RT5663_ADC_EQ_RECOV_13: +	case RT5663_VID_HIDDEN: +	case RT5663_VID_CUSTOMER: +	case RT5663_SCAN_MODE: +	case RT5663_I2C_BYPA:  		return true;  	case RT5663_TDM_1:  	case RT5663_DEPOP_3:  	case RT5663_ASRC_11_2:  	case RT5663_INT_ST_2: -	case RT5663_GPIO_STA: +	case RT5663_GPIO_STA1:  	case RT5663_SIN_GEN_1:  	case RT5663_SIN_GEN_2:  	case RT5663_SIN_GEN_3: @@ -1344,7 +1344,7 @@ static bool rt5668_readable_register(struct device *dev, unsigned int reg)  }  static const DECLARE_TLV_DB_SCALE(rt5663_hp_vol_tlv, -2400, 150, 0); -static const DECLARE_TLV_DB_SCALE(rt5668_hp_vol_tlv, -2250, 150, 0); +static const DECLARE_TLV_DB_SCALE(rt5663_v2_hp_vol_tlv, -2250, 150, 0);  static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0);  static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); @@ -1374,57 +1374,57 @@ static void rt5663_enable_push_button_irq(struct snd_soc_codec *codec,  	if (enable) {  		snd_soc_update_bits(codec, RT5663_IL_CMD_6, -			RT5668_EN_4BTN_INL_MASK, RT5668_EN_4BTN_INL_EN); +			RT5663_EN_4BTN_INL_MASK, RT5663_EN_4BTN_INL_EN);  		/* reset in-line command */  		snd_soc_update_bits(codec, RT5663_IL_CMD_6, -			RT5668_RESET_4BTN_INL_MASK, -			RT5668_RESET_4BTN_INL_RESET); +			RT5663_RESET_4BTN_INL_MASK, +			RT5663_RESET_4BTN_INL_RESET);  		snd_soc_update_bits(codec, RT5663_IL_CMD_6, -			RT5668_RESET_4BTN_INL_MASK, -			RT5668_RESET_4BTN_INL_NOR); -		switch (rt5663->codec_type) { -		case CODEC_TYPE_RT5668: +			RT5663_RESET_4BTN_INL_MASK, +			RT5663_RESET_4BTN_INL_NOR); +		switch (rt5663->codec_ver) { +		case CODEC_VER_1:  			snd_soc_update_bits(codec, RT5663_IRQ_3, -				RT5668_EN_IRQ_INLINE_MASK, -				RT5668_EN_IRQ_INLINE_NOR); +				RT5663_V2_EN_IRQ_INLINE_MASK, +				RT5663_V2_EN_IRQ_INLINE_NOR);  			break; -		case CODEC_TYPE_RT5663: +		case CODEC_VER_0:  			snd_soc_update_bits(codec, RT5663_IRQ_2,  				RT5663_EN_IRQ_INLINE_MASK,  				RT5663_EN_IRQ_INLINE_NOR);  			break;  		default: -			dev_err(codec->dev, "Unknown CODEC_TYPE\n"); +			dev_err(codec->dev, "Unknown CODEC Version\n");  		}  	} else { -		switch (rt5663->codec_type) { -		case CODEC_TYPE_RT5668: +		switch (rt5663->codec_ver) { +		case CODEC_VER_1:  			snd_soc_update_bits(codec, RT5663_IRQ_3, -				RT5668_EN_IRQ_INLINE_MASK, -				RT5668_EN_IRQ_INLINE_BYP); +				RT5663_V2_EN_IRQ_INLINE_MASK, +				RT5663_V2_EN_IRQ_INLINE_BYP);  			break; -		case CODEC_TYPE_RT5663: +		case CODEC_VER_0:  			snd_soc_update_bits(codec, RT5663_IRQ_2,  				RT5663_EN_IRQ_INLINE_MASK,  				RT5663_EN_IRQ_INLINE_BYP);  			break;  		default: -			dev_err(codec->dev, "Unknown CODEC_TYPE\n"); +			dev_err(codec->dev, "Unknown CODEC Version\n");  		}  		snd_soc_update_bits(codec, RT5663_IL_CMD_6, -			RT5668_EN_4BTN_INL_MASK, RT5668_EN_4BTN_INL_DIS); +			RT5663_EN_4BTN_INL_MASK, RT5663_EN_4BTN_INL_DIS);  		/* reset in-line command */  		snd_soc_update_bits(codec, RT5663_IL_CMD_6, -			RT5668_RESET_4BTN_INL_MASK, -			RT5668_RESET_4BTN_INL_RESET); +			RT5663_RESET_4BTN_INL_MASK, +			RT5663_RESET_4BTN_INL_RESET);  		snd_soc_update_bits(codec, RT5663_IL_CMD_6, -			RT5668_RESET_4BTN_INL_MASK, -			RT5668_RESET_4BTN_INL_NOR); +			RT5663_RESET_4BTN_INL_MASK, +			RT5663_RESET_4BTN_INL_NOR);  	}  }  /** - * rt5668_jack_detect - Detect headset. + * rt5663_v2_jack_detect - Detect headset.   * @codec: SoC audio codec device.   * @jack_insert: Jack insert or not.   * @@ -1433,16 +1433,16 @@ static void rt5663_enable_push_button_irq(struct snd_soc_codec *codec,   * Returns detect status.   */ -static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert) +static int rt5663_v2_jack_detect(struct snd_soc_codec *codec, int jack_insert)  {  	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); -	struct rt5663_priv *rt5668 = snd_soc_codec_get_drvdata(codec); +	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);  	int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30};  	dev_dbg(codec->dev, "%s jack_insert:%d\n", __func__, jack_insert);  	if (jack_insert) { -		snd_soc_write(codec, RT5668_CBJ_TYPE_2, 0x8040); -		snd_soc_write(codec, RT5668_CBJ_TYPE_3, 0x1484); +		snd_soc_write(codec, RT5663_CBJ_TYPE_2, 0x8040); +		snd_soc_write(codec, RT5663_CBJ_TYPE_3, 0x1484);  		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");  		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS2"); @@ -1450,12 +1450,12 @@ static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert)  		snd_soc_dapm_force_enable_pin(dapm, "CBJ Power");  		snd_soc_dapm_sync(dapm);  		snd_soc_update_bits(codec, RT5663_RC_CLK, -			RT5668_DIG_1M_CLK_MASK, RT5668_DIG_1M_CLK_EN); +			RT5663_DIG_1M_CLK_MASK, RT5663_DIG_1M_CLK_EN);  		snd_soc_update_bits(codec, RT5663_RECMIX, 0x8, 0x8);  		while (i < 5) {  			msleep(sleep_time[i]); -			val = snd_soc_read(codec, RT5668_CBJ_TYPE_2) & 0x0003; +			val = snd_soc_read(codec, RT5663_CBJ_TYPE_2) & 0x0003;  			if (val == 0x1 || val == 0x2 || val == 0x3)  				break;  			dev_dbg(codec->dev, "%s: MX-0011 val=%x sleep %d\n", @@ -1466,7 +1466,7 @@ static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert)  		switch (val) {  		case 1:  		case 2: -			rt5668->jack_type = SND_JACK_HEADSET; +			rt5663->jack_type = SND_JACK_HEADSET;  			rt5663_enable_push_button_irq(codec, true);  			break;  		default: @@ -1475,13 +1475,13 @@ static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert)  			snd_soc_dapm_disable_pin(dapm, "Mic Det Power");  			snd_soc_dapm_disable_pin(dapm, "CBJ Power");  			snd_soc_dapm_sync(dapm); -			rt5668->jack_type = SND_JACK_HEADPHONE; +			rt5663->jack_type = SND_JACK_HEADPHONE;  			break;  		}  	} else {  		snd_soc_update_bits(codec, RT5663_RECMIX, 0x8, 0x0); -		if (rt5668->jack_type == SND_JACK_HEADSET) { +		if (rt5663->jack_type == SND_JACK_HEADSET) {  			rt5663_enable_push_button_irq(codec, false);  			snd_soc_dapm_disable_pin(dapm, "MICBIAS1");  			snd_soc_dapm_disable_pin(dapm, "MICBIAS2"); @@ -1489,11 +1489,11 @@ static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert)  			snd_soc_dapm_disable_pin(dapm, "CBJ Power");  			snd_soc_dapm_sync(dapm);  		} -		rt5668->jack_type = 0; +		rt5663->jack_type = 0;  	} -	dev_dbg(codec->dev, "jack_type = %d\n", rt5668->jack_type); -	return rt5668->jack_type; +	dev_dbg(codec->dev, "jack_type = %d\n", rt5663->jack_type); +	return rt5663->jack_type;  }  /** @@ -1514,11 +1514,11 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)  	if (jack_insert) {  		snd_soc_update_bits(codec, RT5663_DIG_MISC, -			RT5668_DIG_GATE_CTRL_MASK, RT5668_DIG_GATE_CTRL_EN); +			RT5663_DIG_GATE_CTRL_MASK, RT5663_DIG_GATE_CTRL_EN);  		snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, -			RT5663_SI_HP_MASK | RT5668_OSW_HP_L_MASK | -			RT5668_OSW_HP_R_MASK, RT5663_SI_HP_EN | -			RT5668_OSW_HP_L_DIS | RT5668_OSW_HP_R_DIS); +			RT5663_SI_HP_MASK | RT5663_OSW_HP_L_MASK | +			RT5663_OSW_HP_R_MASK, RT5663_SI_HP_EN | +			RT5663_OSW_HP_L_DIS | RT5663_OSW_HP_R_DIS);  		snd_soc_update_bits(codec, RT5663_DUMMY_1,  			RT5663_EMB_CLK_MASK | RT5663_HPA_CPL_BIAS_MASK |  			RT5663_HPA_CPR_BIAS_MASK, RT5663_EMB_CLK_EN | @@ -1530,17 +1530,17 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)  			RT5663_PWR_MIC_DET_MASK, RT5663_PWR_MIC_DET_ON);  		/* BST1 power on for JD */  		snd_soc_update_bits(codec, RT5663_PWR_ANLG_2, -			RT5668_PWR_BST1_MASK, RT5668_PWR_BST1_ON); +			RT5663_PWR_BST1_MASK, RT5663_PWR_BST1_ON);  		snd_soc_update_bits(codec, RT5663_EM_JACK_TYPE_1,  			RT5663_CBJ_DET_MASK | RT5663_EXT_JD_MASK |  			RT5663_POL_EXT_JD_MASK, RT5663_CBJ_DET_EN |  			RT5663_EXT_JD_EN | RT5663_POL_EXT_JD_EN);  		snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, -			RT5668_PWR_MB_MASK | RT5668_LDO1_DVO_MASK | -			RT5668_AMP_HP_MASK, RT5668_PWR_MB | -			RT5668_LDO1_DVO_0_9V | RT5668_AMP_HP_3X); +			RT5663_PWR_MB_MASK | RT5663_LDO1_DVO_MASK | +			RT5663_AMP_HP_MASK, RT5663_PWR_MB | +			RT5663_LDO1_DVO_0_9V | RT5663_AMP_HP_3X);  		snd_soc_update_bits(codec, RT5663_AUTO_1MRC_CLK, -			RT5668_IRQ_POW_SAV_MASK, RT5668_IRQ_POW_SAV_EN); +			RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN);  		snd_soc_update_bits(codec, RT5663_IRQ_1,  			RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN);  		while (i < 5) { @@ -1619,13 +1619,13 @@ static bool rt5663_check_jd_status(struct snd_soc_codec *codec)  	dev_dbg(codec->dev, "%s val=%x\n", __func__, val);  	/* JD1 */ -	switch (rt5663->codec_type) { -	case CODEC_TYPE_RT5668: +	switch (rt5663->codec_ver) { +	case CODEC_VER_1:  		return !(val & 0x2000); -	case CODEC_TYPE_RT5663: +	case CODEC_VER_0:  		return !(val & 0x1000);  	default: -		dev_err(codec->dev, "Unknown CODEC_TYPE\n"); +		dev_err(codec->dev, "Unknown CODEC Version\n");  	}  	return false; @@ -1645,15 +1645,16 @@ static void rt5663_jack_detect_work(struct work_struct *work)  		/* jack in */  		if (rt5663->jack_type == 0) {  			/* jack was out, report jack type */ -			switch (rt5663->codec_type) { -			case CODEC_TYPE_RT5668: -				report = rt5668_jack_detect(rt5663->codec, 1); +			switch (rt5663->codec_ver) { +			case CODEC_VER_1: +				report = rt5663_v2_jack_detect( +						rt5663->codec, 1);  				break; -			case CODEC_TYPE_RT5663: +			case CODEC_VER_0:  				report = rt5663_jack_detect(rt5663->codec, 1);  				break;  			default: -				dev_err(codec->dev, "Unknown CODEC_TYPE\n"); +				dev_err(codec->dev, "Unknown CODEC Version\n");  			}  		} else {  			/* jack is already in, report button event */ @@ -1702,15 +1703,15 @@ static void rt5663_jack_detect_work(struct work_struct *work)  		}  	} else {  		/* jack out */ -		switch (rt5663->codec_type) { -		case CODEC_TYPE_RT5668: -			report = rt5668_jack_detect(rt5663->codec, 0); +		switch (rt5663->codec_ver) { +		case CODEC_VER_1: +			report = rt5663_v2_jack_detect(rt5663->codec, 0);  			break; -		case CODEC_TYPE_RT5663: +		case CODEC_VER_0:  			report = rt5663_jack_detect(rt5663->codec, 0);  			break;  		default: -			dev_err(codec->dev, "Unknown CODEC_TYPE\n"); +			dev_err(codec->dev, "Unknown CODEC Version\n");  		}  	}  	dev_dbg(codec->dev, "%s jack report: 0x%04x\n", __func__, report); @@ -1722,24 +1723,24 @@ static void rt5663_jack_detect_work(struct work_struct *work)  static const struct snd_kcontrol_new rt5663_snd_controls[] = {  	/* DAC Digital Volume */  	SOC_DOUBLE_TLV("DAC Playback Volume", RT5663_STO1_DAC_DIG_VOL, -		RT5668_DAC_L1_VOL_SHIFT + 1, RT5668_DAC_R1_VOL_SHIFT + 1, +		RT5663_DAC_L1_VOL_SHIFT + 1, RT5663_DAC_R1_VOL_SHIFT + 1,  		87, 0, dac_vol_tlv),  	/* ADC Digital Volume Control */  	SOC_DOUBLE("ADC Capture Switch", RT5663_STO1_ADC_DIG_VOL, -		RT5668_ADC_L_MUTE_SHIFT, RT5668_ADC_R_MUTE_SHIFT, 1, 1), +		RT5663_ADC_L_MUTE_SHIFT, RT5663_ADC_R_MUTE_SHIFT, 1, 1),  	SOC_DOUBLE_TLV("ADC Capture Volume", RT5663_STO1_ADC_DIG_VOL, -		RT5668_ADC_L_VOL_SHIFT + 1, RT5668_ADC_R_VOL_SHIFT + 1, +		RT5663_ADC_L_VOL_SHIFT + 1, RT5663_ADC_R_VOL_SHIFT + 1,  		63, 0, adc_vol_tlv),  }; -static const struct snd_kcontrol_new rt5668_specific_controls[] = { +static const struct snd_kcontrol_new rt5663_v2_specific_controls[] = {  	/* Headphone Output Volume */  	SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_HP_LCH_DRE, -		RT5663_HP_RCH_DRE, RT5668_GAIN_HP_SHIFT, 15, 1, -		rt5668_hp_vol_tlv), +		RT5663_HP_RCH_DRE, RT5663_GAIN_HP_SHIFT, 15, 1, +		rt5663_v2_hp_vol_tlv),  	/* Mic Boost Volume */ -	SOC_SINGLE_TLV("IN1 Capture Volume", RT5668_AEC_BST, -		RT5668_GAIN_CBJ_SHIFT, 8, 0, in_bst_tlv), +	SOC_SINGLE_TLV("IN1 Capture Volume", RT5663_AEC_BST, +		RT5663_GAIN_CBJ_SHIFT, 8, 0, in_bst_tlv),  };  static const struct snd_kcontrol_new rt5663_specific_controls[] = { @@ -1775,15 +1776,15 @@ static int rt5663_is_using_asrc(struct snd_soc_dapm_widget *w,  	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);  	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); -	if (rt5663->codec_type == CODEC_TYPE_RT5668) { +	if (rt5663->codec_ver == CODEC_VER_1) {  		switch (w->shift) { -		case RT5668_ADC_STO1_ASRC_SHIFT: -			reg = RT5668_ASRC_3; -			shift = RT5668_AD_STO1_TRACK_SHIFT; +		case RT5663_ADC_STO1_ASRC_SHIFT: +			reg = RT5663_ASRC_3; +			shift = RT5663_V2_AD_STO1_TRACK_SHIFT;  			break; -		case RT5668_DAC_STO1_ASRC_SHIFT: +		case RT5663_DAC_STO1_ASRC_SHIFT:  			reg = RT5663_ASRC_2; -			shift = RT5668_DA_STO1_TRACK_SHIFT; +			shift = RT5663_DA_STO1_TRACK_SHIFT;  			break;  		default:  			return 0; @@ -1820,17 +1821,17 @@ static int rt5663_i2s_use_asrc(struct snd_soc_dapm_widget *source,  	da_asrc_en = (snd_soc_read(codec, RT5663_ASRC_2) &  		RT5663_DA_STO1_TRACK_MASK) ? 1 : 0; -	switch (rt5663->codec_type) { -	case CODEC_TYPE_RT5668: -		ad_asrc_en = (snd_soc_read(codec, RT5668_ASRC_3) & -			RT5668_AD_STO1_TRACK_MASK) ? 1 : 0; +	switch (rt5663->codec_ver) { +	case CODEC_VER_1: +		ad_asrc_en = (snd_soc_read(codec, RT5663_ASRC_3) & +			RT5663_V2_AD_STO1_TRACK_MASK) ? 1 : 0;  		break; -	case CODEC_TYPE_RT5663: +	case CODEC_VER_0:  		ad_asrc_en = (snd_soc_read(codec, RT5663_ASRC_2) &  			RT5663_AD_STO1_TRACK_MASK) ? 1 : 0;  		break;  	default: -		dev_err(codec->dev, "Unknown CODEC_TYPE\n"); +		dev_err(codec->dev, "Unknown CODEC Version\n");  		return 1;  	} @@ -1849,7 +1850,7 @@ static int rt5663_i2s_use_asrc(struct snd_soc_dapm_widget *source,   * @filter_mask: mask of filters.   * @clk_src: clock source   * - * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5668 can + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5663 can   * only support standard 32fs or 64fs i2s format, ASRC should be enabled to   * support special i2s clock format such as Intel's 100fs(100 * sampling rate).   * ASRC function will track i2s clock and generate a corresponding system clock @@ -1860,7 +1861,7 @@ static int rt5663_i2s_use_asrc(struct snd_soc_dapm_widget *source,  int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec,  		unsigned int filter_mask, unsigned int clk_src)  { -	struct rt5663_priv *rt5668 = snd_soc_codec_get_drvdata(codec); +	struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);  	unsigned int asrc2_mask = 0;  	unsigned int asrc2_value = 0;  	unsigned int asrc3_mask = 0; @@ -1876,22 +1877,22 @@ int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec,  	}  	if (filter_mask & RT5663_DA_STEREO_FILTER) { -		asrc2_mask |= RT5668_DA_STO1_TRACK_MASK; -		asrc2_value |= clk_src << RT5668_DA_STO1_TRACK_SHIFT; +		asrc2_mask |= RT5663_DA_STO1_TRACK_MASK; +		asrc2_value |= clk_src << RT5663_DA_STO1_TRACK_SHIFT;  	}  	if (filter_mask & RT5663_AD_STEREO_FILTER) { -		switch (rt5668->codec_type) { -		case CODEC_TYPE_RT5668: -			asrc3_mask |= RT5668_AD_STO1_TRACK_MASK; -			asrc3_value |= clk_src << RT5668_AD_STO1_TRACK_SHIFT; +		switch (rt5663->codec_ver) { +		case CODEC_VER_1: +			asrc3_mask |= RT5663_V2_AD_STO1_TRACK_MASK; +			asrc3_value |= clk_src << RT5663_V2_AD_STO1_TRACK_SHIFT;  			break; -		case CODEC_TYPE_RT5663: +		case CODEC_VER_0:  			asrc2_mask |= RT5663_AD_STO1_TRACK_MASK;  			asrc2_value |= clk_src << RT5663_AD_STO1_TRACK_SHIFT;  			break;  		default: -			dev_err(codec->dev, "Unknown CODEC_TYPE\n"); +			dev_err(codec->dev, "Unknown CODEC Version\n");  		}  	} @@ -1900,7 +1901,7 @@ int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec,  			asrc2_value);  	if (asrc3_mask) -		snd_soc_update_bits(codec, RT5668_ASRC_3, asrc3_mask, +		snd_soc_update_bits(codec, RT5663_ASRC_3, asrc3_mask,  			asrc3_value);  	return 0; @@ -1908,82 +1909,82 @@ int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec,  EXPORT_SYMBOL_GPL(rt5663_sel_asrc_clk_src);  /* Analog Mixer */ -static const struct snd_kcontrol_new rt5668_recmix1l[] = { -	SOC_DAPM_SINGLE("BST2 Switch", RT5668_RECMIX1L, -		RT5668_RECMIX1L_BST2_SHIFT, 1, 1), -	SOC_DAPM_SINGLE("BST1 CBJ Switch", RT5668_RECMIX1L, -		RT5668_RECMIX1L_BST1_CBJ_SHIFT, 1, 1), +static const struct snd_kcontrol_new rt5663_recmix1l[] = { +	SOC_DAPM_SINGLE("BST2 Switch", RT5663_RECMIX1L, +		RT5663_RECMIX1L_BST2_SHIFT, 1, 1), +	SOC_DAPM_SINGLE("BST1 CBJ Switch", RT5663_RECMIX1L, +		RT5663_RECMIX1L_BST1_CBJ_SHIFT, 1, 1),  }; -static const struct snd_kcontrol_new rt5668_recmix1r[] = { -	SOC_DAPM_SINGLE("BST2 Switch", RT5668_RECMIX1R, -		RT5668_RECMIX1R_BST2_SHIFT, 1, 1), +static const struct snd_kcontrol_new rt5663_recmix1r[] = { +	SOC_DAPM_SINGLE("BST2 Switch", RT5663_RECMIX1R, +		RT5663_RECMIX1R_BST2_SHIFT, 1, 1),  };  /* Digital Mixer */  static const struct snd_kcontrol_new rt5663_sto1_adc_l_mix[] = {  	SOC_DAPM_SINGLE("ADC1 Switch", RT5663_STO1_ADC_MIXER, -			RT5668_M_STO1_ADC_L1_SHIFT, 1, 1), +			RT5663_M_STO1_ADC_L1_SHIFT, 1, 1),  	SOC_DAPM_SINGLE("ADC2 Switch", RT5663_STO1_ADC_MIXER, -			RT5668_M_STO1_ADC_L2_SHIFT, 1, 1), +			RT5663_M_STO1_ADC_L2_SHIFT, 1, 1),  }; -static const struct snd_kcontrol_new rt5668_sto1_adc_r_mix[] = { +static const struct snd_kcontrol_new rt5663_sto1_adc_r_mix[] = {  	SOC_DAPM_SINGLE("ADC1 Switch", RT5663_STO1_ADC_MIXER, -			RT5668_M_STO1_ADC_R1_SHIFT, 1, 1), +			RT5663_M_STO1_ADC_R1_SHIFT, 1, 1),  	SOC_DAPM_SINGLE("ADC2 Switch", RT5663_STO1_ADC_MIXER, -			RT5668_M_STO1_ADC_R2_SHIFT, 1, 1), +			RT5663_M_STO1_ADC_R2_SHIFT, 1, 1),  };  static const struct snd_kcontrol_new rt5663_adda_l_mix[] = {  	SOC_DAPM_SINGLE("ADC L Switch", RT5663_AD_DA_MIXER, -			RT5668_M_ADCMIX_L_SHIFT, 1, 1), +			RT5663_M_ADCMIX_L_SHIFT, 1, 1),  	SOC_DAPM_SINGLE("DAC L Switch", RT5663_AD_DA_MIXER, -			RT5668_M_DAC1_L_SHIFT, 1, 1), +			RT5663_M_DAC1_L_SHIFT, 1, 1),  };  static const struct snd_kcontrol_new rt5663_adda_r_mix[] = {  	SOC_DAPM_SINGLE("ADC R Switch", RT5663_AD_DA_MIXER, -			RT5668_M_ADCMIX_R_SHIFT, 1, 1), +			RT5663_M_ADCMIX_R_SHIFT, 1, 1),  	SOC_DAPM_SINGLE("DAC R Switch", RT5663_AD_DA_MIXER, -			RT5668_M_DAC1_R_SHIFT, 1, 1), +			RT5663_M_DAC1_R_SHIFT, 1, 1),  };  static const struct snd_kcontrol_new rt5663_sto1_dac_l_mix[] = {  	SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER, -			RT5668_M_DAC_L1_STO_L_SHIFT, 1, 1), +			RT5663_M_DAC_L1_STO_L_SHIFT, 1, 1),  	SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER, -			RT5668_M_DAC_R1_STO_L_SHIFT, 1, 1), +			RT5663_M_DAC_R1_STO_L_SHIFT, 1, 1),  };  static const struct snd_kcontrol_new rt5663_sto1_dac_r_mix[] = {  	SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER, -			RT5668_M_DAC_L1_STO_R_SHIFT, 1, 1), +			RT5663_M_DAC_L1_STO_R_SHIFT, 1, 1),  	SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER, -			RT5668_M_DAC_R1_STO_R_SHIFT, 1, 1), +			RT5663_M_DAC_R1_STO_R_SHIFT, 1, 1),  };  /* Out Switch */ -static const struct snd_kcontrol_new rt5668_hpo_switch = -	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5668_HP_AMP_2, -		RT5668_EN_DAC_HPO_SHIFT, 1, 0); +static const struct snd_kcontrol_new rt5663_hpo_switch = +	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5663_HP_AMP_2, +		RT5663_EN_DAC_HPO_SHIFT, 1, 0);  /* Stereo ADC source */ -static const char * const rt5668_sto1_adc_src[] = { +static const char * const rt5663_sto1_adc_src[] = {  	"ADC L", "ADC R"  }; -static SOC_ENUM_SINGLE_DECL(rt5668_sto1_adcl_enum, RT5663_STO1_ADC_MIXER, -	RT5668_STO1_ADC_L_SRC_SHIFT, rt5668_sto1_adc_src); +static SOC_ENUM_SINGLE_DECL(rt5663_sto1_adcl_enum, RT5663_STO1_ADC_MIXER, +	RT5663_STO1_ADC_L_SRC_SHIFT, rt5663_sto1_adc_src); -static const struct snd_kcontrol_new rt5668_sto1_adcl_mux = -	SOC_DAPM_ENUM("STO1 ADC L Mux", rt5668_sto1_adcl_enum); +static const struct snd_kcontrol_new rt5663_sto1_adcl_mux = +	SOC_DAPM_ENUM("STO1 ADC L Mux", rt5663_sto1_adcl_enum); -static SOC_ENUM_SINGLE_DECL(rt5668_sto1_adcr_enum, RT5663_STO1_ADC_MIXER, -	RT5668_STO1_ADC_R_SRC_SHIFT, rt5668_sto1_adc_src); +static SOC_ENUM_SINGLE_DECL(rt5663_sto1_adcr_enum, RT5663_STO1_ADC_MIXER, +	RT5663_STO1_ADC_R_SRC_SHIFT, rt5663_sto1_adc_src); -static const struct snd_kcontrol_new rt5668_sto1_adcr_mux = -	SOC_DAPM_ENUM("STO1 ADC R Mux", rt5668_sto1_adcr_enum); +static const struct snd_kcontrol_new rt5663_sto1_adcr_mux = +	SOC_DAPM_ENUM("STO1 ADC R Mux", rt5663_sto1_adcr_enum);  /* RT5663: Analog DACL1 input source */  static const char * const rt5663_alg_dacl_src[] = { @@ -2015,12 +2016,12 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,  	switch (event) {  	case SND_SOC_DAPM_POST_PMU: -		if (rt5663->codec_type == CODEC_TYPE_RT5668) { +		if (rt5663->codec_ver == CODEC_VER_1) {  			snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, -				RT5668_SEL_PM_HP_SHIFT, RT5668_SEL_PM_HP_HIGH); +				RT5663_SEL_PM_HP_SHIFT, RT5663_SEL_PM_HP_HIGH);  			snd_soc_update_bits(codec, RT5663_HP_LOGIC_2, -				RT5668_HP_SIG_SRC1_MASK, -				RT5668_HP_SIG_SRC1_SILENCE); +				RT5663_HP_SIG_SRC1_MASK, +				RT5663_HP_SIG_SRC1_SILENCE);  		} else {  			snd_soc_write(codec, RT5663_DEPOP_2, 0x3003);  			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b, @@ -2028,7 +2029,7 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,  			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030,  				0x0030);  			snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, -				RT5668_OVCD_HP_MASK, RT5668_OVCD_HP_DIS); +				RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_DIS);  			snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_2, 0x1371);  			snd_soc_write(codec, RT5663_HP_BIAS, 0xabba);  			snd_soc_write(codec, RT5663_CHARGE_PUMP_1, 0x2224); @@ -2041,14 +2042,14 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,  		break;  	case SND_SOC_DAPM_PRE_PMD: -		if (rt5663->codec_type == CODEC_TYPE_RT5668) { +		if (rt5663->codec_ver == CODEC_VER_1) {  			snd_soc_update_bits(codec, RT5663_HP_LOGIC_2, -				RT5668_HP_SIG_SRC1_MASK, -				RT5668_HP_SIG_SRC1_REG); +				RT5663_HP_SIG_SRC1_MASK, +				RT5663_HP_SIG_SRC1_REG);  		} else {  			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0x0);  			snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, -				RT5668_OVCD_HP_MASK, RT5668_OVCD_HP_EN); +				RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_EN);  			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0x0);  			snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b,  				0x000b); @@ -2062,7 +2063,7 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w,  	return 0;  } -static int rt5668_bst2_power(struct snd_soc_dapm_widget *w, +static int rt5663_bst2_power(struct snd_soc_dapm_widget *w,  	struct snd_kcontrol *kcontrol, int event)  {  	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); @@ -2070,13 +2071,13 @@ static int rt5668_bst2_power(struct snd_soc_dapm_widget *w,  	switch (event) {  	case SND_SOC_DAPM_POST_PMU:  		snd_soc_update_bits(codec, RT5663_PWR_ANLG_2, -			RT5668_PWR_BST2_MASK | RT5668_PWR_BST2_OP_MASK, -			RT5668_PWR_BST2 | RT5668_PWR_BST2_OP); +			RT5663_PWR_BST2_MASK | RT5663_PWR_BST2_OP_MASK, +			RT5663_PWR_BST2 | RT5663_PWR_BST2_OP);  		break;  	case SND_SOC_DAPM_PRE_PMD:  		snd_soc_update_bits(codec, RT5663_PWR_ANLG_2, -			RT5668_PWR_BST2_MASK | RT5668_PWR_BST2_OP_MASK, 0); +			RT5663_PWR_BST2_MASK | RT5663_PWR_BST2_OP_MASK, 0);  		break;  	default: @@ -2110,14 +2111,14 @@ static int rt5663_pre_div_power(struct snd_soc_dapm_widget *w,  }  static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = { -	SND_SOC_DAPM_SUPPLY("PLL", RT5663_PWR_ANLG_3, RT5668_PWR_PLL_SHIFT, 0, +	SND_SOC_DAPM_SUPPLY("PLL", RT5663_PWR_ANLG_3, RT5663_PWR_PLL_SHIFT, 0,  		NULL, 0),  	/* micbias */  	SND_SOC_DAPM_MICBIAS("MICBIAS1", RT5663_PWR_ANLG_2, -		RT5668_PWR_MB1_SHIFT, 0), +		RT5663_PWR_MB1_SHIFT, 0),  	SND_SOC_DAPM_MICBIAS("MICBIAS2", RT5663_PWR_ANLG_2, -		RT5668_PWR_MB2_SHIFT, 0), +		RT5663_PWR_MB2_SHIFT, 0),  	/* Input Lines */  	SND_SOC_DAPM_INPUT("IN1P"), @@ -2125,14 +2126,14 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = {  	/* REC Mixer Power */  	SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5663_PWR_ANLG_2, -		RT5668_PWR_RECMIX1_SHIFT, 0, NULL, 0), +		RT5663_PWR_RECMIX1_SHIFT, 0, NULL, 0),  	/* ADCs */  	SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),  	SND_SOC_DAPM_SUPPLY("ADC L Power", RT5663_PWR_DIG_1, -		RT5668_PWR_ADC_L1_SHIFT, 0, NULL, 0), +		RT5663_PWR_ADC_L1_SHIFT, 0, NULL, 0),  	SND_SOC_DAPM_SUPPLY("ADC Clock", RT5663_CHOP_ADC, -		RT5668_CKGEN_ADCC_SHIFT, 0, NULL, 0), +		RT5663_CKGEN_ADCC_SHIFT, 0, NULL, 0),  	/* ADC Mixer */  	SND_SOC_DAPM_MIXER("STO1 ADC MIXL", SND_SOC_NOPM, @@ -2141,10 +2142,10 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = {  	/* ADC Filter Power */  	SND_SOC_DAPM_SUPPLY("STO1 ADC Filter", RT5663_PWR_DIG_2, -		RT5668_PWR_ADC_S1F_SHIFT, 0, NULL, 0), +		RT5663_PWR_ADC_S1F_SHIFT, 0, NULL, 0),  	/* Digital Interface */ -	SND_SOC_DAPM_SUPPLY("I2S", RT5663_PWR_DIG_1, RT5668_PWR_I2S1_SHIFT, 0, +	SND_SOC_DAPM_SUPPLY("I2S", RT5663_PWR_DIG_1, RT5663_PWR_I2S1_SHIFT, 0,  		NULL, 0),  	SND_SOC_DAPM_PGA("IF DAC", SND_SOC_NOPM, 0, 0, NULL, 0),  	SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -2166,7 +2167,7 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = {  	/* DAC Mixer */  	SND_SOC_DAPM_SUPPLY("STO1 DAC Filter", RT5663_PWR_DIG_2, -		RT5668_PWR_DAC_S1F_SHIFT, 0, NULL, 0), +		RT5663_PWR_DAC_S1F_SHIFT, 0, NULL, 0),  	SND_SOC_DAPM_MIXER("STO1 DAC MIXL", SND_SOC_NOPM, 0, 0,  		rt5663_sto1_dac_l_mix, ARRAY_SIZE(rt5663_sto1_dac_l_mix)),  	SND_SOC_DAPM_MIXER("STO1 DAC MIXR", SND_SOC_NOPM, 0, 0, @@ -2174,9 +2175,9 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = {  	/* DACs */  	SND_SOC_DAPM_SUPPLY("STO1 DAC L Power", RT5663_PWR_DIG_1, -		RT5668_PWR_DAC_L1_SHIFT, 0, NULL, 0), +		RT5663_PWR_DAC_L1_SHIFT, 0, NULL, 0),  	SND_SOC_DAPM_SUPPLY("STO1 DAC R Power", RT5663_PWR_DIG_1, -		RT5668_PWR_DAC_R1_SHIFT, 0, NULL, 0), +		RT5663_PWR_DAC_R1_SHIFT, 0, NULL, 0),  	SND_SOC_DAPM_DAC("DAC L", NULL, SND_SOC_NOPM, 0, 0),  	SND_SOC_DAPM_DAC("DAC R", NULL, SND_SOC_NOPM, 0, 0), @@ -2189,21 +2190,21 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = {  	SND_SOC_DAPM_OUTPUT("HPOR"),  }; -static const struct snd_soc_dapm_widget rt5668_specific_dapm_widgets[] = { +static const struct snd_soc_dapm_widget rt5663_v2_specific_dapm_widgets[] = {  	SND_SOC_DAPM_SUPPLY("LDO2", RT5663_PWR_ANLG_3, -		RT5668_PWR_LDO2_SHIFT, 0, NULL, 0), -	SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5668_PWR_VOL, -		RT5668_PWR_MIC_DET_SHIFT, 0, NULL, 0), +		RT5663_PWR_LDO2_SHIFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5663_PWR_VOL, +		RT5663_V2_PWR_MIC_DET_SHIFT, 0, NULL, 0),  	SND_SOC_DAPM_SUPPLY("LDO DAC", RT5663_PWR_DIG_1, -		RT5668_PWR_LDO_DACREF_SHIFT, 0, NULL, 0), +		RT5663_PWR_LDO_DACREF_SHIFT, 0, NULL, 0),  	/* ASRC */  	SND_SOC_DAPM_SUPPLY("I2S ASRC", RT5663_ASRC_1, -		RT5668_I2S1_ASRC_SHIFT, 0, NULL, 0), +		RT5663_I2S1_ASRC_SHIFT, 0, NULL, 0),  	SND_SOC_DAPM_SUPPLY("DAC ASRC", RT5663_ASRC_1, -		RT5668_DAC_STO1_ASRC_SHIFT, 0, NULL, 0), +		RT5663_DAC_STO1_ASRC_SHIFT, 0, NULL, 0),  	SND_SOC_DAPM_SUPPLY("ADC ASRC", RT5663_ASRC_1, -		RT5668_ADC_STO1_ASRC_SHIFT, 0, NULL, 0), +		RT5663_ADC_STO1_ASRC_SHIFT, 0, NULL, 0),  	/* Input Lines */  	SND_SOC_DAPM_INPUT("IN2P"), @@ -2212,51 +2213,51 @@ static const struct snd_soc_dapm_widget rt5668_specific_dapm_widgets[] = {  	/* Boost */  	SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM, 0, 0, NULL, 0),  	SND_SOC_DAPM_SUPPLY("CBJ Power", RT5663_PWR_ANLG_3, -		RT5668_PWR_CBJ_SHIFT, 0, NULL, 0), +		RT5663_PWR_CBJ_SHIFT, 0, NULL, 0),  	SND_SOC_DAPM_PGA("BST2", SND_SOC_NOPM, 0, 0, NULL, 0),  	SND_SOC_DAPM_SUPPLY("BST2 Power", SND_SOC_NOPM, 0, 0, -		rt5668_bst2_power, SND_SOC_DAPM_PRE_PMD | +		rt5663_bst2_power, SND_SOC_DAPM_PRE_PMD |  		SND_SOC_DAPM_POST_PMU),  	/* REC Mixer */ -	SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5668_recmix1l, -		ARRAY_SIZE(rt5668_recmix1l)), -	SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5668_recmix1r, -		ARRAY_SIZE(rt5668_recmix1r)), +	SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5663_recmix1l, +		ARRAY_SIZE(rt5663_recmix1l)), +	SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5663_recmix1r, +		ARRAY_SIZE(rt5663_recmix1r)),  	SND_SOC_DAPM_SUPPLY("RECMIX1R Power", RT5663_PWR_ANLG_2, -		RT5668_PWR_RECMIX2_SHIFT, 0, NULL, 0), +		RT5663_PWR_RECMIX2_SHIFT, 0, NULL, 0),  	/* ADC */  	SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),  	SND_SOC_DAPM_SUPPLY("ADC R Power", RT5663_PWR_DIG_1, -		RT5668_PWR_ADC_R1_SHIFT, 0, NULL, 0), +		RT5663_PWR_ADC_R1_SHIFT, 0, NULL, 0),  	/* ADC Mux */  	SND_SOC_DAPM_PGA("STO1 ADC L1", RT5663_STO1_ADC_MIXER, -		RT5668_STO1_ADC_L1_SRC_SHIFT, 0, NULL, 0), +		RT5663_STO1_ADC_L1_SRC_SHIFT, 0, NULL, 0),  	SND_SOC_DAPM_PGA("STO1 ADC R1", RT5663_STO1_ADC_MIXER, -		RT5668_STO1_ADC_R1_SRC_SHIFT, 0, NULL, 0), +		RT5663_STO1_ADC_R1_SRC_SHIFT, 0, NULL, 0),  	SND_SOC_DAPM_PGA("STO1 ADC L2", RT5663_STO1_ADC_MIXER, -		RT5668_STO1_ADC_L2_SRC_SHIFT, 1, NULL, 0), +		RT5663_STO1_ADC_L2_SRC_SHIFT, 1, NULL, 0),  	SND_SOC_DAPM_PGA("STO1 ADC R2", RT5663_STO1_ADC_MIXER, -		RT5668_STO1_ADC_R2_SRC_SHIFT, 1, NULL, 0), +		RT5663_STO1_ADC_R2_SRC_SHIFT, 1, NULL, 0),  	SND_SOC_DAPM_MUX("STO1 ADC L Mux", SND_SOC_NOPM, 0, 0, -		&rt5668_sto1_adcl_mux), +		&rt5663_sto1_adcl_mux),  	SND_SOC_DAPM_MUX("STO1 ADC R Mux", SND_SOC_NOPM, 0, 0, -		&rt5668_sto1_adcr_mux), +		&rt5663_sto1_adcr_mux),  	/* ADC Mix */  	SND_SOC_DAPM_MIXER("STO1 ADC MIXR", SND_SOC_NOPM, 0, 0, -		rt5668_sto1_adc_r_mix, ARRAY_SIZE(rt5668_sto1_adc_r_mix)), +		rt5663_sto1_adc_r_mix, ARRAY_SIZE(rt5663_sto1_adc_r_mix)),  	/* Analog DAC Clock */  	SND_SOC_DAPM_SUPPLY("DAC Clock", RT5663_CHOP_DAC_L, -		RT5668_CKGEN_DAC1_SHIFT, 0, NULL, 0), +		RT5663_CKGEN_DAC1_SHIFT, 0, NULL, 0),  	/* Headphone out */  	SND_SOC_DAPM_SWITCH("HPO Playback", SND_SOC_NOPM, 0, 0, -		&rt5668_hpo_switch), +		&rt5663_hpo_switch),  };  static const struct snd_soc_dapm_widget rt5663_specific_dapm_widgets[] = { @@ -2267,7 +2268,7 @@ static const struct snd_soc_dapm_widget rt5663_specific_dapm_widgets[] = {  	/* LDO */  	SND_SOC_DAPM_SUPPLY("LDO ADC", RT5663_PWR_DIG_1, -		RT5668_PWR_LDO_DACREF_SHIFT, 0, NULL, 0), +		RT5663_PWR_LDO_DACREF_SHIFT, 0, NULL, 0),  	/* ASRC */  	SND_SOC_DAPM_SUPPLY("I2S ASRC", RT5663_ASRC_1, @@ -2341,7 +2342,7 @@ static const struct snd_soc_dapm_route rt5663_dapm_routes[] = {  	{ "HP Amp", NULL, "DAC R" },  }; -static const struct snd_soc_dapm_route rt5668_specific_dapm_routes[] = { +static const struct snd_soc_dapm_route rt5663_v2_specific_dapm_routes[] = {  	{ "MICBIAS1", NULL, "LDO2" },  	{ "MICBIAS2", NULL, "LDO2" }, @@ -2440,26 +2441,26 @@ static int rt5663_hw_params(struct snd_pcm_substream *substream,  	switch (params_width(params)) {  	case 8: -		val_len = RT5668_I2S_DL_8; +		val_len = RT5663_I2S_DL_8;  		break;  	case 16: -		val_len = RT5668_I2S_DL_16; +		val_len = RT5663_I2S_DL_16;  		break;  	case 20: -		val_len = RT5668_I2S_DL_20; +		val_len = RT5663_I2S_DL_20;  		break;  	case 24: -		val_len = RT5668_I2S_DL_24; +		val_len = RT5663_I2S_DL_24;  		break;  	default:  		return -EINVAL;  	}  	snd_soc_update_bits(codec, RT5663_I2S1_SDP, -		RT5668_I2S_DL_MASK, val_len); +		RT5663_I2S_DL_MASK, val_len);  	snd_soc_update_bits(codec, RT5663_ADDA_CLK_1, -		RT5668_I2S_PD1_MASK, pre_div << RT5668_I2S_PD1_SHIFT); +		RT5663_I2S_PD1_MASK, pre_div << RT5663_I2S_PD1_SHIFT);  	return 0;  } @@ -2473,7 +2474,7 @@ static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)  	case SND_SOC_DAIFMT_CBM_CFM:  		break;  	case SND_SOC_DAIFMT_CBS_CFS: -		reg_val |= RT5668_I2S_MS_S; +		reg_val |= RT5663_I2S_MS_S;  		break;  	default:  		return -EINVAL; @@ -2483,7 +2484,7 @@ static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)  	case SND_SOC_DAIFMT_NB_NF:  		break;  	case SND_SOC_DAIFMT_IB_NF: -		reg_val |= RT5668_I2S_BP_INV; +		reg_val |= RT5663_I2S_BP_INV;  		break;  	default:  		return -EINVAL; @@ -2493,20 +2494,20 @@ static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)  	case SND_SOC_DAIFMT_I2S:  		break;  	case SND_SOC_DAIFMT_LEFT_J: -		reg_val |= RT5668_I2S_DF_LEFT; +		reg_val |= RT5663_I2S_DF_LEFT;  		break;  	case SND_SOC_DAIFMT_DSP_A: -		reg_val |= RT5668_I2S_DF_PCM_A; +		reg_val |= RT5663_I2S_DF_PCM_A;  		break;  	case SND_SOC_DAIFMT_DSP_B: -		reg_val |= RT5668_I2S_DF_PCM_B; +		reg_val |= RT5663_I2S_DF_PCM_B;  		break;  	default:  		return -EINVAL;  	} -	snd_soc_update_bits(codec, RT5663_I2S1_SDP, RT5668_I2S_MS_MASK | -		RT5668_I2S_BP_MASK | RT5668_I2S_DF_MASK, reg_val); +	snd_soc_update_bits(codec, RT5663_I2S1_SDP, RT5663_I2S_MS_MASK | +		RT5663_I2S_BP_MASK | RT5663_I2S_DF_MASK, reg_val);  	return 0;  } @@ -2535,7 +2536,7 @@ static int rt5663_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,  		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);  		return -EINVAL;  	} -	snd_soc_update_bits(codec, RT5663_GLB_CLK, RT5668_SCLK_SRC_MASK, +	snd_soc_update_bits(codec, RT5663_GLB_CLK, RT5663_SCLK_SRC_MASK,  		reg_val);  	rt5663->sysclk = freq;  	rt5663->sysclk_src = clk_id; @@ -2569,17 +2570,17 @@ static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,  		return 0;  	} -	switch (rt5663->codec_type) { -	case CODEC_TYPE_RT5668: -		mask = RT5668_PLL1_SRC_MASK; -		shift = RT5668_PLL1_SRC_SHIFT; +	switch (rt5663->codec_ver) { +	case CODEC_VER_1: +		mask = RT5663_V2_PLL1_SRC_MASK; +		shift = RT5663_V2_PLL1_SRC_SHIFT;  		break; -	case CODEC_TYPE_RT5663: +	case CODEC_VER_0:  		mask = RT5663_PLL1_SRC_MASK;  		shift = RT5663_PLL1_SRC_SHIFT;  		break;  	default: -		dev_err(codec->dev, "Unknown CODEC_TYPE\n"); +		dev_err(codec->dev, "Unknown CODEC Version\n");  		return -EINVAL;  	} @@ -2607,10 +2608,10 @@ static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,  		pll_code.k_code);  	snd_soc_write(codec, RT5663_PLL_1, -		pll_code.n_code << RT5668_PLL_N_SHIFT | pll_code.k_code); +		pll_code.n_code << RT5663_PLL_N_SHIFT | pll_code.k_code);  	snd_soc_write(codec, RT5663_PLL_2, -		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5668_PLL_M_SHIFT | -		pll_code.m_bp << RT5668_PLL_M_BP_SHIFT); +		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5663_PLL_M_SHIFT | +		pll_code.m_bp << RT5663_PLL_M_BP_SHIFT);  	rt5663->pll_in = freq_in;  	rt5663->pll_out = freq_out; @@ -2627,20 +2628,20 @@ static int rt5663_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,  	unsigned int val = 0, reg;  	if (rx_mask || tx_mask) -		val |= RT5668_TDM_MODE_TDM; +		val |= RT5663_TDM_MODE_TDM;  	switch (slots) {  	case 4: -		val |= RT5668_TDM_IN_CH_4; -		val |= RT5668_TDM_OUT_CH_4; +		val |= RT5663_TDM_IN_CH_4; +		val |= RT5663_TDM_OUT_CH_4;  		break;  	case 6: -		val |= RT5668_TDM_IN_CH_6; -		val |= RT5668_TDM_OUT_CH_6; +		val |= RT5663_TDM_IN_CH_6; +		val |= RT5663_TDM_OUT_CH_6;  		break;  	case 8: -		val |= RT5668_TDM_IN_CH_8; -		val |= RT5668_TDM_OUT_CH_8; +		val |= RT5663_TDM_IN_CH_8; +		val |= RT5663_TDM_OUT_CH_8;  		break;  	case 2:  		break; @@ -2650,16 +2651,16 @@ static int rt5663_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,  	switch (slot_width) {  	case 20: -		val |= RT5668_TDM_IN_LEN_20; -		val |= RT5668_TDM_OUT_LEN_20; +		val |= RT5663_TDM_IN_LEN_20; +		val |= RT5663_TDM_OUT_LEN_20;  		break;  	case 24: -		val |= RT5668_TDM_IN_LEN_24; -		val |= RT5668_TDM_OUT_LEN_24; +		val |= RT5663_TDM_IN_LEN_24; +		val |= RT5663_TDM_OUT_LEN_24;  		break;  	case 32: -		val |= RT5668_TDM_IN_LEN_32; -		val |= RT5668_TDM_OUT_LEN_32; +		val |= RT5663_TDM_IN_LEN_32; +		val |= RT5663_TDM_OUT_LEN_32;  		break;  	case 16:  		break; @@ -2667,21 +2668,21 @@ static int rt5663_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,  		return -EINVAL;  	} -	switch (rt5663->codec_type) { -	case CODEC_TYPE_RT5668: +	switch (rt5663->codec_ver) { +	case CODEC_VER_1:  		reg = RT5663_TDM_2;  		break; -	case CODEC_TYPE_RT5663: +	case CODEC_VER_0:  		reg = RT5663_TDM_1;  		break;  	default: -		dev_err(codec->dev, "Unknown CODEC_TYPE\n"); +		dev_err(codec->dev, "Unknown CODEC Version\n");  		return -EINVAL;  	} -	snd_soc_update_bits(codec, reg, RT5668_TDM_MODE_MASK | -		RT5668_TDM_IN_CH_MASK | RT5668_TDM_OUT_CH_MASK | -		RT5668_TDM_IN_LEN_MASK | RT5668_TDM_OUT_LEN_MASK, val); +	snd_soc_update_bits(codec, reg, RT5663_TDM_MODE_MASK | +		RT5663_TDM_IN_CH_MASK | RT5663_TDM_OUT_CH_MASK | +		RT5663_TDM_IN_LEN_MASK | RT5663_TDM_OUT_LEN_MASK, val);  	return 0;  } @@ -2694,8 +2695,8 @@ static int rt5663_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)  	dev_dbg(codec->dev, "%s ratio = %d\n", __func__, ratio); -	if (rt5663->codec_type == CODEC_TYPE_RT5668) -		reg = RT5668_TDM_8; +	if (rt5663->codec_ver == CODEC_VER_1) +		reg = RT5663_TDM_9;  	else  		reg = RT5663_TDM_5; @@ -2736,47 +2737,47 @@ static int rt5663_set_bias_level(struct snd_soc_codec *codec,  	switch (level) {  	case SND_SOC_BIAS_ON:  		snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, -			RT5668_PWR_FV1_MASK | RT5668_PWR_FV2_MASK, -			RT5668_PWR_FV1 | RT5668_PWR_FV2); +			RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK, +			RT5663_PWR_FV1 | RT5663_PWR_FV2);  		break;  	case SND_SOC_BIAS_PREPARE: -		if (rt5663->codec_type == CODEC_TYPE_RT5668) { +		if (rt5663->codec_ver == CODEC_VER_1) {  			snd_soc_update_bits(codec, RT5663_DIG_MISC, -				RT5668_DIG_GATE_CTRL_MASK, -				RT5668_DIG_GATE_CTRL_EN); +				RT5663_DIG_GATE_CTRL_MASK, +				RT5663_DIG_GATE_CTRL_EN);  			snd_soc_update_bits(codec, RT5663_SIG_CLK_DET, -				RT5668_EN_ANA_CLK_DET_MASK | -				RT5668_PWR_CLK_DET_MASK, -				RT5668_EN_ANA_CLK_DET_AUTO | -				RT5668_PWR_CLK_DET_EN); +				RT5663_EN_ANA_CLK_DET_MASK | +				RT5663_PWR_CLK_DET_MASK, +				RT5663_EN_ANA_CLK_DET_AUTO | +				RT5663_PWR_CLK_DET_EN);  		}  		break;  	case SND_SOC_BIAS_STANDBY: -		if (rt5663->codec_type == CODEC_TYPE_RT5668) +		if (rt5663->codec_ver == CODEC_VER_1)  			snd_soc_update_bits(codec, RT5663_DIG_MISC, -				RT5668_DIG_GATE_CTRL_MASK, -				RT5668_DIG_GATE_CTRL_DIS); +				RT5663_DIG_GATE_CTRL_MASK, +				RT5663_DIG_GATE_CTRL_DIS);  		snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, -			RT5668_PWR_VREF1_MASK | RT5668_PWR_VREF2_MASK | -			RT5668_PWR_FV1_MASK | RT5668_PWR_FV2_MASK | -			RT5668_PWR_MB_MASK, RT5668_PWR_VREF1 | -			RT5668_PWR_VREF2 | RT5668_PWR_MB); +			RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK | +			RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK | +			RT5663_PWR_MB_MASK, RT5663_PWR_VREF1 | +			RT5663_PWR_VREF2 | RT5663_PWR_MB);  		usleep_range(10000, 10005); -		if (rt5663->codec_type == CODEC_TYPE_RT5668) { +		if (rt5663->codec_ver == CODEC_VER_1) {  			snd_soc_update_bits(codec, RT5663_SIG_CLK_DET, -				RT5668_EN_ANA_CLK_DET_MASK | -				RT5668_PWR_CLK_DET_MASK, -				RT5668_EN_ANA_CLK_DET_DIS | -				RT5668_PWR_CLK_DET_DIS); +				RT5663_EN_ANA_CLK_DET_MASK | +				RT5663_PWR_CLK_DET_MASK, +				RT5663_EN_ANA_CLK_DET_DIS | +				RT5663_PWR_CLK_DET_DIS);  		}  		break;  	case SND_SOC_BIAS_OFF:  		snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, -			RT5668_PWR_VREF1_MASK | RT5668_PWR_VREF2_MASK | -			RT5668_PWR_FV1 | RT5668_PWR_FV2, 0x0); +			RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK | +			RT5663_PWR_FV1 | RT5663_PWR_FV2, 0x0);  		break;  	default: @@ -2793,18 +2794,18 @@ static int rt5663_probe(struct snd_soc_codec *codec)  	rt5663->codec = codec; -	switch (rt5663->codec_type) { -	case CODEC_TYPE_RT5668: +	switch (rt5663->codec_ver) { +	case CODEC_VER_1:  		snd_soc_dapm_new_controls(dapm, -			rt5668_specific_dapm_widgets, -			ARRAY_SIZE(rt5668_specific_dapm_widgets)); +			rt5663_v2_specific_dapm_widgets, +			ARRAY_SIZE(rt5663_v2_specific_dapm_widgets));  		snd_soc_dapm_add_routes(dapm, -			rt5668_specific_dapm_routes, -			ARRAY_SIZE(rt5668_specific_dapm_routes)); -		snd_soc_add_codec_controls(codec, rt5668_specific_controls, -			ARRAY_SIZE(rt5668_specific_controls)); +			rt5663_v2_specific_dapm_routes, +			ARRAY_SIZE(rt5663_v2_specific_dapm_routes)); +		snd_soc_add_codec_controls(codec, rt5663_v2_specific_controls, +			ARRAY_SIZE(rt5663_v2_specific_controls));  		break; -	case CODEC_TYPE_RT5663: +	case CODEC_VER_0:  		snd_soc_dapm_new_controls(dapm,  			rt5663_specific_dapm_widgets,  			ARRAY_SIZE(rt5663_specific_dapm_widgets)); @@ -2905,16 +2906,16 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5663 = {  	}  }; -static const struct regmap_config rt5668_regmap = { +static const struct regmap_config rt5663_v2_regmap = {  	.reg_bits = 16,  	.val_bits = 16,  	.use_single_rw = true,  	.max_register = 0x07fa, -	.volatile_reg = rt5668_volatile_register, -	.readable_reg = rt5668_readable_register, +	.volatile_reg = rt5663_v2_volatile_register, +	.readable_reg = rt5663_v2_readable_register,  	.cache_type = REGCACHE_RBTREE, -	.reg_defaults = rt5668_reg, -	.num_reg_defaults = ARRAY_SIZE(rt5668_reg), +	.reg_defaults = rt5663_v2_reg, +	.num_reg_defaults = ARRAY_SIZE(rt5663_v2_reg),  };  static const struct regmap_config rt5663_regmap = { @@ -2939,7 +2940,6 @@ static const struct regmap_config temp_regmap = {  };  static const struct i2c_device_id rt5663_i2c_id[] = { -	{ "rt5668", 0 },  	{ "rt5663", 0 },  	{}  }; @@ -2947,7 +2947,6 @@ MODULE_DEVICE_TABLE(i2c, rt5663_i2c_id);  #if defined(CONFIG_OF)  static const struct of_device_id rt5663_of_match[] = { -	{ .compatible = "realtek,rt5668", },  	{ .compatible = "realtek,rt5663", },  	{},  }; @@ -2956,80 +2955,79 @@ MODULE_DEVICE_TABLE(of, rt5663_of_match);  #ifdef CONFIG_ACPI  static struct acpi_device_id rt5663_acpi_match[] = { -	{ "10EC5668", 0},  	{ "10EC5663", 0},  	{},  };  MODULE_DEVICE_TABLE(acpi, rt5663_acpi_match);  #endif -static void rt5668_calibrate(struct rt5663_priv *rt5668) +static void rt5663_v2_calibrate(struct rt5663_priv *rt5663)  { -	regmap_write(rt5668->regmap, RT5663_BIAS_CUR_8, 0xa402); -	regmap_write(rt5668->regmap, RT5663_PWR_DIG_1, 0x0100); -	regmap_write(rt5668->regmap, RT5663_RECMIX, 0x4040); -	regmap_write(rt5668->regmap, RT5663_DIG_MISC, 0x0001); -	regmap_write(rt5668->regmap, RT5663_RC_CLK, 0x0380); -	regmap_write(rt5668->regmap, RT5663_GLB_CLK, 0x8000); -	regmap_write(rt5668->regmap, RT5663_ADDA_CLK_1, 0x1000); -	regmap_write(rt5668->regmap, RT5663_CHOP_DAC_L, 0x3030); -	regmap_write(rt5668->regmap, RT5663_CALIB_ADC, 0x3c05); -	regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xa23e); +	regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0xa402); +	regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x0100); +	regmap_write(rt5663->regmap, RT5663_RECMIX, 0x4040); +	regmap_write(rt5663->regmap, RT5663_DIG_MISC, 0x0001); +	regmap_write(rt5663->regmap, RT5663_RC_CLK, 0x0380); +	regmap_write(rt5663->regmap, RT5663_GLB_CLK, 0x8000); +	regmap_write(rt5663->regmap, RT5663_ADDA_CLK_1, 0x1000); +	regmap_write(rt5663->regmap, RT5663_CHOP_DAC_L, 0x3030); +	regmap_write(rt5663->regmap, RT5663_CALIB_ADC, 0x3c05); +	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa23e);  	msleep(40); -	regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xf23e); -	regmap_write(rt5668->regmap, RT5663_HP_CALIB_2, 0x0321); -	regmap_write(rt5668->regmap, RT5663_HP_CALIB_1, 0xfc00); +	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf23e); +	regmap_write(rt5663->regmap, RT5663_HP_CALIB_2, 0x0321); +	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1, 0xfc00);  	msleep(500);  } -static void rt5663_calibrate(struct rt5663_priv *rt5668) +static void rt5663_calibrate(struct rt5663_priv *rt5663)  {  	int value, count; -	regmap_write(rt5668->regmap, RT5663_RC_CLK, 0x0280); -	regmap_write(rt5668->regmap, RT5663_GLB_CLK, 0x8000); -	regmap_write(rt5668->regmap, RT5663_DIG_MISC, 0x8001); -	regmap_write(rt5668->regmap, RT5663_VREF_RECMIX, 0x0032); -	regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xa2be); +	regmap_write(rt5663->regmap, RT5663_RC_CLK, 0x0280); +	regmap_write(rt5663->regmap, RT5663_GLB_CLK, 0x8000); +	regmap_write(rt5663->regmap, RT5663_DIG_MISC, 0x8001); +	regmap_write(rt5663->regmap, RT5663_VREF_RECMIX, 0x0032); +	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa2be);  	msleep(20); -	regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xf2be); -	regmap_write(rt5668->regmap, RT5663_PWR_DIG_2, 0x8400); -	regmap_write(rt5668->regmap, RT5663_CHOP_ADC, 0x3000); -	regmap_write(rt5668->regmap, RT5663_DEPOP_1, 0x003b); -	regmap_write(rt5668->regmap, RT5663_PWR_DIG_1, 0x8df8); -	regmap_write(rt5668->regmap, RT5663_PWR_ANLG_2, 0x0003); -	regmap_write(rt5668->regmap, RT5663_PWR_ANLG_3, 0x018c); -	regmap_write(rt5668->regmap, RT5663_ADDA_CLK_1, 0x1111); -	regmap_write(rt5668->regmap, RT5663_PRE_DIV_GATING_1, 0xffff); -	regmap_write(rt5668->regmap, RT5663_PRE_DIV_GATING_2, 0xffff); -	regmap_write(rt5668->regmap, RT5663_DEPOP_2, 0x3003); -	regmap_write(rt5668->regmap, RT5663_DEPOP_1, 0x003b); -	regmap_write(rt5668->regmap, RT5663_HP_CHARGE_PUMP_1, 0x1e32); -	regmap_write(rt5668->regmap, RT5663_HP_CHARGE_PUMP_2, 0x1371); -	regmap_write(rt5668->regmap, RT5663_DACREF_LDO, 0x3b0b); -	regmap_write(rt5668->regmap, RT5663_STO_DAC_MIXER, 0x2080); -	regmap_write(rt5668->regmap, RT5663_BYPASS_STO_DAC, 0x000c); -	regmap_write(rt5668->regmap, RT5663_HP_BIAS, 0xabba); -	regmap_write(rt5668->regmap, RT5663_CHARGE_PUMP_1, 0x2224); -	regmap_write(rt5668->regmap, RT5663_HP_OUT_EN, 0x8088); -	regmap_write(rt5668->regmap, RT5663_STO_DRE_9, 0x0017); -	regmap_write(rt5668->regmap, RT5663_STO_DRE_10, 0x0017); -	regmap_write(rt5668->regmap, RT5663_STO1_ADC_MIXER, 0x4040); -	regmap_write(rt5668->regmap, RT5663_RECMIX, 0x0005); -	regmap_write(rt5668->regmap, RT5663_ADDA_RST, 0xc000); -	regmap_write(rt5668->regmap, RT5663_STO1_HPF_ADJ1, 0x3320); -	regmap_write(rt5668->regmap, RT5663_HP_CALIB_2, 0x00c9); -	regmap_write(rt5668->regmap, RT5663_DUMMY_1, 0x004c); -	regmap_write(rt5668->regmap, RT5663_ANA_BIAS_CUR_1, 0x7766); -	regmap_write(rt5668->regmap, RT5663_BIAS_CUR_8, 0x4702); +	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf2be); +	regmap_write(rt5663->regmap, RT5663_PWR_DIG_2, 0x8400); +	regmap_write(rt5663->regmap, RT5663_CHOP_ADC, 0x3000); +	regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x003b); +	regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x8df8); +	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x0003); +	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_3, 0x018c); +	regmap_write(rt5663->regmap, RT5663_ADDA_CLK_1, 0x1111); +	regmap_write(rt5663->regmap, RT5663_PRE_DIV_GATING_1, 0xffff); +	regmap_write(rt5663->regmap, RT5663_PRE_DIV_GATING_2, 0xffff); +	regmap_write(rt5663->regmap, RT5663_DEPOP_2, 0x3003); +	regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x003b); +	regmap_write(rt5663->regmap, RT5663_HP_CHARGE_PUMP_1, 0x1e32); +	regmap_write(rt5663->regmap, RT5663_HP_CHARGE_PUMP_2, 0x1371); +	regmap_write(rt5663->regmap, RT5663_DACREF_LDO, 0x3b0b); +	regmap_write(rt5663->regmap, RT5663_STO_DAC_MIXER, 0x2080); +	regmap_write(rt5663->regmap, RT5663_BYPASS_STO_DAC, 0x000c); +	regmap_write(rt5663->regmap, RT5663_HP_BIAS, 0xabba); +	regmap_write(rt5663->regmap, RT5663_CHARGE_PUMP_1, 0x2224); +	regmap_write(rt5663->regmap, RT5663_HP_OUT_EN, 0x8088); +	regmap_write(rt5663->regmap, RT5663_STO_DRE_9, 0x0017); +	regmap_write(rt5663->regmap, RT5663_STO_DRE_10, 0x0017); +	regmap_write(rt5663->regmap, RT5663_STO1_ADC_MIXER, 0x4040); +	regmap_write(rt5663->regmap, RT5663_RECMIX, 0x0005); +	regmap_write(rt5663->regmap, RT5663_ADDA_RST, 0xc000); +	regmap_write(rt5663->regmap, RT5663_STO1_HPF_ADJ1, 0x3320); +	regmap_write(rt5663->regmap, RT5663_HP_CALIB_2, 0x00c9); +	regmap_write(rt5663->regmap, RT5663_DUMMY_1, 0x004c); +	regmap_write(rt5663->regmap, RT5663_ANA_BIAS_CUR_1, 0x7766); +	regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0x4702);  	msleep(200); -	regmap_write(rt5668->regmap, RT5663_HP_CALIB_1, 0x0069); -	regmap_write(rt5668->regmap, RT5663_HP_CALIB_3, 0x06c2); -	regmap_write(rt5668->regmap, RT5663_HP_CALIB_1_1, 0x7b00); -	regmap_write(rt5668->regmap, RT5663_HP_CALIB_1_1, 0xfb00); +	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1, 0x0069); +	regmap_write(rt5663->regmap, RT5663_HP_CALIB_3, 0x06c2); +	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0x7b00); +	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0xfb00);  	count = 0;  	while (true) { -		regmap_read(rt5668->regmap, RT5663_HP_CALIB_1_1, &value); +		regmap_read(rt5663->regmap, RT5663_HP_CALIB_1_1, &value);  		if (value & 0x8000)  			usleep_range(10000, 10005);  		else @@ -3066,17 +3064,17 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,  	}  	regmap_read(regmap, RT5663_VENDOR_ID_2, &val);  	switch (val) { -	case RT5668_DEVICE_ID: -		rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5668_regmap); -		rt5663->codec_type = CODEC_TYPE_RT5668; +	case RT5663_DEVICE_ID_2: +		rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5663_v2_regmap); +		rt5663->codec_ver = CODEC_VER_1;  		break; -	case RT5663_DEVICE_ID: +	case RT5663_DEVICE_ID_1:  		rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5663_regmap); -		rt5663->codec_type = CODEC_TYPE_RT5663; +		rt5663->codec_ver = CODEC_VER_0;  		break;  	default:  		dev_err(&i2c->dev, -			"Device with ID register %#x is not rt5663 or rt5668\n", +			"Device with ID register %#x is not rt5663\n",  			val);  		return -ENODEV;  	} @@ -3091,11 +3089,11 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,  	/* reset and calibrate */  	regmap_write(rt5663->regmap, RT5663_RESET, 0);  	regcache_cache_bypass(rt5663->regmap, true); -	switch (rt5663->codec_type) { -	case CODEC_TYPE_RT5668: -		rt5668_calibrate(rt5663); +	switch (rt5663->codec_ver) { +	case CODEC_VER_1: +		rt5663_v2_calibrate(rt5663);  		break; -	case CODEC_TYPE_RT5663: +	case CODEC_VER_0:  		rt5663_calibrate(rt5663);  		break;  	default: @@ -3106,46 +3104,55 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,  	dev_dbg(&i2c->dev, "calibrate done\n");  	/* GPIO1 as IRQ */ -	regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, RT5668_GP1_PIN_MASK, -		RT5668_GP1_PIN_IRQ); +	regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, RT5663_GP1_PIN_MASK, +		RT5663_GP1_PIN_IRQ);  	/* 4btn inline command debounce */  	regmap_update_bits(rt5663->regmap, RT5663_IL_CMD_5, -		RT5668_4BTN_CLK_DEB_MASK, RT5668_4BTN_CLK_DEB_65MS); +		RT5663_4BTN_CLK_DEB_MASK, RT5663_4BTN_CLK_DEB_65MS); -	switch (rt5663->codec_type) { -	case CODEC_TYPE_RT5668: +	switch (rt5663->codec_ver) { +	case CODEC_VER_1:  		regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0xa402);  		/* JD1 */  		regmap_update_bits(rt5663->regmap, RT5663_AUTO_1MRC_CLK, -			RT5668_IRQ_POW_SAV_MASK | RT5668_IRQ_POW_SAV_JD1_MASK, -			RT5668_IRQ_POW_SAV_EN | RT5668_IRQ_POW_SAV_JD1_EN); +			RT5663_IRQ_POW_SAV_MASK | RT5663_IRQ_POW_SAV_JD1_MASK, +			RT5663_IRQ_POW_SAV_EN | RT5663_IRQ_POW_SAV_JD1_EN);  		regmap_update_bits(rt5663->regmap, RT5663_PWR_ANLG_2, -			RT5668_PWR_JD1_MASK, RT5668_PWR_JD1); +			RT5663_PWR_JD1_MASK, RT5663_PWR_JD1);  		regmap_update_bits(rt5663->regmap, RT5663_IRQ_1, -			RT5668_EN_CB_JD_MASK, RT5668_EN_CB_JD_EN); +			RT5663_EN_CB_JD_MASK, RT5663_EN_CB_JD_EN);  		regmap_update_bits(rt5663->regmap, RT5663_HP_LOGIC_2, -			RT5668_HP_SIG_SRC1_MASK, RT5668_HP_SIG_SRC1_REG); +			RT5663_HP_SIG_SRC1_MASK, RT5663_HP_SIG_SRC1_REG);  		regmap_update_bits(rt5663->regmap, RT5663_RECMIX, -			RT5668_VREF_BIAS_MASK | RT5668_CBJ_DET_MASK | -			RT5668_DET_TYPE_MASK, RT5668_VREF_BIAS_REG | -			RT5668_CBJ_DET_EN | RT5668_DET_TYPE_QFN); +			RT5663_VREF_BIAS_MASK | RT5663_CBJ_DET_MASK | +			RT5663_DET_TYPE_MASK, RT5663_VREF_BIAS_REG | +			RT5663_CBJ_DET_EN | RT5663_DET_TYPE_QFN);  		/* Set GPIO4 and GPIO8 as input for combo jack */  		regmap_update_bits(rt5663->regmap, RT5663_GPIO_2, -			RT5668_GP4_PIN_CONF_MASK, RT5668_GP4_PIN_CONF_INPUT); -		regmap_update_bits(rt5663->regmap, RT5668_GPIO_3, -			RT5668_GP8_PIN_CONF_MASK, RT5668_GP8_PIN_CONF_INPUT); +			RT5663_GP4_PIN_CONF_MASK, RT5663_GP4_PIN_CONF_INPUT); +		regmap_update_bits(rt5663->regmap, RT5663_GPIO_3, +			RT5663_GP8_PIN_CONF_MASK, RT5663_GP8_PIN_CONF_INPUT);  		regmap_update_bits(rt5663->regmap, RT5663_PWR_ANLG_1, -			RT5668_LDO1_DVO_MASK | RT5668_AMP_HP_MASK, -			RT5668_LDO1_DVO_0_9V | RT5668_AMP_HP_3X); +			RT5663_LDO1_DVO_MASK | RT5663_AMP_HP_MASK, +			RT5663_LDO1_DVO_0_9V | RT5663_AMP_HP_3X);  			break; -	case CODEC_TYPE_RT5663: +	case CODEC_VER_0: +		regmap_update_bits(rt5663->regmap, RT5663_DIG_MISC, +			RT5663_DIG_GATE_CTRL_MASK, RT5663_DIG_GATE_CTRL_EN); +		regmap_update_bits(rt5663->regmap, RT5663_AUTO_1MRC_CLK, +			RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN); +		regmap_update_bits(rt5663->regmap, RT5663_IRQ_1, +			RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN); +		regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, +			RT5663_GPIO1_TYPE_MASK, RT5663_GPIO1_TYPE_EN);  		regmap_write(rt5663->regmap, RT5663_VREF_RECMIX, 0x0032);  		regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa2be);  		msleep(20);  		regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf2be);  		regmap_update_bits(rt5663->regmap, RT5663_GPIO_2, -			RT5663_GP1_PIN_CONF_MASK, RT5663_GP1_PIN_CONF_OUTPUT); +			RT5663_GP1_PIN_CONF_MASK | RT5663_SEL_GPIO1_MASK, +			RT5663_GP1_PIN_CONF_OUTPUT | RT5663_SEL_GPIO1_EN);  		/* DACREF LDO control */  		regmap_update_bits(rt5663->regmap, RT5663_DACREF_LDO, 0x3e0e,  			0x3a0a); diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h index 2cc8f28080f6..d77fae619f2f 100644 --- a/sound/soc/codecs/rt5663.h +++ b/sound/soc/codecs/rt5663.h @@ -18,655 +18,652 @@  #define RT5663_VENDOR_ID_1			0x00fe  #define RT5663_VENDOR_ID_2			0x00ff -#define RT5668_LOUT_CTRL			0x0001 -#define RT5668_HP_AMP_2				0x0003 -#define RT5668_MONO_OUT				0x0004 -#define RT5668_MONO_GAIN			0x0007 - -#define RT5668_AEC_BST				0x000b -#define RT5668_IN1_IN2				0x000c -#define RT5668_IN3_IN4				0x000d -#define RT5668_INL1_INR1			0x000f -#define RT5668_CBJ_TYPE_2			0x0011 -#define RT5668_CBJ_TYPE_3			0x0012 -#define RT5668_CBJ_TYPE_4			0x0013 -#define RT5668_CBJ_TYPE_5			0x0014 -#define RT5668_CBJ_TYPE_8			0x0017 +#define RT5663_LOUT_CTRL			0x0001 +#define RT5663_HP_AMP_2				0x0003 +#define RT5663_MONO_OUT				0x0004 +#define RT5663_MONO_GAIN			0x0007 + +#define RT5663_AEC_BST				0x000b +#define RT5663_IN1_IN2				0x000c +#define RT5663_IN3_IN4				0x000d +#define RT5663_INL1_INR1			0x000f +#define RT5663_CBJ_TYPE_2			0x0011 +#define RT5663_CBJ_TYPE_3			0x0012 +#define RT5663_CBJ_TYPE_4			0x0013 +#define RT5663_CBJ_TYPE_5			0x0014 +#define RT5663_CBJ_TYPE_8			0x0017  /* I/O - ADC/DAC/DMIC */ -#define RT5668_DAC3_DIG_VOL			0x001a -#define RT5668_DAC3_CTRL			0x001b -#define RT5668_MONO_ADC_DIG_VOL			0x001d -#define RT5668_STO2_ADC_DIG_VOL			0x001e -#define RT5668_MONO_ADC_BST_GAIN		0x0020 -#define RT5668_STO2_ADC_BST_GAIN		0x0021 -#define RT5668_SIDETONE_CTRL			0x0024 +#define RT5663_DAC3_DIG_VOL			0x001a +#define RT5663_DAC3_CTRL			0x001b +#define RT5663_MONO_ADC_DIG_VOL			0x001d +#define RT5663_STO2_ADC_DIG_VOL			0x001e +#define RT5663_MONO_ADC_BST_GAIN		0x0020 +#define RT5663_STO2_ADC_BST_GAIN		0x0021 +#define RT5663_SIDETONE_CTRL			0x0024  /* Mixer - D-D */ -#define RT5668_MONO1_ADC_MIXER			0x0027 -#define RT5668_STO2_ADC_MIXER			0x0028 -#define RT5668_MONO_DAC_MIXER			0x002b -#define RT5668_DAC2_SRC_CTRL			0x002e -#define RT5668_IF_3_4_DATA_CTL			0x002f -#define RT5668_IF_5_DATA_CTL			0x0030 -#define RT5668_PDM_OUT_CTL			0x0031 -#define RT5668_PDM_I2C_DATA_CTL1		0x0032 -#define RT5668_PDM_I2C_DATA_CTL2		0x0033 -#define RT5668_PDM_I2C_DATA_CTL3		0x0034 -#define RT5668_PDM_I2C_DATA_CTL4		0x0035 +#define RT5663_MONO1_ADC_MIXER			0x0027 +#define RT5663_STO2_ADC_MIXER			0x0028 +#define RT5663_MONO_DAC_MIXER			0x002b +#define RT5663_DAC2_SRC_CTRL			0x002e +#define RT5663_IF_3_4_DATA_CTL			0x002f +#define RT5663_IF_5_DATA_CTL			0x0030 +#define RT5663_PDM_OUT_CTL			0x0031 +#define RT5663_PDM_I2C_DATA_CTL1		0x0032 +#define RT5663_PDM_I2C_DATA_CTL2		0x0033 +#define RT5663_PDM_I2C_DATA_CTL3		0x0034 +#define RT5663_PDM_I2C_DATA_CTL4		0x0035  /*Mixer - Analog*/ -#define RT5668_RECMIX1_NEW			0x003a -#define RT5668_RECMIX1L_0			0x003b -#define RT5668_RECMIX1L				0x003c -#define RT5668_RECMIX1R_0			0x003d -#define RT5668_RECMIX1R				0x003e -#define RT5668_RECMIX2_NEW			0x003f -#define RT5668_RECMIX2_L_2			0x0041 -#define RT5668_RECMIX2_R			0x0042 -#define RT5668_RECMIX2_R_2			0x0043 -#define RT5668_CALIB_REC_LR			0x0044 -#define RT5668_ALC_BK_GAIN			0x0049 -#define RT5668_MONOMIX_GAIN			0x004a -#define RT5668_MONOMIX_IN_GAIN			0x004b -#define RT5668_OUT_MIXL_GAIN			0x004d -#define RT5668_OUT_LMIX_IN_GAIN			0x004e -#define RT5668_OUT_RMIX_IN_GAIN			0x004f -#define RT5668_OUT_RMIX_IN_GAIN1		0x0050 -#define RT5668_LOUT_MIXER_CTRL			0x0052 +#define RT5663_RECMIX1_NEW			0x003a +#define RT5663_RECMIX1L_0			0x003b +#define RT5663_RECMIX1L				0x003c +#define RT5663_RECMIX1R_0			0x003d +#define RT5663_RECMIX1R				0x003e +#define RT5663_RECMIX2_NEW			0x003f +#define RT5663_RECMIX2_L_2			0x0041 +#define RT5663_RECMIX2_R			0x0042 +#define RT5663_RECMIX2_R_2			0x0043 +#define RT5663_CALIB_REC_LR			0x0044 +#define RT5663_ALC_BK_GAIN			0x0049 +#define RT5663_MONOMIX_GAIN			0x004a +#define RT5663_MONOMIX_IN_GAIN			0x004b +#define RT5663_OUT_MIXL_GAIN			0x004d +#define RT5663_OUT_LMIX_IN_GAIN			0x004e +#define RT5663_OUT_RMIX_IN_GAIN			0x004f +#define RT5663_OUT_RMIX_IN_GAIN1		0x0050 +#define RT5663_LOUT_MIXER_CTRL			0x0052  /* Power */ -#define RT5668_PWR_VOL				0x0067 +#define RT5663_PWR_VOL				0x0067 -#define RT5668_ADCDAC_RST			0x006d +#define RT5663_ADCDAC_RST			0x006d  /* Format - ADC/DAC */ -#define RT5668_I2S34_SDP			0x0071 -#define RT5668_I2S5_SDP				0x0072 -/* Format - TDM Control */ -#define RT5668_TDM_5				0x007c -#define RT5668_TDM_6				0x007d -#define RT5668_TDM_7				0x007e -#define RT5668_TDM_8				0x007f +#define RT5663_I2S34_SDP			0x0071 +#define RT5663_I2S5_SDP				0x0072  /* Function - Analog */ -#define RT5668_ASRC_3				0x0085 -#define RT5668_ASRC_6				0x0088 -#define RT5668_ASRC_7				0x0089 -#define RT5668_PLL_TRK_13			0x0099 -#define RT5668_I2S_M_CLK_CTL			0x00a0 -#define RT5668_FDIV_I2S34_M_CLK			0x00a1 -#define RT5668_FDIV_I2S34_M_CLK2		0x00a2 -#define RT5668_FDIV_I2S5_M_CLK			0x00a3 -#define RT5668_FDIV_I2S5_M_CLK2			0x00a4 +#define RT5663_ASRC_3				0x0085 +#define RT5663_ASRC_6				0x0088 +#define RT5663_ASRC_7				0x0089 +#define RT5663_PLL_TRK_13			0x0099 +#define RT5663_I2S_M_CLK_CTL			0x00a0 +#define RT5663_FDIV_I2S34_M_CLK			0x00a1 +#define RT5663_FDIV_I2S34_M_CLK2		0x00a2 +#define RT5663_FDIV_I2S5_M_CLK			0x00a3 +#define RT5663_FDIV_I2S5_M_CLK2			0x00a4  /* Function - Digital */ -#define RT5668_IRQ_4				0x00b9 -#define RT5668_GPIO_3				0x00c2 -#define RT5668_GPIO_4				0x00c3 -#define RT5668_GPIO_STA				0x00c4 -#define RT5668_HP_AMP_DET1			0x00d0 -#define RT5668_HP_AMP_DET2			0x00d1 -#define RT5668_HP_AMP_DET3			0x00d2 -#define RT5668_MID_BD_HP_AMP			0x00d3 -#define RT5668_LOW_BD_HP_AMP			0x00d4 -#define RT5668_SOF_VOL_ZC2			0x00da -#define RT5668_ADC_STO2_ADJ1			0x00ee -#define RT5668_ADC_STO2_ADJ2			0x00ef +#define RT5663_V2_IRQ_4				0x00b9 +#define RT5663_GPIO_3				0x00c2 +#define RT5663_GPIO_4				0x00c3 +#define RT5663_GPIO_STA2			0x00c4 +#define RT5663_HP_AMP_DET1			0x00d0 +#define RT5663_HP_AMP_DET2			0x00d1 +#define RT5663_HP_AMP_DET3			0x00d2 +#define RT5663_MID_BD_HP_AMP			0x00d3 +#define RT5663_LOW_BD_HP_AMP			0x00d4 +#define RT5663_SOF_VOL_ZC2			0x00da +#define RT5663_ADC_STO2_ADJ1			0x00ee +#define RT5663_ADC_STO2_ADJ2			0x00ef  /* General Control */ -#define RT5668_A_JD_CTRL			0x00f0 -#define RT5668_JD1_TRES_CTRL			0x00f1 -#define RT5668_JD2_TRES_CTRL			0x00f2 -#define RT5668_JD_CTRL2				0x00f7 -#define RT5668_DUM_REG_2			0x00fb -#define RT5668_DUM_REG_3			0x00fc - - -#define RT5668_DACADC_DIG_VOL2			0x0101 -#define RT5668_DIG_IN_PIN2			0x0133 -#define RT5668_PAD_DRV_CTL1			0x0136 -#define RT5668_SOF_RAM_DEPOP			0x0138 -#define RT5668_VOL_TEST				0x013f -#define RT5668_TEST_MODE_3			0x0147 -#define RT5668_TEST_MODE_4			0x0148 -#define RT5668_MONO_DYNA_1			0x0170 -#define RT5668_MONO_DYNA_2			0x0171 -#define RT5668_MONO_DYNA_3			0x0172 -#define RT5668_MONO_DYNA_4			0x0173 -#define RT5668_MONO_DYNA_5			0x0174 -#define RT5668_MONO_DYNA_6			0x0175 -#define RT5668_STO1_SIL_DET			0x0190 -#define RT5668_MONOL_SIL_DET			0x0191 -#define RT5668_MONOR_SIL_DET			0x0192 -#define RT5668_STO2_DAC_SIL			0x0193 -#define RT5668_PWR_SAV_CTL1			0x0194 -#define RT5668_PWR_SAV_CTL2			0x0195 -#define RT5668_PWR_SAV_CTL3			0x0196 -#define RT5668_PWR_SAV_CTL4			0x0197 -#define RT5668_PWR_SAV_CTL5			0x0198 -#define RT5668_PWR_SAV_CTL6			0x0199 -#define RT5668_MONO_AMP_CAL1			0x01a0 -#define RT5668_MONO_AMP_CAL2			0x01a1 -#define RT5668_MONO_AMP_CAL3			0x01a2 -#define RT5668_MONO_AMP_CAL4			0x01a3 -#define RT5668_MONO_AMP_CAL5			0x01a4 -#define RT5668_MONO_AMP_CAL6			0x01a5 -#define RT5668_MONO_AMP_CAL7			0x01a6 -#define RT5668_MONO_AMP_CAL_ST1			0x01a7 -#define RT5668_MONO_AMP_CAL_ST2			0x01a8 -#define RT5668_MONO_AMP_CAL_ST3			0x01a9 -#define RT5668_MONO_AMP_CAL_ST4			0x01aa -#define RT5668_MONO_AMP_CAL_ST5			0x01ab -#define RT5668_HP_IMP_SEN_13			0x01b9 -#define RT5668_HP_IMP_SEN_14			0x01ba -#define RT5668_HP_IMP_SEN_6			0x01bb -#define RT5668_HP_IMP_SEN_7			0x01bc -#define RT5668_HP_IMP_SEN_8			0x01bd -#define RT5668_HP_IMP_SEN_9			0x01be -#define RT5668_HP_IMP_SEN_10			0x01bf -#define RT5668_HP_LOGIC_3			0x01dc -#define RT5668_HP_CALIB_ST10			0x01f3 -#define RT5668_HP_CALIB_ST11			0x01f4 -#define RT5668_PRO_REG_TBL_4			0x0203 -#define RT5668_PRO_REG_TBL_5			0x0204 -#define RT5668_PRO_REG_TBL_6			0x0205 -#define RT5668_PRO_REG_TBL_7			0x0206 -#define RT5668_PRO_REG_TBL_8			0x0207 -#define RT5668_PRO_REG_TBL_9			0x0208 -#define RT5668_SAR_ADC_INL_1			0x0210 -#define RT5668_SAR_ADC_INL_2			0x0211 -#define RT5668_SAR_ADC_INL_3			0x0212 -#define RT5668_SAR_ADC_INL_4			0x0213 -#define RT5668_SAR_ADC_INL_5			0x0214 -#define RT5668_SAR_ADC_INL_6			0x0215 -#define RT5668_SAR_ADC_INL_7			0x0216 -#define RT5668_SAR_ADC_INL_8			0x0217 -#define RT5668_SAR_ADC_INL_9			0x0218 -#define RT5668_SAR_ADC_INL_10			0x0219 -#define RT5668_SAR_ADC_INL_11			0x021a -#define RT5668_SAR_ADC_INL_12			0x021b -#define RT5668_DRC_CTRL_1			0x02ff -#define RT5668_DRC1_CTRL_2			0x0301 -#define RT5668_DRC1_CTRL_3			0x0302 -#define RT5668_DRC1_CTRL_4			0x0303 -#define RT5668_DRC1_CTRL_5			0x0304 -#define RT5668_DRC1_CTRL_6			0x0305 -#define RT5668_DRC1_HD_CTRL_1			0x0306 -#define RT5668_DRC1_HD_CTRL_2			0x0307 -#define RT5668_DRC1_PRI_REG_1			0x0310 -#define RT5668_DRC1_PRI_REG_2			0x0311 -#define RT5668_DRC1_PRI_REG_3			0x0312 -#define RT5668_DRC1_PRI_REG_4			0x0313 -#define RT5668_DRC1_PRI_REG_5			0x0314 -#define RT5668_DRC1_PRI_REG_6			0x0315 -#define RT5668_DRC1_PRI_REG_7			0x0316 -#define RT5668_DRC1_PRI_REG_8			0x0317 -#define RT5668_ALC_PGA_CTL_1			0x0330 -#define RT5668_ALC_PGA_CTL_2			0x0331 -#define RT5668_ALC_PGA_CTL_3			0x0332 -#define RT5668_ALC_PGA_CTL_4			0x0333 -#define RT5668_ALC_PGA_CTL_5			0x0334 -#define RT5668_ALC_PGA_CTL_6			0x0335 -#define RT5668_ALC_PGA_CTL_7			0x0336 -#define RT5668_ALC_PGA_CTL_8			0x0337 -#define RT5668_ALC_PGA_REG_1			0x0338 -#define RT5668_ALC_PGA_REG_2			0x0339 -#define RT5668_ALC_PGA_REG_3			0x033a -#define RT5668_ADC_EQ_RECOV_1			0x03c0 -#define RT5668_ADC_EQ_RECOV_2			0x03c1 -#define RT5668_ADC_EQ_RECOV_3			0x03c2 -#define RT5668_ADC_EQ_RECOV_4			0x03c3 -#define RT5668_ADC_EQ_RECOV_5			0x03c4 -#define RT5668_ADC_EQ_RECOV_6			0x03c5 -#define RT5668_ADC_EQ_RECOV_7			0x03c6 -#define RT5668_ADC_EQ_RECOV_8			0x03c7 -#define RT5668_ADC_EQ_RECOV_9			0x03c8 -#define RT5668_ADC_EQ_RECOV_10			0x03c9 -#define RT5668_ADC_EQ_RECOV_11			0x03ca -#define RT5668_ADC_EQ_RECOV_12			0x03cb -#define RT5668_ADC_EQ_RECOV_13			0x03cc -#define RT5668_VID_HIDDEN			0x03fe -#define RT5668_VID_CUSTOMER			0x03ff -#define RT5668_SCAN_MODE			0x07f0 -#define RT5668_I2C_BYPA				0x07fa +#define RT5663_A_JD_CTRL			0x00f0 +#define RT5663_JD1_TRES_CTRL			0x00f1 +#define RT5663_JD2_TRES_CTRL			0x00f2 +#define RT5663_V2_JD_CTRL2			0x00f7 +#define RT5663_DUM_REG_2			0x00fb +#define RT5663_DUM_REG_3			0x00fc + + +#define RT5663_DACADC_DIG_VOL2			0x0101 +#define RT5663_DIG_IN_PIN2			0x0133 +#define RT5663_PAD_DRV_CTL1			0x0136 +#define RT5663_SOF_RAM_DEPOP			0x0138 +#define RT5663_VOL_TEST				0x013f +#define RT5663_MONO_DYNA_1			0x0170 +#define RT5663_MONO_DYNA_2			0x0171 +#define RT5663_MONO_DYNA_3			0x0172 +#define RT5663_MONO_DYNA_4			0x0173 +#define RT5663_MONO_DYNA_5			0x0174 +#define RT5663_MONO_DYNA_6			0x0175 +#define RT5663_STO1_SIL_DET			0x0190 +#define RT5663_MONOL_SIL_DET			0x0191 +#define RT5663_MONOR_SIL_DET			0x0192 +#define RT5663_STO2_DAC_SIL			0x0193 +#define RT5663_PWR_SAV_CTL1			0x0194 +#define RT5663_PWR_SAV_CTL2			0x0195 +#define RT5663_PWR_SAV_CTL3			0x0196 +#define RT5663_PWR_SAV_CTL4			0x0197 +#define RT5663_PWR_SAV_CTL5			0x0198 +#define RT5663_PWR_SAV_CTL6			0x0199 +#define RT5663_MONO_AMP_CAL1			0x01a0 +#define RT5663_MONO_AMP_CAL2			0x01a1 +#define RT5663_MONO_AMP_CAL3			0x01a2 +#define RT5663_MONO_AMP_CAL4			0x01a3 +#define RT5663_MONO_AMP_CAL5			0x01a4 +#define RT5663_MONO_AMP_CAL6			0x01a5 +#define RT5663_MONO_AMP_CAL7			0x01a6 +#define RT5663_MONO_AMP_CAL_ST1			0x01a7 +#define RT5663_MONO_AMP_CAL_ST2			0x01a8 +#define RT5663_MONO_AMP_CAL_ST3			0x01a9 +#define RT5663_MONO_AMP_CAL_ST4			0x01aa +#define RT5663_MONO_AMP_CAL_ST5			0x01ab +#define RT5663_V2_HP_IMP_SEN_13			0x01b9 +#define RT5663_V2_HP_IMP_SEN_14			0x01ba +#define RT5663_V2_HP_IMP_SEN_6			0x01bb +#define RT5663_V2_HP_IMP_SEN_7			0x01bc +#define RT5663_V2_HP_IMP_SEN_8			0x01bd +#define RT5663_V2_HP_IMP_SEN_9			0x01be +#define RT5663_V2_HP_IMP_SEN_10			0x01bf +#define RT5663_HP_LOGIC_3			0x01dc +#define RT5663_HP_CALIB_ST10			0x01f3 +#define RT5663_HP_CALIB_ST11			0x01f4 +#define RT5663_PRO_REG_TBL_4			0x0203 +#define RT5663_PRO_REG_TBL_5			0x0204 +#define RT5663_PRO_REG_TBL_6			0x0205 +#define RT5663_PRO_REG_TBL_7			0x0206 +#define RT5663_PRO_REG_TBL_8			0x0207 +#define RT5663_PRO_REG_TBL_9			0x0208 +#define RT5663_SAR_ADC_INL_1			0x0210 +#define RT5663_SAR_ADC_INL_2			0x0211 +#define RT5663_SAR_ADC_INL_3			0x0212 +#define RT5663_SAR_ADC_INL_4			0x0213 +#define RT5663_SAR_ADC_INL_5			0x0214 +#define RT5663_SAR_ADC_INL_6			0x0215 +#define RT5663_SAR_ADC_INL_7			0x0216 +#define RT5663_SAR_ADC_INL_8			0x0217 +#define RT5663_SAR_ADC_INL_9			0x0218 +#define RT5663_SAR_ADC_INL_10			0x0219 +#define RT5663_SAR_ADC_INL_11			0x021a +#define RT5663_SAR_ADC_INL_12			0x021b +#define RT5663_DRC_CTRL_1			0x02ff +#define RT5663_DRC1_CTRL_2			0x0301 +#define RT5663_DRC1_CTRL_3			0x0302 +#define RT5663_DRC1_CTRL_4			0x0303 +#define RT5663_DRC1_CTRL_5			0x0304 +#define RT5663_DRC1_CTRL_6			0x0305 +#define RT5663_DRC1_HD_CTRL_1			0x0306 +#define RT5663_DRC1_HD_CTRL_2			0x0307 +#define RT5663_DRC1_PRI_REG_1			0x0310 +#define RT5663_DRC1_PRI_REG_2			0x0311 +#define RT5663_DRC1_PRI_REG_3			0x0312 +#define RT5663_DRC1_PRI_REG_4			0x0313 +#define RT5663_DRC1_PRI_REG_5			0x0314 +#define RT5663_DRC1_PRI_REG_6			0x0315 +#define RT5663_DRC1_PRI_REG_7			0x0316 +#define RT5663_DRC1_PRI_REG_8			0x0317 +#define RT5663_ALC_PGA_CTL_1			0x0330 +#define RT5663_ALC_PGA_CTL_2			0x0331 +#define RT5663_ALC_PGA_CTL_3			0x0332 +#define RT5663_ALC_PGA_CTL_4			0x0333 +#define RT5663_ALC_PGA_CTL_5			0x0334 +#define RT5663_ALC_PGA_CTL_6			0x0335 +#define RT5663_ALC_PGA_CTL_7			0x0336 +#define RT5663_ALC_PGA_CTL_8			0x0337 +#define RT5663_ALC_PGA_REG_1			0x0338 +#define RT5663_ALC_PGA_REG_2			0x0339 +#define RT5663_ALC_PGA_REG_3			0x033a +#define RT5663_ADC_EQ_RECOV_1			0x03c0 +#define RT5663_ADC_EQ_RECOV_2			0x03c1 +#define RT5663_ADC_EQ_RECOV_3			0x03c2 +#define RT5663_ADC_EQ_RECOV_4			0x03c3 +#define RT5663_ADC_EQ_RECOV_5			0x03c4 +#define RT5663_ADC_EQ_RECOV_6			0x03c5 +#define RT5663_ADC_EQ_RECOV_7			0x03c6 +#define RT5663_ADC_EQ_RECOV_8			0x03c7 +#define RT5663_ADC_EQ_RECOV_9			0x03c8 +#define RT5663_ADC_EQ_RECOV_10			0x03c9 +#define RT5663_ADC_EQ_RECOV_11			0x03ca +#define RT5663_ADC_EQ_RECOV_12			0x03cb +#define RT5663_ADC_EQ_RECOV_13			0x03cc +#define RT5663_VID_HIDDEN			0x03fe +#define RT5663_VID_CUSTOMER			0x03ff +#define RT5663_SCAN_MODE			0x07f0 +#define RT5663_I2C_BYPA				0x07fa  /* Headphone Amp Control 2 (0x0003) */ -#define RT5668_EN_DAC_HPO_MASK			(0x1 << 14) -#define RT5668_EN_DAC_HPO_SHIFT			14 -#define RT5668_EN_DAC_HPO_DIS			(0x0 << 14) -#define RT5668_EN_DAC_HPO_EN			(0x1 << 14) +#define RT5663_EN_DAC_HPO_MASK			(0x1 << 14) +#define RT5663_EN_DAC_HPO_SHIFT			14 +#define RT5663_EN_DAC_HPO_DIS			(0x0 << 14) +#define RT5663_EN_DAC_HPO_EN			(0x1 << 14)  /*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/ -#define RT5668_GAIN_HP				(0x1f << 8) -#define RT5668_GAIN_HP_SHIFT			8 +#define RT5663_GAIN_HP				(0x1f << 8) +#define RT5663_GAIN_HP_SHIFT			8  /* AEC BST Control (0x000b) */ -#define RT5668_GAIN_CBJ_MASK			(0xf << 8) -#define RT5668_GAIN_CBJ_SHIFT			8 +#define RT5663_GAIN_CBJ_MASK			(0xf << 8) +#define RT5663_GAIN_CBJ_SHIFT			8  /* IN1 Control / MIC GND REF (0x000c) */ -#define RT5668_IN1_DF_MASK			(0x1 << 15) -#define RT5668_IN1_DF_SHIFT			15 +#define RT5663_IN1_DF_MASK			(0x1 << 15) +#define RT5663_IN1_DF_SHIFT			15  /* Combo Jack and Type Detection Control 1 (0x0010) */ -#define RT5668_CBJ_DET_MASK			(0x1 << 15) -#define RT5668_CBJ_DET_SHIFT			15 -#define RT5668_CBJ_DET_DIS			(0x0 << 15) -#define RT5668_CBJ_DET_EN			(0x1 << 15) -#define RT5668_DET_TYPE_MASK			(0x1 << 12) -#define RT5668_DET_TYPE_SHIFT			12 -#define RT5668_DET_TYPE_WLCSP			(0x0 << 12) -#define RT5668_DET_TYPE_QFN			(0x1 << 12) -#define RT5668_VREF_BIAS_MASK			(0x1 << 6) -#define RT5668_VREF_BIAS_SHIFT			6 -#define RT5668_VREF_BIAS_FSM			(0x0 << 6) -#define RT5668_VREF_BIAS_REG			(0x1 << 6) +#define RT5663_CBJ_DET_MASK			(0x1 << 15) +#define RT5663_CBJ_DET_SHIFT			15 +#define RT5663_CBJ_DET_DIS			(0x0 << 15) +#define RT5663_CBJ_DET_EN			(0x1 << 15) +#define RT5663_DET_TYPE_MASK			(0x1 << 12) +#define RT5663_DET_TYPE_SHIFT			12 +#define RT5663_DET_TYPE_WLCSP			(0x0 << 12) +#define RT5663_DET_TYPE_QFN			(0x1 << 12) +#define RT5663_VREF_BIAS_MASK			(0x1 << 6) +#define RT5663_VREF_BIAS_SHIFT			6 +#define RT5663_VREF_BIAS_FSM			(0x0 << 6) +#define RT5663_VREF_BIAS_REG			(0x1 << 6)  /* REC Left Mixer Control 2 (0x003c) */ -#define RT5668_RECMIX1L_BST1_CBJ		(0x1 << 7) -#define RT5668_RECMIX1L_BST1_CBJ_SHIFT		7 -#define RT5668_RECMIX1L_BST2			(0x1 << 4) -#define RT5668_RECMIX1L_BST2_SHIFT		4 +#define RT5663_RECMIX1L_BST1_CBJ		(0x1 << 7) +#define RT5663_RECMIX1L_BST1_CBJ_SHIFT		7 +#define RT5663_RECMIX1L_BST2			(0x1 << 4) +#define RT5663_RECMIX1L_BST2_SHIFT		4  /* REC Right Mixer Control 2 (0x003e) */ -#define RT5668_RECMIX1R_BST2			(0x1 << 4) -#define RT5668_RECMIX1R_BST2_SHIFT		4 +#define RT5663_RECMIX1R_BST2			(0x1 << 4) +#define RT5663_RECMIX1R_BST2_SHIFT		4  /* DAC1 Digital Volume (0x0019) */ -#define RT5668_DAC_L1_VOL_MASK			(0xff << 8) -#define RT5668_DAC_L1_VOL_SHIFT			8 -#define RT5668_DAC_R1_VOL_MASK			(0xff) -#define RT5668_DAC_R1_VOL_SHIFT			0 +#define RT5663_DAC_L1_VOL_MASK			(0xff << 8) +#define RT5663_DAC_L1_VOL_SHIFT			8 +#define RT5663_DAC_R1_VOL_MASK			(0xff) +#define RT5663_DAC_R1_VOL_SHIFT			0  /* ADC Digital Volume Control (0x001c) */ -#define RT5668_ADC_L_MUTE_MASK			(0x1 << 15) -#define RT5668_ADC_L_MUTE_SHIFT			15 -#define RT5668_ADC_L_VOL_MASK			(0x7f << 8) -#define RT5668_ADC_L_VOL_SHIFT			8 -#define RT5668_ADC_R_MUTE_MASK			(0x1 << 7) -#define RT5668_ADC_R_MUTE_SHIFT			7 -#define RT5668_ADC_R_VOL_MASK			(0x7f) -#define RT5668_ADC_R_VOL_SHIFT			0 +#define RT5663_ADC_L_MUTE_MASK			(0x1 << 15) +#define RT5663_ADC_L_MUTE_SHIFT			15 +#define RT5663_ADC_L_VOL_MASK			(0x7f << 8) +#define RT5663_ADC_L_VOL_SHIFT			8 +#define RT5663_ADC_R_MUTE_MASK			(0x1 << 7) +#define RT5663_ADC_R_MUTE_SHIFT			7 +#define RT5663_ADC_R_VOL_MASK			(0x7f) +#define RT5663_ADC_R_VOL_SHIFT			0  /* Stereo ADC Mixer Control (0x0026) */ -#define RT5668_M_STO1_ADC_L1			(0x1 << 15) -#define RT5668_M_STO1_ADC_L1_SHIFT		15 -#define RT5668_M_STO1_ADC_L2			(0x1 << 14) -#define RT5668_M_STO1_ADC_L2_SHIFT		14 -#define RT5668_STO1_ADC_L1_SRC			(0x1 << 13) -#define RT5668_STO1_ADC_L1_SRC_SHIFT		13 -#define RT5668_STO1_ADC_L2_SRC			(0x1 << 12) -#define RT5668_STO1_ADC_L2_SRC_SHIFT		12 -#define RT5668_STO1_ADC_L_SRC			(0x3 << 10) -#define RT5668_STO1_ADC_L_SRC_SHIFT		10 -#define RT5668_M_STO1_ADC_R1			(0x1 << 7) -#define RT5668_M_STO1_ADC_R1_SHIFT		7 -#define RT5668_M_STO1_ADC_R2			(0x1 << 6) -#define RT5668_M_STO1_ADC_R2_SHIFT		6 -#define RT5668_STO1_ADC_R1_SRC			(0x1 << 5) -#define RT5668_STO1_ADC_R1_SRC_SHIFT		5 -#define RT5668_STO1_ADC_R2_SRC			(0x1 << 4) -#define RT5668_STO1_ADC_R2_SRC_SHIFT		4 -#define RT5668_STO1_ADC_R_SRC			(0x3 << 2) -#define RT5668_STO1_ADC_R_SRC_SHIFT		2 +#define RT5663_M_STO1_ADC_L1			(0x1 << 15) +#define RT5663_M_STO1_ADC_L1_SHIFT		15 +#define RT5663_M_STO1_ADC_L2			(0x1 << 14) +#define RT5663_M_STO1_ADC_L2_SHIFT		14 +#define RT5663_STO1_ADC_L1_SRC			(0x1 << 13) +#define RT5663_STO1_ADC_L1_SRC_SHIFT		13 +#define RT5663_STO1_ADC_L2_SRC			(0x1 << 12) +#define RT5663_STO1_ADC_L2_SRC_SHIFT		12 +#define RT5663_STO1_ADC_L_SRC			(0x3 << 10) +#define RT5663_STO1_ADC_L_SRC_SHIFT		10 +#define RT5663_M_STO1_ADC_R1			(0x1 << 7) +#define RT5663_M_STO1_ADC_R1_SHIFT		7 +#define RT5663_M_STO1_ADC_R2			(0x1 << 6) +#define RT5663_M_STO1_ADC_R2_SHIFT		6 +#define RT5663_STO1_ADC_R1_SRC			(0x1 << 5) +#define RT5663_STO1_ADC_R1_SRC_SHIFT		5 +#define RT5663_STO1_ADC_R2_SRC			(0x1 << 4) +#define RT5663_STO1_ADC_R2_SRC_SHIFT		4 +#define RT5663_STO1_ADC_R_SRC			(0x3 << 2) +#define RT5663_STO1_ADC_R_SRC_SHIFT		2  /* ADC Mixer to DAC Mixer Control (0x0029) */ -#define RT5668_M_ADCMIX_L			(0x1 << 15) -#define RT5668_M_ADCMIX_L_SHIFT			15 -#define RT5668_M_DAC1_L				(0x1 << 14) -#define RT5668_M_DAC1_L_SHIFT			14 -#define RT5668_M_ADCMIX_R			(0x1 << 7) -#define RT5668_M_ADCMIX_R_SHIFT			7 -#define RT5668_M_DAC1_R				(0x1 << 6) -#define RT5668_M_DAC1_R_SHIFT			6 +#define RT5663_M_ADCMIX_L			(0x1 << 15) +#define RT5663_M_ADCMIX_L_SHIFT			15 +#define RT5663_M_DAC1_L				(0x1 << 14) +#define RT5663_M_DAC1_L_SHIFT			14 +#define RT5663_M_ADCMIX_R			(0x1 << 7) +#define RT5663_M_ADCMIX_R_SHIFT			7 +#define RT5663_M_DAC1_R				(0x1 << 6) +#define RT5663_M_DAC1_R_SHIFT			6  /* Stereo DAC Mixer Control (0x002a) */ -#define RT5668_M_DAC_L1_STO_L			(0x1 << 15) -#define RT5668_M_DAC_L1_STO_L_SHIFT		15 -#define RT5668_M_DAC_R1_STO_L			(0x1 << 13) -#define RT5668_M_DAC_R1_STO_L_SHIFT		13 -#define RT5668_M_DAC_L1_STO_R			(0x1 << 7) -#define RT5668_M_DAC_L1_STO_R_SHIFT		7 -#define RT5668_M_DAC_R1_STO_R			(0x1 << 5) -#define RT5668_M_DAC_R1_STO_R_SHIFT		5 +#define RT5663_M_DAC_L1_STO_L			(0x1 << 15) +#define RT5663_M_DAC_L1_STO_L_SHIFT		15 +#define RT5663_M_DAC_R1_STO_L			(0x1 << 13) +#define RT5663_M_DAC_R1_STO_L_SHIFT		13 +#define RT5663_M_DAC_L1_STO_R			(0x1 << 7) +#define RT5663_M_DAC_L1_STO_R_SHIFT		7 +#define RT5663_M_DAC_R1_STO_R			(0x1 << 5) +#define RT5663_M_DAC_R1_STO_R_SHIFT		5  /* Power Management for Digital 1 (0x0061) */ -#define RT5668_PWR_I2S1				(0x1 << 15) -#define RT5668_PWR_I2S1_SHIFT			15 -#define RT5668_PWR_DAC_L1			(0x1 << 11) -#define RT5668_PWR_DAC_L1_SHIFT			11 -#define RT5668_PWR_DAC_R1			(0x1 << 10) -#define RT5668_PWR_DAC_R1_SHIFT			10 -#define RT5668_PWR_LDO_DACREF_MASK		(0x1 << 8) -#define RT5668_PWR_LDO_DACREF_SHIFT		8 -#define RT5668_PWR_LDO_DACREF_ON		(0x1 << 8) -#define RT5668_PWR_LDO_DACREF_DOWN		(0x0 << 8) -#define RT5668_PWR_LDO_SHIFT			8 -#define RT5668_PWR_ADC_L1			(0x1 << 4) -#define RT5668_PWR_ADC_L1_SHIFT			4 -#define RT5668_PWR_ADC_R1			(0x1 << 3) -#define RT5668_PWR_ADC_R1_SHIFT			3 +#define RT5663_PWR_I2S1				(0x1 << 15) +#define RT5663_PWR_I2S1_SHIFT			15 +#define RT5663_PWR_DAC_L1			(0x1 << 11) +#define RT5663_PWR_DAC_L1_SHIFT			11 +#define RT5663_PWR_DAC_R1			(0x1 << 10) +#define RT5663_PWR_DAC_R1_SHIFT			10 +#define RT5663_PWR_LDO_DACREF_MASK		(0x1 << 8) +#define RT5663_PWR_LDO_DACREF_SHIFT		8 +#define RT5663_PWR_LDO_DACREF_ON		(0x1 << 8) +#define RT5663_PWR_LDO_DACREF_DOWN		(0x0 << 8) +#define RT5663_PWR_LDO_SHIFT			8 +#define RT5663_PWR_ADC_L1			(0x1 << 4) +#define RT5663_PWR_ADC_L1_SHIFT			4 +#define RT5663_PWR_ADC_R1			(0x1 << 3) +#define RT5663_PWR_ADC_R1_SHIFT			3  /* Power Management for Digital 2 (0x0062) */ -#define RT5668_PWR_ADC_S1F			(0x1 << 15) -#define RT5668_PWR_ADC_S1F_SHIFT		15 -#define RT5668_PWR_DAC_S1F			(0x1 << 10) -#define RT5668_PWR_DAC_S1F_SHIFT		10 +#define RT5663_PWR_ADC_S1F			(0x1 << 15) +#define RT5663_PWR_ADC_S1F_SHIFT		15 +#define RT5663_PWR_DAC_S1F			(0x1 << 10) +#define RT5663_PWR_DAC_S1F_SHIFT		10  /* Power Management for Analog 1 (0x0063) */ -#define RT5668_PWR_VREF1			(0x1 << 15) -#define RT5668_PWR_VREF1_MASK			(0x1 << 15) -#define RT5668_PWR_VREF1_SHIFT			15 -#define RT5668_PWR_FV1				(0x1 << 14) -#define RT5668_PWR_FV1_MASK			(0x1 << 14) -#define RT5668_PWR_FV1_SHIFT			14 -#define RT5668_PWR_VREF2			(0x1 << 13) -#define RT5668_PWR_VREF2_MASK			(0x1 << 13) -#define RT5668_PWR_VREF2_SHIFT			13 -#define RT5668_PWR_FV2				(0x1 << 12) -#define RT5668_PWR_FV2_MASK			(0x1 << 12) -#define RT5668_PWR_FV2_SHIFT			12 -#define RT5668_PWR_MB				(0x1 << 9) -#define RT5668_PWR_MB_MASK			(0x1 << 9) -#define RT5668_PWR_MB_SHIFT			9 -#define RT5668_AMP_HP_MASK			(0x3 << 2) -#define RT5668_AMP_HP_SHIFT			2 -#define RT5668_AMP_HP_1X			(0x0 << 2) -#define RT5668_AMP_HP_3X			(0x1 << 2) -#define RT5668_AMP_HP_5X			(0x3 << 2) -#define RT5668_LDO1_DVO_MASK			(0x3) -#define RT5668_LDO1_DVO_SHIFT			0 -#define RT5668_LDO1_DVO_0_9V			(0x0) -#define RT5668_LDO1_DVO_1_0V			(0x1) -#define RT5668_LDO1_DVO_1_2V			(0x2) -#define RT5668_LDO1_DVO_1_4V			(0x3) +#define RT5663_PWR_VREF1			(0x1 << 15) +#define RT5663_PWR_VREF1_MASK			(0x1 << 15) +#define RT5663_PWR_VREF1_SHIFT			15 +#define RT5663_PWR_FV1				(0x1 << 14) +#define RT5663_PWR_FV1_MASK			(0x1 << 14) +#define RT5663_PWR_FV1_SHIFT			14 +#define RT5663_PWR_VREF2			(0x1 << 13) +#define RT5663_PWR_VREF2_MASK			(0x1 << 13) +#define RT5663_PWR_VREF2_SHIFT			13 +#define RT5663_PWR_FV2				(0x1 << 12) +#define RT5663_PWR_FV2_MASK			(0x1 << 12) +#define RT5663_PWR_FV2_SHIFT			12 +#define RT5663_PWR_MB				(0x1 << 9) +#define RT5663_PWR_MB_MASK			(0x1 << 9) +#define RT5663_PWR_MB_SHIFT			9 +#define RT5663_AMP_HP_MASK			(0x3 << 2) +#define RT5663_AMP_HP_SHIFT			2 +#define RT5663_AMP_HP_1X			(0x0 << 2) +#define RT5663_AMP_HP_3X			(0x1 << 2) +#define RT5663_AMP_HP_5X			(0x3 << 2) +#define RT5663_LDO1_DVO_MASK			(0x3) +#define RT5663_LDO1_DVO_SHIFT			0 +#define RT5663_LDO1_DVO_0_9V			(0x0) +#define RT5663_LDO1_DVO_1_0V			(0x1) +#define RT5663_LDO1_DVO_1_2V			(0x2) +#define RT5663_LDO1_DVO_1_4V			(0x3)  /* Power Management for Analog 2 (0x0064) */ -#define RT5668_PWR_BST1				(0x1 << 15) -#define RT5668_PWR_BST1_MASK			(0x1 << 15) -#define RT5668_PWR_BST1_SHIFT			15 -#define RT5668_PWR_BST1_OFF			(0x0 << 15) -#define RT5668_PWR_BST1_ON			(0x1 << 15) -#define RT5668_PWR_BST2				(0x1 << 14) -#define RT5668_PWR_BST2_MASK			(0x1 << 14) -#define RT5668_PWR_BST2_SHIFT			14 -#define RT5668_PWR_MB1				(0x1 << 11) -#define RT5668_PWR_MB1_SHIFT			11 -#define RT5668_PWR_MB2				(0x1 << 10) -#define RT5668_PWR_MB2_SHIFT			10 -#define RT5668_PWR_BST2_OP			(0x1 << 6) -#define RT5668_PWR_BST2_OP_MASK			(0x1 << 6) -#define RT5668_PWR_BST2_OP_SHIFT		6 -#define RT5668_PWR_JD1				(0x1 << 3) -#define RT5668_PWR_JD1_MASK			(0x1 << 3) -#define RT5668_PWR_JD1_SHIFT			3 -#define RT5668_PWR_JD2				(0x1 << 2) -#define RT5668_PWR_JD2_MASK			(0x1 << 2) -#define RT5668_PWR_JD2_SHIFT			2 -#define RT5668_PWR_RECMIX1			(0x1 << 1) -#define RT5668_PWR_RECMIX1_SHIFT		1 -#define RT5668_PWR_RECMIX2			(0x1) -#define RT5668_PWR_RECMIX2_SHIFT		0 +#define RT5663_PWR_BST1				(0x1 << 15) +#define RT5663_PWR_BST1_MASK			(0x1 << 15) +#define RT5663_PWR_BST1_SHIFT			15 +#define RT5663_PWR_BST1_OFF			(0x0 << 15) +#define RT5663_PWR_BST1_ON			(0x1 << 15) +#define RT5663_PWR_BST2				(0x1 << 14) +#define RT5663_PWR_BST2_MASK			(0x1 << 14) +#define RT5663_PWR_BST2_SHIFT			14 +#define RT5663_PWR_MB1				(0x1 << 11) +#define RT5663_PWR_MB1_SHIFT			11 +#define RT5663_PWR_MB2				(0x1 << 10) +#define RT5663_PWR_MB2_SHIFT			10 +#define RT5663_PWR_BST2_OP			(0x1 << 6) +#define RT5663_PWR_BST2_OP_MASK			(0x1 << 6) +#define RT5663_PWR_BST2_OP_SHIFT		6 +#define RT5663_PWR_JD1				(0x1 << 3) +#define RT5663_PWR_JD1_MASK			(0x1 << 3) +#define RT5663_PWR_JD1_SHIFT			3 +#define RT5663_PWR_JD2				(0x1 << 2) +#define RT5663_PWR_JD2_MASK			(0x1 << 2) +#define RT5663_PWR_JD2_SHIFT			2 +#define RT5663_PWR_RECMIX1			(0x1 << 1) +#define RT5663_PWR_RECMIX1_SHIFT		1 +#define RT5663_PWR_RECMIX2			(0x1) +#define RT5663_PWR_RECMIX2_SHIFT		0  /* Power Management for Analog 3 (0x0065) */ -#define RT5668_PWR_CBJ_MASK			(0x1 << 9) -#define RT5668_PWR_CBJ_SHIFT			9 -#define RT5668_PWR_CBJ_OFF			(0x0 << 9) -#define RT5668_PWR_CBJ_ON			(0x1 << 9) -#define RT5668_PWR_PLL				(0x1 << 6) -#define RT5668_PWR_PLL_SHIFT			6 -#define RT5668_PWR_LDO2				(0x1 << 2) -#define RT5668_PWR_LDO2_SHIFT			2 +#define RT5663_PWR_CBJ_MASK			(0x1 << 9) +#define RT5663_PWR_CBJ_SHIFT			9 +#define RT5663_PWR_CBJ_OFF			(0x0 << 9) +#define RT5663_PWR_CBJ_ON			(0x1 << 9) +#define RT5663_PWR_PLL				(0x1 << 6) +#define RT5663_PWR_PLL_SHIFT			6 +#define RT5663_PWR_LDO2				(0x1 << 2) +#define RT5663_PWR_LDO2_SHIFT			2  /* Power Management for Volume (0x0067) */ -#define RT5668_PWR_MIC_DET			(0x1 << 5) -#define RT5668_PWR_MIC_DET_SHIFT		5 +#define RT5663_V2_PWR_MIC_DET			(0x1 << 5) +#define RT5663_V2_PWR_MIC_DET_SHIFT		5  /* MCLK and System Clock Detection Control (0x006b) */ -#define RT5668_EN_ANA_CLK_DET_MASK		(0x1 << 15) -#define RT5668_EN_ANA_CLK_DET_SHIFT		15 -#define RT5668_EN_ANA_CLK_DET_DIS		(0x0 << 15) -#define RT5668_EN_ANA_CLK_DET_AUTO		(0x1 << 15) -#define RT5668_PWR_CLK_DET_MASK			(0x1) -#define RT5668_PWR_CLK_DET_SHIFT		0 -#define RT5668_PWR_CLK_DET_DIS			(0x0) -#define RT5668_PWR_CLK_DET_EN			(0x1) +#define RT5663_EN_ANA_CLK_DET_MASK		(0x1 << 15) +#define RT5663_EN_ANA_CLK_DET_SHIFT		15 +#define RT5663_EN_ANA_CLK_DET_DIS		(0x0 << 15) +#define RT5663_EN_ANA_CLK_DET_AUTO		(0x1 << 15) +#define RT5663_PWR_CLK_DET_MASK			(0x1) +#define RT5663_PWR_CLK_DET_SHIFT		0 +#define RT5663_PWR_CLK_DET_DIS			(0x0) +#define RT5663_PWR_CLK_DET_EN			(0x1)  /* I2S1 Audio Serial Data Port Control (0x0070) */ -#define RT5668_I2S_MS_MASK			(0x1 << 15) -#define RT5668_I2S_MS_SHIFT			15 -#define RT5668_I2S_MS_M				(0x0 << 15) -#define RT5668_I2S_MS_S				(0x1 << 15) -#define RT5668_I2S_BP_MASK			(0x1 << 8) -#define RT5668_I2S_BP_SHIFT			8 -#define RT5668_I2S_BP_NOR			(0x0 << 8) -#define RT5668_I2S_BP_INV			(0x1 << 8) -#define RT5668_I2S_DL_MASK			(0x3 << 4) -#define RT5668_I2S_DL_SHIFT			4 -#define RT5668_I2S_DL_16			(0x0 << 4) -#define RT5668_I2S_DL_20			(0x1 << 4) -#define RT5668_I2S_DL_24			(0x2 << 4) -#define RT5668_I2S_DL_8				(0x3 << 4) -#define RT5668_I2S_DF_MASK			(0x7) -#define RT5668_I2S_DF_SHIFT			0 -#define RT5668_I2S_DF_I2S			(0x0) -#define RT5668_I2S_DF_LEFT			(0x1) -#define RT5668_I2S_DF_PCM_A			(0x2) -#define RT5668_I2S_DF_PCM_B			(0x3) -#define RT5668_I2S_DF_PCM_A_N			(0x6) -#define RT5668_I2S_DF_PCM_B_N			(0x7) +#define RT5663_I2S_MS_MASK			(0x1 << 15) +#define RT5663_I2S_MS_SHIFT			15 +#define RT5663_I2S_MS_M				(0x0 << 15) +#define RT5663_I2S_MS_S				(0x1 << 15) +#define RT5663_I2S_BP_MASK			(0x1 << 8) +#define RT5663_I2S_BP_SHIFT			8 +#define RT5663_I2S_BP_NOR			(0x0 << 8) +#define RT5663_I2S_BP_INV			(0x1 << 8) +#define RT5663_I2S_DL_MASK			(0x3 << 4) +#define RT5663_I2S_DL_SHIFT			4 +#define RT5663_I2S_DL_16			(0x0 << 4) +#define RT5663_I2S_DL_20			(0x1 << 4) +#define RT5663_I2S_DL_24			(0x2 << 4) +#define RT5663_I2S_DL_8				(0x3 << 4) +#define RT5663_I2S_DF_MASK			(0x7) +#define RT5663_I2S_DF_SHIFT			0 +#define RT5663_I2S_DF_I2S			(0x0) +#define RT5663_I2S_DF_LEFT			(0x1) +#define RT5663_I2S_DF_PCM_A			(0x2) +#define RT5663_I2S_DF_PCM_B			(0x3) +#define RT5663_I2S_DF_PCM_A_N			(0x6) +#define RT5663_I2S_DF_PCM_B_N			(0x7)  /* ADC/DAC Clock Control 1 (0x0073) */ -#define RT5668_I2S_PD1_MASK			(0x7 << 12) -#define RT5668_I2S_PD1_SHIFT			12 -#define RT5668_M_I2S_DIV_MASK			(0x7 << 8) -#define RT5668_M_I2S_DIV_SHIFT			8 -#define RT5668_CLK_SRC_MASK			(0x3 << 4) -#define RT5668_CLK_SRC_MCLK			(0x0 << 4) -#define RT5668_CLK_SRC_PLL_OUT			(0x1 << 4) -#define RT5668_CLK_SRC_DIV			(0x2 << 4) -#define RT5668_CLK_SRC_RC			(0x3 << 4) -#define RT5668_DAC_OSR_MASK			(0x3 << 2) -#define RT5668_DAC_OSR_SHIFT			2 -#define RT5668_DAC_OSR_128			(0x0 << 2) -#define RT5668_DAC_OSR_64			(0x1 << 2) -#define RT5668_DAC_OSR_32			(0x2 << 2) -#define RT5668_ADC_OSR_MASK			(0x3) -#define RT5668_ADC_OSR_SHIFT			0 -#define RT5668_ADC_OSR_128			(0x0) -#define RT5668_ADC_OSR_64			(0x1) -#define RT5668_ADC_OSR_32			(0x2) +#define RT5663_I2S_PD1_MASK			(0x7 << 12) +#define RT5663_I2S_PD1_SHIFT			12 +#define RT5663_M_I2S_DIV_MASK			(0x7 << 8) +#define RT5663_M_I2S_DIV_SHIFT			8 +#define RT5663_CLK_SRC_MASK			(0x3 << 4) +#define RT5663_CLK_SRC_MCLK			(0x0 << 4) +#define RT5663_CLK_SRC_PLL_OUT			(0x1 << 4) +#define RT5663_CLK_SRC_DIV			(0x2 << 4) +#define RT5663_CLK_SRC_RC			(0x3 << 4) +#define RT5663_DAC_OSR_MASK			(0x3 << 2) +#define RT5663_DAC_OSR_SHIFT			2 +#define RT5663_DAC_OSR_128			(0x0 << 2) +#define RT5663_DAC_OSR_64			(0x1 << 2) +#define RT5663_DAC_OSR_32			(0x2 << 2) +#define RT5663_ADC_OSR_MASK			(0x3) +#define RT5663_ADC_OSR_SHIFT			0 +#define RT5663_ADC_OSR_128			(0x0) +#define RT5663_ADC_OSR_64			(0x1) +#define RT5663_ADC_OSR_32			(0x2)  /* TDM1 control 1 (0x0078) */ -#define RT5668_TDM_MODE_MASK			(0x1 << 15) -#define RT5668_TDM_MODE_SHIFT			15 -#define RT5668_TDM_MODE_I2S			(0x0 << 15) -#define RT5668_TDM_MODE_TDM			(0x1 << 15) -#define RT5668_TDM_IN_CH_MASK			(0x3 << 10) -#define RT5668_TDM_IN_CH_SHIFT			10 -#define RT5668_TDM_IN_CH_2			(0x0 << 10) -#define RT5668_TDM_IN_CH_4			(0x1 << 10) -#define RT5668_TDM_IN_CH_6			(0x2 << 10) -#define RT5668_TDM_IN_CH_8			(0x3 << 10) -#define RT5668_TDM_OUT_CH_MASK			(0x3 << 8) -#define RT5668_TDM_OUT_CH_SHIFT			8 -#define RT5668_TDM_OUT_CH_2			(0x0 << 8) -#define RT5668_TDM_OUT_CH_4			(0x1 << 8) -#define RT5668_TDM_OUT_CH_6			(0x2 << 8) -#define RT5668_TDM_OUT_CH_8			(0x3 << 8) -#define RT5668_TDM_IN_LEN_MASK			(0x3 << 6) -#define RT5668_TDM_IN_LEN_SHIFT			6 -#define RT5668_TDM_IN_LEN_16			(0x0 << 6) -#define RT5668_TDM_IN_LEN_20			(0x1 << 6) -#define RT5668_TDM_IN_LEN_24			(0x2 << 6) -#define RT5668_TDM_IN_LEN_32			(0x3 << 6) -#define RT5668_TDM_OUT_LEN_MASK			(0x3 << 4) -#define RT5668_TDM_OUT_LEN_SHIFT		4 -#define RT5668_TDM_OUT_LEN_16			(0x0 << 4) -#define RT5668_TDM_OUT_LEN_20			(0x1 << 4) -#define RT5668_TDM_OUT_LEN_24			(0x2 << 4) -#define RT5668_TDM_OUT_LEN_32			(0x3 << 4) +#define RT5663_TDM_MODE_MASK			(0x1 << 15) +#define RT5663_TDM_MODE_SHIFT			15 +#define RT5663_TDM_MODE_I2S			(0x0 << 15) +#define RT5663_TDM_MODE_TDM			(0x1 << 15) +#define RT5663_TDM_IN_CH_MASK			(0x3 << 10) +#define RT5663_TDM_IN_CH_SHIFT			10 +#define RT5663_TDM_IN_CH_2			(0x0 << 10) +#define RT5663_TDM_IN_CH_4			(0x1 << 10) +#define RT5663_TDM_IN_CH_6			(0x2 << 10) +#define RT5663_TDM_IN_CH_8			(0x3 << 10) +#define RT5663_TDM_OUT_CH_MASK			(0x3 << 8) +#define RT5663_TDM_OUT_CH_SHIFT			8 +#define RT5663_TDM_OUT_CH_2			(0x0 << 8) +#define RT5663_TDM_OUT_CH_4			(0x1 << 8) +#define RT5663_TDM_OUT_CH_6			(0x2 << 8) +#define RT5663_TDM_OUT_CH_8			(0x3 << 8) +#define RT5663_TDM_IN_LEN_MASK			(0x3 << 6) +#define RT5663_TDM_IN_LEN_SHIFT			6 +#define RT5663_TDM_IN_LEN_16			(0x0 << 6) +#define RT5663_TDM_IN_LEN_20			(0x1 << 6) +#define RT5663_TDM_IN_LEN_24			(0x2 << 6) +#define RT5663_TDM_IN_LEN_32			(0x3 << 6) +#define RT5663_TDM_OUT_LEN_MASK			(0x3 << 4) +#define RT5663_TDM_OUT_LEN_SHIFT		4 +#define RT5663_TDM_OUT_LEN_16			(0x0 << 4) +#define RT5663_TDM_OUT_LEN_20			(0x1 << 4) +#define RT5663_TDM_OUT_LEN_24			(0x2 << 4) +#define RT5663_TDM_OUT_LEN_32			(0x3 << 4)  /* Global Clock Control (0x0080) */ -#define RT5668_SCLK_SRC_MASK			(0x3 << 14) -#define RT5668_SCLK_SRC_SHIFT			14 -#define RT5668_SCLK_SRC_MCLK			(0x0 << 14) -#define RT5668_SCLK_SRC_PLL1			(0x1 << 14) -#define RT5668_SCLK_SRC_RCCLK			(0x2 << 14) -#define RT5668_PLL1_SRC_MASK			(0x7 << 8) -#define RT5668_PLL1_SRC_SHIFT			8 -#define RT5668_PLL1_SRC_MCLK			(0x0 << 8) -#define RT5668_PLL1_SRC_BCLK1			(0x1 << 8) -#define RT5668_PLL1_PD_MASK			(0x1 << 4) -#define RT5668_PLL1_PD_SHIFT			4 - -#define RT5668_PLL_INP_MAX			40000000 -#define RT5668_PLL_INP_MIN			256000 +#define RT5663_SCLK_SRC_MASK			(0x3 << 14) +#define RT5663_SCLK_SRC_SHIFT			14 +#define RT5663_SCLK_SRC_MCLK			(0x0 << 14) +#define RT5663_SCLK_SRC_PLL1			(0x1 << 14) +#define RT5663_SCLK_SRC_RCCLK			(0x2 << 14) +#define RT5663_PLL1_SRC_MASK			(0x7 << 11) +#define RT5663_PLL1_SRC_SHIFT			11 +#define RT5663_PLL1_SRC_MCLK			(0x0 << 11) +#define RT5663_PLL1_SRC_BCLK1			(0x1 << 11) +#define RT5663_V2_PLL1_SRC_MASK			(0x7 << 8) +#define RT5663_V2_PLL1_SRC_SHIFT		8 +#define RT5663_V2_PLL1_SRC_MCLK			(0x0 << 8) +#define RT5663_V2_PLL1_SRC_BCLK1		(0x1 << 8) +#define RT5663_PLL1_PD_MASK			(0x1 << 4) +#define RT5663_PLL1_PD_SHIFT			4 + +#define RT5663_PLL_INP_MAX			40000000 +#define RT5663_PLL_INP_MIN			256000  /* PLL M/N/K Code Control 1 (0x0081) */ -#define RT5668_PLL_N_MAX			0x001ff -#define RT5668_PLL_N_MASK			(RT5668_PLL_N_MAX << 7) -#define RT5668_PLL_N_SHIFT			7 -#define RT5668_PLL_K_MAX			0x001f -#define RT5668_PLL_K_MASK			(RT5668_PLL_K_MAX) -#define RT5668_PLL_K_SHIFT			0 +#define RT5663_PLL_N_MAX			0x001ff +#define RT5663_PLL_N_MASK			(RT5663_PLL_N_MAX << 7) +#define RT5663_PLL_N_SHIFT			7 +#define RT5663_PLL_K_MAX			0x001f +#define RT5663_PLL_K_MASK			(RT5663_PLL_K_MAX) +#define RT5663_PLL_K_SHIFT			0  /* PLL M/N/K Code Control 2 (0x0082) */ -#define RT5668_PLL_M_MAX			0x00f -#define RT5668_PLL_M_MASK			(RT5668_PLL_M_MAX << 12) -#define RT5668_PLL_M_SHIFT			12 -#define RT5668_PLL_M_BP				(0x1 << 11) -#define RT5668_PLL_M_BP_SHIFT			11 +#define RT5663_PLL_M_MAX			0x00f +#define RT5663_PLL_M_MASK			(RT5663_PLL_M_MAX << 12) +#define RT5663_PLL_M_SHIFT			12 +#define RT5663_PLL_M_BP				(0x1 << 11) +#define RT5663_PLL_M_BP_SHIFT			11  /* PLL tracking mode 1 (0x0083) */ -#define RT5668_I2S1_ASRC_MASK			(0x1 << 13) -#define RT5668_I2S1_ASRC_SHIFT			13 -#define RT5668_DAC_STO1_ASRC_MASK		(0x1 << 12) -#define RT5668_DAC_STO1_ASRC_SHIFT		12 -#define RT5668_ADC_STO1_ASRC_MASK		(0x1 << 4) -#define RT5668_ADC_STO1_ASRC_SHIFT		4 +#define RT5663_V2_I2S1_ASRC_MASK			(0x1 << 13) +#define RT5663_V2_I2S1_ASRC_SHIFT			13 +#define RT5663_V2_DAC_STO1_ASRC_MASK		(0x1 << 12) +#define RT5663_V2_DAC_STO1_ASRC_SHIFT		12 +#define RT5663_V2_ADC_STO1_ASRC_MASK		(0x1 << 4) +#define RT5663_V2_ADC_STO1_ASRC_SHIFT		4  /* PLL tracking mode 2 (0x0084)*/ -#define RT5668_DA_STO1_TRACK_MASK		(0x7 << 12) -#define RT5668_DA_STO1_TRACK_SHIFT		12 -#define RT5668_DA_STO1_TRACK_SYSCLK		(0x0 << 12) -#define RT5668_DA_STO1_TRACK_I2S1		(0x1 << 12) +#define RT5663_DA_STO1_TRACK_MASK		(0x7 << 12) +#define RT5663_DA_STO1_TRACK_SHIFT		12 +#define RT5663_DA_STO1_TRACK_SYSCLK		(0x0 << 12) +#define RT5663_DA_STO1_TRACK_I2S1		(0x1 << 12)  /* PLL tracking mode 3 (0x0085)*/ -#define RT5668_AD_STO1_TRACK_MASK		(0x7 << 12) -#define RT5668_AD_STO1_TRACK_SHIFT		12 -#define RT5668_AD_STO1_TRACK_SYSCLK		(0x0 << 12) -#define RT5668_AD_STO1_TRACK_I2S1		(0x1 << 12) +#define RT5663_V2_AD_STO1_TRACK_MASK		(0x7 << 12) +#define RT5663_V2_AD_STO1_TRACK_SHIFT		12 +#define RT5663_V2_AD_STO1_TRACK_SYSCLK		(0x0 << 12) +#define RT5663_V2_AD_STO1_TRACK_I2S1		(0x1 << 12)  /* HPOUT Charge pump control 1 (0x0091) */ -#define RT5668_OSW_HP_L_MASK			(0x1 << 11) -#define RT5668_OSW_HP_L_SHIFT			11 -#define RT5668_OSW_HP_L_EN			(0x1 << 11) -#define RT5668_OSW_HP_L_DIS			(0x0 << 11) -#define RT5668_OSW_HP_R_MASK			(0x1 << 10) -#define RT5668_OSW_HP_R_SHIFT			10 -#define RT5668_OSW_HP_R_EN			(0x1 << 10) -#define RT5668_OSW_HP_R_DIS			(0x0 << 10) -#define RT5668_SEL_PM_HP_MASK			(0x3 << 8) -#define RT5668_SEL_PM_HP_SHIFT			8 -#define RT5668_SEL_PM_HP_0_6			(0x0 << 8) -#define RT5668_SEL_PM_HP_0_9			(0x1 << 8) -#define RT5668_SEL_PM_HP_1_8			(0x2 << 8) -#define RT5668_SEL_PM_HP_HIGH			(0x3 << 8) -#define RT5668_OVCD_HP_MASK			(0x1 << 2) -#define RT5668_OVCD_HP_SHIFT			2 -#define RT5668_OVCD_HP_EN			(0x1 << 2) -#define RT5668_OVCD_HP_DIS			(0x0 << 2) +#define RT5663_OSW_HP_L_MASK			(0x1 << 11) +#define RT5663_OSW_HP_L_SHIFT			11 +#define RT5663_OSW_HP_L_EN			(0x1 << 11) +#define RT5663_OSW_HP_L_DIS			(0x0 << 11) +#define RT5663_OSW_HP_R_MASK			(0x1 << 10) +#define RT5663_OSW_HP_R_SHIFT			10 +#define RT5663_OSW_HP_R_EN			(0x1 << 10) +#define RT5663_OSW_HP_R_DIS			(0x0 << 10) +#define RT5663_SEL_PM_HP_MASK			(0x3 << 8) +#define RT5663_SEL_PM_HP_SHIFT			8 +#define RT5663_SEL_PM_HP_0_6			(0x0 << 8) +#define RT5663_SEL_PM_HP_0_9			(0x1 << 8) +#define RT5663_SEL_PM_HP_1_8			(0x2 << 8) +#define RT5663_SEL_PM_HP_HIGH			(0x3 << 8) +#define RT5663_OVCD_HP_MASK			(0x1 << 2) +#define RT5663_OVCD_HP_SHIFT			2 +#define RT5663_OVCD_HP_EN			(0x1 << 2) +#define RT5663_OVCD_HP_DIS			(0x0 << 2)  /* RC Clock Control (0x0094) */ -#define RT5668_DIG_25M_CLK_MASK			(0x1 << 9) -#define RT5668_DIG_25M_CLK_SHIFT		9 -#define RT5668_DIG_25M_CLK_DIS			(0x0 << 9) -#define RT5668_DIG_25M_CLK_EN			(0x1 << 9) -#define RT5668_DIG_1M_CLK_MASK			(0x1 << 8) -#define RT5668_DIG_1M_CLK_SHIFT			8 -#define RT5668_DIG_1M_CLK_DIS			(0x0 << 8) -#define RT5668_DIG_1M_CLK_EN			(0x1 << 8) +#define RT5663_DIG_25M_CLK_MASK			(0x1 << 9) +#define RT5663_DIG_25M_CLK_SHIFT		9 +#define RT5663_DIG_25M_CLK_DIS			(0x0 << 9) +#define RT5663_DIG_25M_CLK_EN			(0x1 << 9) +#define RT5663_DIG_1M_CLK_MASK			(0x1 << 8) +#define RT5663_DIG_1M_CLK_SHIFT			8 +#define RT5663_DIG_1M_CLK_DIS			(0x0 << 8) +#define RT5663_DIG_1M_CLK_EN			(0x1 << 8)  /* Auto Turn On 1M RC CLK (0x009f) */ -#define RT5668_IRQ_POW_SAV_MASK			(0x1 << 15) -#define RT5668_IRQ_POW_SAV_SHIFT		15 -#define RT5668_IRQ_POW_SAV_DIS			(0x0 << 15) -#define RT5668_IRQ_POW_SAV_EN			(0x1 << 15) -#define RT5668_IRQ_POW_SAV_JD1_MASK		(0x1 << 14) -#define RT5668_IRQ_POW_SAV_JD1_SHIFT		14 -#define RT5668_IRQ_POW_SAV_JD1_DIS		(0x0 << 14) -#define RT5668_IRQ_POW_SAV_JD1_EN		(0x1 << 14) +#define RT5663_IRQ_POW_SAV_MASK			(0x1 << 15) +#define RT5663_IRQ_POW_SAV_SHIFT		15 +#define RT5663_IRQ_POW_SAV_DIS			(0x0 << 15) +#define RT5663_IRQ_POW_SAV_EN			(0x1 << 15) +#define RT5663_IRQ_POW_SAV_JD1_MASK		(0x1 << 14) +#define RT5663_IRQ_POW_SAV_JD1_SHIFT		14 +#define RT5663_IRQ_POW_SAV_JD1_DIS		(0x0 << 14) +#define RT5663_IRQ_POW_SAV_JD1_EN		(0x1 << 14)  /* IRQ Control 1 (0x00b6) */ -#define RT5668_EN_CB_JD_MASK			(0x1 << 3) -#define RT5668_EN_CB_JD_SHIFT			3 -#define RT5668_EN_CB_JD_EN			(0x1 << 3) -#define RT5668_EN_CB_JD_DIS			(0x0 << 3) +#define RT5663_EN_CB_JD_MASK			(0x1 << 3) +#define RT5663_EN_CB_JD_SHIFT			3 +#define RT5663_EN_CB_JD_EN			(0x1 << 3) +#define RT5663_EN_CB_JD_DIS			(0x0 << 3)  /* IRQ Control 3 (0x00b8) */ -#define RT5668_EN_IRQ_INLINE_MASK		(0x1 << 6) -#define RT5668_EN_IRQ_INLINE_SHIFT		6 -#define RT5668_EN_IRQ_INLINE_BYP		(0x0 << 6) -#define RT5668_EN_IRQ_INLINE_NOR		(0x1 << 6) +#define RT5663_V2_EN_IRQ_INLINE_MASK		(0x1 << 6) +#define RT5663_V2_EN_IRQ_INLINE_SHIFT		6 +#define RT5663_V2_EN_IRQ_INLINE_BYP		(0x0 << 6) +#define RT5663_V2_EN_IRQ_INLINE_NOR		(0x1 << 6)  /* GPIO Control 1 (0x00c0) */ -#define RT5668_GP1_PIN_MASK			(0x1 << 15) -#define RT5668_GP1_PIN_SHIFT			15 -#define RT5668_GP1_PIN_GPIO1			(0x0 << 15) -#define RT5668_GP1_PIN_IRQ			(0x1 << 15) +#define RT5663_GP1_PIN_MASK			(0x1 << 15) +#define RT5663_GP1_PIN_SHIFT			15 +#define RT5663_GP1_PIN_GPIO1			(0x0 << 15) +#define RT5663_GP1_PIN_IRQ			(0x1 << 15)  /* GPIO Control 2 (0x00c1) */ -#define RT5668_GP4_PIN_CONF_MASK		(0x1 << 5) -#define RT5668_GP4_PIN_CONF_SHIFT		5 -#define RT5668_GP4_PIN_CONF_INPUT		(0x0 << 5) -#define RT5668_GP4_PIN_CONF_OUTPUT		(0x1 << 5) +#define RT5663_GP4_PIN_CONF_MASK		(0x1 << 5) +#define RT5663_GP4_PIN_CONF_SHIFT		5 +#define RT5663_GP4_PIN_CONF_INPUT		(0x0 << 5) +#define RT5663_GP4_PIN_CONF_OUTPUT		(0x1 << 5)  /* GPIO Control 2 (0x00c2) */ -#define RT5668_GP8_PIN_CONF_MASK		(0x1 << 13) -#define RT5668_GP8_PIN_CONF_SHIFT		13 -#define RT5668_GP8_PIN_CONF_INPUT		(0x0 << 13) -#define RT5668_GP8_PIN_CONF_OUTPUT		(0x1 << 13) +#define RT5663_GP8_PIN_CONF_MASK		(0x1 << 13) +#define RT5663_GP8_PIN_CONF_SHIFT		13 +#define RT5663_GP8_PIN_CONF_INPUT		(0x0 << 13) +#define RT5663_GP8_PIN_CONF_OUTPUT		(0x1 << 13)  /* 4 Buttons Inline Command Function 1 (0x00df) */ -#define RT5668_4BTN_CLK_DEB_MASK		(0x3 << 2) -#define RT5668_4BTN_CLK_DEB_SHIFT		2 -#define RT5668_4BTN_CLK_DEB_8MS			(0x0 << 2) -#define RT5668_4BTN_CLK_DEB_16MS		(0x1 << 2) -#define RT5668_4BTN_CLK_DEB_32MS		(0x2 << 2) -#define RT5668_4BTN_CLK_DEB_65MS		(0x3 << 2) +#define RT5663_4BTN_CLK_DEB_MASK		(0x3 << 2) +#define RT5663_4BTN_CLK_DEB_SHIFT		2 +#define RT5663_4BTN_CLK_DEB_8MS			(0x0 << 2) +#define RT5663_4BTN_CLK_DEB_16MS		(0x1 << 2) +#define RT5663_4BTN_CLK_DEB_32MS		(0x2 << 2) +#define RT5663_4BTN_CLK_DEB_65MS		(0x3 << 2)  /* Inline Command Function 6 (0x00e0) */ -#define RT5668_EN_4BTN_INL_MASK			(0x1 << 15) -#define RT5668_EN_4BTN_INL_SHIFT		15 -#define RT5668_EN_4BTN_INL_DIS			(0x0 << 15) -#define RT5668_EN_4BTN_INL_EN			(0x1 << 15) -#define RT5668_RESET_4BTN_INL_MASK		(0x1 << 14) -#define RT5668_RESET_4BTN_INL_SHIFT		14 -#define RT5668_RESET_4BTN_INL_RESET		(0x0 << 14) -#define RT5668_RESET_4BTN_INL_NOR		(0x1 << 14) +#define RT5663_EN_4BTN_INL_MASK			(0x1 << 15) +#define RT5663_EN_4BTN_INL_SHIFT		15 +#define RT5663_EN_4BTN_INL_DIS			(0x0 << 15) +#define RT5663_EN_4BTN_INL_EN			(0x1 << 15) +#define RT5663_RESET_4BTN_INL_MASK		(0x1 << 14) +#define RT5663_RESET_4BTN_INL_SHIFT		14 +#define RT5663_RESET_4BTN_INL_RESET		(0x0 << 14) +#define RT5663_RESET_4BTN_INL_NOR		(0x1 << 14)  /* Digital Misc Control (0x00fa) */ -#define RT5668_DIG_GATE_CTRL_MASK		0x1 -#define RT5668_DIG_GATE_CTRL_SHIFT		(0) -#define RT5668_DIG_GATE_CTRL_DIS		0x0 -#define RT5668_DIG_GATE_CTRL_EN			0x1 +#define RT5663_DIG_GATE_CTRL_MASK		0x1 +#define RT5663_DIG_GATE_CTRL_SHIFT		(0) +#define RT5663_DIG_GATE_CTRL_DIS		0x0 +#define RT5663_DIG_GATE_CTRL_EN			0x1  /* Chopper and Clock control for DAC L (0x013a)*/ -#define RT5668_CKXEN_DAC1_MASK			(0x1 << 13) -#define RT5668_CKXEN_DAC1_SHIFT			13 -#define RT5668_CKGEN_DAC1_MASK			(0x1 << 12) -#define RT5668_CKGEN_DAC1_SHIFT			12 +#define RT5663_CKXEN_DAC1_MASK			(0x1 << 13) +#define RT5663_CKXEN_DAC1_SHIFT			13 +#define RT5663_CKGEN_DAC1_MASK			(0x1 << 12) +#define RT5663_CKGEN_DAC1_SHIFT			12  /* Chopper and Clock control for ADC (0x013b)*/ -#define RT5668_CKXEN_ADCC_MASK			(0x1 << 13) -#define RT5668_CKXEN_ADCC_SHIFT			13 -#define RT5668_CKGEN_ADCC_MASK			(0x1 << 12) -#define RT5668_CKGEN_ADCC_SHIFT			12 +#define RT5663_CKXEN_ADCC_MASK			(0x1 << 13) +#define RT5663_CKXEN_ADCC_SHIFT			13 +#define RT5663_CKGEN_ADCC_MASK			(0x1 << 12) +#define RT5663_CKGEN_ADCC_SHIFT			12  /* HP Behavior Logic Control 2 (0x01db) */ -#define RT5668_HP_SIG_SRC1_MASK			(0x3) -#define RT5668_HP_SIG_SRC1_SHIFT		0 -#define RT5668_HP_SIG_SRC1_HP_DC		(0x0) -#define RT5668_HP_SIG_SRC1_HP_CALIB		(0x1) -#define RT5668_HP_SIG_SRC1_REG			(0x2) -#define RT5668_HP_SIG_SRC1_SILENCE		(0x3) +#define RT5663_HP_SIG_SRC1_MASK			(0x3) +#define RT5663_HP_SIG_SRC1_SHIFT		0 +#define RT5663_HP_SIG_SRC1_HP_DC		(0x0) +#define RT5663_HP_SIG_SRC1_HP_CALIB		(0x1) +#define RT5663_HP_SIG_SRC1_REG			(0x2) +#define RT5663_HP_SIG_SRC1_SILENCE		(0x3)  /* RT5663 specific register */  #define RT5663_HP_OUT_EN			0x0002 @@ -707,6 +704,10 @@  #define RT5663_TDM_3				0x0079  #define RT5663_TDM_4				0x007a  #define RT5663_TDM_5				0x007b +#define RT5663_TDM_6				0x007c +#define RT5663_TDM_7				0x007d +#define RT5663_TDM_8				0x007e +#define RT5663_TDM_9				0x007f  #define RT5663_GLB_CLK				0x0080  #define RT5663_PLL_1				0x0081  #define RT5663_PLL_2				0x0082 @@ -739,7 +740,7 @@  #define RT5663_INT_ST_2				0x00bf  #define RT5663_GPIO_1				0x00c0  #define RT5663_GPIO_2				0x00c1 -#define RT5663_GPIO_STA				0x00c5 +#define RT5663_GPIO_STA1			0x00c5  #define RT5663_SIN_GEN_1			0x00cb  #define RT5663_SIN_GEN_2			0x00cc  #define RT5663_SIN_GEN_3			0x00cd @@ -800,6 +801,8 @@  #define RT5663_TEST_MODE_1			0x0144  #define RT5663_TEST_MODE_2			0x0145  #define RT5663_TEST_MODE_3			0x0146 +#define RT5663_TEST_MODE_4			0x0147 +#define RT5663_TEST_MODE_5			0x0148  #define RT5663_STO_DRE_1			0x0160  #define RT5663_STO_DRE_2			0x0161  #define RT5663_STO_DRE_3			0x0162 @@ -921,19 +924,19 @@  #define RT5663_ADC_EQ_POST_VOL_L		0x03f2  #define RT5663_ADC_EQ_POST_VOL_R		0x03f3 -/* RT5663: RECMIX Control (0x0010) */ +/* RECMIX Control (0x0010) */  #define RT5663_RECMIX1_BST1_MASK		(0x1)  #define RT5663_RECMIX1_BST1_SHIFT		0  #define RT5663_RECMIX1_BST1_ON			(0x0)  #define RT5663_RECMIX1_BST1_OFF			(0x1) -/* RT5663: Bypass Stereo1 DAC Mixer Control (0x002d) */ +/* Bypass Stereo1 DAC Mixer Control (0x002d) */  #define RT5663_DACL1_SRC_MASK			(0x1 << 3)  #define RT5663_DACL1_SRC_SHIFT			3  #define RT5663_DACR1_SRC_MASK			(0x1 << 2)  #define RT5663_DACR1_SRC_SHIFT			2 -/* RT5663: TDM control 2 (0x0078) */ +/* TDM control 2 (0x0078) */  #define RT5663_DATA_SWAP_ADCDAT1_MASK		(0x3 << 14)  #define RT5663_DATA_SWAP_ADCDAT1_SHIFT		14  #define RT5663_DATA_SWAP_ADCDAT1_LR		(0x0 << 14) @@ -941,7 +944,7 @@  #define RT5663_DATA_SWAP_ADCDAT1_LL		(0x2 << 14)  #define RT5663_DATA_SWAP_ADCDAT1_RR		(0x3 << 14) -/* RT5663: TDM control 5 (0x007b) */ +/* TDM control 5 (0x007b) */  #define RT5663_TDM_LENGTN_MASK			(0x3)  #define RT5663_TDM_LENGTN_SHIFT			0  #define RT5663_TDM_LENGTN_16			(0x0) @@ -949,17 +952,6 @@  #define RT5663_TDM_LENGTN_24			(0x2)  #define RT5663_TDM_LENGTN_32			(0x3) -/* RT5663: Global Clock Control (0x0080) */ -#define RT5663_SCLK_SRC_MASK			(0x3 << 14) -#define RT5663_SCLK_SRC_SHIFT			14 -#define RT5663_SCLK_SRC_MCLK			(0x0 << 14) -#define RT5663_SCLK_SRC_PLL1			(0x1 << 14) -#define RT5663_SCLK_SRC_RCCLK			(0x2 << 14) -#define RT5663_PLL1_SRC_MASK			(0x7 << 11) -#define RT5663_PLL1_SRC_SHIFT			11 -#define RT5663_PLL1_SRC_MCLK			(0x0 << 11) -#define RT5663_PLL1_SRC_BCLK1			(0x1 << 11) -  /* PLL tracking mode 1 (0x0083) */  #define RT5663_I2S1_ASRC_MASK			(0x1 << 11)  #define RT5663_I2S1_ASRC_SHIFT			11 @@ -978,37 +970,47 @@  #define RT5663_AD_STO1_TRACK_SYSCLK		(0x0)  #define RT5663_AD_STO1_TRACK_I2S1		(0x1) -/* RT5663: HPOUT Charge pump control 1 (0x0091) */ +/* HPOUT Charge pump control 1 (0x0091) */  #define RT5663_SI_HP_MASK			(0x1 << 12)  #define RT5663_SI_HP_SHIFT			12  #define RT5663_SI_HP_EN				(0x1 << 12)  #define RT5663_SI_HP_DIS			(0x0 << 12) -/* RT5663: GPIO Control 2 (0x00b6) */ +/* GPIO Control 2 (0x00b6) */  #define RT5663_GP1_PIN_CONF_MASK		(0x1 << 2)  #define RT5663_GP1_PIN_CONF_SHIFT		2  #define RT5663_GP1_PIN_CONF_OUTPUT		(0x1 << 2)  #define RT5663_GP1_PIN_CONF_INPUT		(0x0 << 2) -/* RT5663: GPIO Control 2 (0x00b7) */ +/* GPIO Control 2 (0x00b7) */  #define RT5663_EN_IRQ_INLINE_MASK		(0x1 << 3)  #define RT5663_EN_IRQ_INLINE_SHIFT		3  #define RT5663_EN_IRQ_INLINE_NOR		(0x1 << 3)  #define RT5663_EN_IRQ_INLINE_BYP		(0x0 << 3) -/* RT5663: IRQ Control 1 (0x00c1) */ +/* GPIO Control 1 (0x00c0) */ +#define RT5663_GPIO1_TYPE_MASK			(0x1 << 15) +#define RT5663_GPIO1_TYPE_SHIFT			15 +#define RT5663_GPIO1_TYPE_EN			(0x1 << 15) +#define RT5663_GPIO1_TYPE_DIS			(0x0 << 15) + +/* IRQ Control 1 (0x00c1) */  #define RT5663_EN_IRQ_JD1_MASK			(0x1 << 6)  #define RT5663_EN_IRQ_JD1_SHIFT			6  #define RT5663_EN_IRQ_JD1_EN			(0x1 << 6)  #define RT5663_EN_IRQ_JD1_DIS			(0x0 << 6) +#define RT5663_SEL_GPIO1_MASK			(0x1 << 2) +#define RT5663_SEL_GPIO1_SHIFT			6 +#define RT5663_SEL_GPIO1_EN			(0x1 << 2) +#define RT5663_SEL_GPIO1_DIS			(0x0 << 2) -/* RT5663: Inline Command Function 2 (0x00dc) */ +/* Inline Command Function 2 (0x00dc) */  #define RT5663_PWR_MIC_DET_MASK			(0x1)  #define RT5663_PWR_MIC_DET_SHIFT		0  #define RT5663_PWR_MIC_DET_ON			(0x1)  #define RT5663_PWR_MIC_DET_OFF			(0x0) -/* RT5663: Embeeded Jack and Type Detection Control 1 (0x00e6)*/ +/* Embeeded Jack and Type Detection Control 1 (0x00e6)*/  #define RT5663_CBJ_DET_MASK			(0x1 << 15)  #define RT5663_CBJ_DET_SHIFT			15  #define RT5663_CBJ_DET_DIS			(0x0 << 15) @@ -1022,17 +1024,17 @@  #define RT5663_POL_EXT_JD_EN			(0x1 << 10)  #define RT5663_POL_EXT_JD_DIS			(0x0 << 10) -/* RT5663: DACREF LDO Control (0x0112)*/ +/* DACREF LDO Control (0x0112)*/  #define RT5663_PWR_LDO_DACREFL_MASK		(0x1 << 9)  #define RT5663_PWR_LDO_DACREFL_SHIFT		9  #define RT5663_PWR_LDO_DACREFR_MASK		(0x1 << 1)  #define RT5663_PWR_LDO_DACREFR_SHIFT		1 -/* RT5663: Stereo Dynamic Range Enhancement Control 9 (0x0168, 0x0169)*/ +/* Stereo Dynamic Range Enhancement Control 9 (0x0168, 0x0169)*/  #define RT5663_DRE_GAIN_HP_MASK			(0x1f)  #define RT5663_DRE_GAIN_HP_SHIFT		0 -/* RT5663: Combo Jack Control (0x0250) */ +/* Combo Jack Control (0x0250) */  #define RT5663_INBUF_CBJ_BST1_MASK		(0x1 << 11)  #define RT5663_INBUF_CBJ_BST1_SHIFT		11  #define RT5663_INBUF_CBJ_BST1_ON		(0x1 << 11) @@ -1042,11 +1044,11 @@  #define RT5663_CBJ_SENSE_BST1_L			(0x1 << 10)  #define RT5663_CBJ_SENSE_BST1_R			(0x0 << 10) -/* RT5663: Combo Jack Control (0x0251) */ +/* Combo Jack Control (0x0251) */  #define RT5663_GAIN_BST1_MASK			(0xf)  #define RT5663_GAIN_BST1_SHIFT			0 -/* RT5663: Dummy register 1 (0x02fa) */ +/* Dummy register 1 (0x02fa) */  #define RT5663_EMB_CLK_MASK			(0x1 << 9)  #define RT5663_EMB_CLK_SHIFT			9  #define RT5663_EMB_CLK_EN			(0x1 << 9) diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c new file mode 100644 index 000000000000..324461e985b3 --- /dev/null +++ b/sound/soc/codecs/rt5665.c @@ -0,0 +1,4874 @@ +/* + * rt5665.c  --  RT5665/RT5658 ALSA SoC audio codec driver + * + * Copyright 2016 Realtek Semiconductor Corp. + * Author: Bard Liao <bardliao@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/acpi.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/regulator/consumer.h> +#include <linux/mutex.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/jack.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <sound/rt5665.h> + +#include "rl6231.h" +#include "rt5665.h" + +#define RT5665_NUM_SUPPLIES 3 + +static const char *rt5665_supply_names[RT5665_NUM_SUPPLIES] = { +	"AVDD", +	"MICVDD", +	"VBAT", +}; + +struct rt5665_priv { +	struct snd_soc_codec *codec; +	struct rt5665_platform_data pdata; +	struct regmap *regmap; +	struct gpio_desc *gpiod_ldo1_en; +	struct gpio_desc *gpiod_reset; +	struct snd_soc_jack *hs_jack; +	struct regulator_bulk_data supplies[RT5665_NUM_SUPPLIES]; +	struct delayed_work jack_detect_work; +	struct delayed_work calibrate_work; +	struct delayed_work jd_check_work; +	struct mutex calibrate_mutex; + +	int sysclk; +	int sysclk_src; +	int lrck[RT5665_AIFS]; +	int bclk[RT5665_AIFS]; +	int master[RT5665_AIFS]; +	int id; + +	int pll_src; +	int pll_in; +	int pll_out; + +	int jack_type; +	int irq_work_delay_time; +	unsigned int sar_adc_value; +}; + +static const struct reg_default rt5665_reg[] = { +	{0x0000, 0x0000}, +	{0x0001, 0xc8c8}, +	{0x0002, 0x8080}, +	{0x0003, 0x8000}, +	{0x0004, 0xc80a}, +	{0x0005, 0x0000}, +	{0x0006, 0x0000}, +	{0x0007, 0x0000}, +	{0x000a, 0x0000}, +	{0x000b, 0x0000}, +	{0x000c, 0x0000}, +	{0x000d, 0x0000}, +	{0x000f, 0x0808}, +	{0x0010, 0x4040}, +	{0x0011, 0x0000}, +	{0x0012, 0x1404}, +	{0x0013, 0x1000}, +	{0x0014, 0xa00a}, +	{0x0015, 0x0404}, +	{0x0016, 0x0404}, +	{0x0017, 0x0011}, +	{0x0018, 0xafaf}, +	{0x0019, 0xafaf}, +	{0x001a, 0xafaf}, +	{0x001b, 0x0011}, +	{0x001c, 0x2f2f}, +	{0x001d, 0x2f2f}, +	{0x001e, 0x2f2f}, +	{0x001f, 0x0000}, +	{0x0020, 0x0000}, +	{0x0021, 0x0000}, +	{0x0022, 0x5757}, +	{0x0023, 0x0039}, +	{0x0026, 0xc0c0}, +	{0x0027, 0xc0c0}, +	{0x0028, 0xc0c0}, +	{0x0029, 0x8080}, +	{0x002a, 0xaaaa}, +	{0x002b, 0xaaaa}, +	{0x002c, 0xaba8}, +	{0x002d, 0x0000}, +	{0x002e, 0x0000}, +	{0x002f, 0x0000}, +	{0x0030, 0x0000}, +	{0x0031, 0x5000}, +	{0x0032, 0x0000}, +	{0x0033, 0x0000}, +	{0x0034, 0x0000}, +	{0x0035, 0x0000}, +	{0x003a, 0x0000}, +	{0x003b, 0x0000}, +	{0x003c, 0x00ff}, +	{0x003d, 0x0000}, +	{0x003e, 0x00ff}, +	{0x003f, 0x0000}, +	{0x0040, 0x0000}, +	{0x0041, 0x00ff}, +	{0x0042, 0x0000}, +	{0x0043, 0x00ff}, +	{0x0044, 0x0c0c}, +	{0x0049, 0xc00b}, +	{0x004a, 0x0000}, +	{0x004b, 0x031f}, +	{0x004d, 0x0000}, +	{0x004e, 0x001f}, +	{0x004f, 0x0000}, +	{0x0050, 0x001f}, +	{0x0052, 0xf000}, +	{0x0061, 0x0000}, +	{0x0062, 0x0000}, +	{0x0063, 0x003e}, +	{0x0064, 0x0000}, +	{0x0065, 0x0000}, +	{0x0066, 0x003f}, +	{0x0067, 0x0000}, +	{0x006b, 0x0000}, +	{0x006d, 0xff00}, +	{0x006e, 0x2808}, +	{0x006f, 0x000a}, +	{0x0070, 0x8000}, +	{0x0071, 0x8000}, +	{0x0072, 0x8000}, +	{0x0073, 0x7000}, +	{0x0074, 0x7770}, +	{0x0075, 0x0002}, +	{0x0076, 0x0001}, +	{0x0078, 0x00f0}, +	{0x0079, 0x0000}, +	{0x007a, 0x0000}, +	{0x007b, 0x0000}, +	{0x007c, 0x0000}, +	{0x007d, 0x0123}, +	{0x007e, 0x4500}, +	{0x007f, 0x8003}, +	{0x0080, 0x0000}, +	{0x0081, 0x0000}, +	{0x0082, 0x0000}, +	{0x0083, 0x0000}, +	{0x0084, 0x0000}, +	{0x0085, 0x0000}, +	{0x0086, 0x0008}, +	{0x0087, 0x0000}, +	{0x0088, 0x0000}, +	{0x0089, 0x0000}, +	{0x008a, 0x0000}, +	{0x008b, 0x0000}, +	{0x008c, 0x0003}, +	{0x008e, 0x0060}, +	{0x008f, 0x1000}, +	{0x0091, 0x0c26}, +	{0x0092, 0x0073}, +	{0x0093, 0x0000}, +	{0x0094, 0x0080}, +	{0x0098, 0x0000}, +	{0x0099, 0x0000}, +	{0x009a, 0x0007}, +	{0x009f, 0x0000}, +	{0x00a0, 0x0000}, +	{0x00a1, 0x0002}, +	{0x00a2, 0x0001}, +	{0x00a3, 0x0002}, +	{0x00a4, 0x0001}, +	{0x00ae, 0x2040}, +	{0x00af, 0x0000}, +	{0x00b6, 0x0000}, +	{0x00b7, 0x0000}, +	{0x00b8, 0x0000}, +	{0x00b9, 0x0000}, +	{0x00ba, 0x0002}, +	{0x00bb, 0x0000}, +	{0x00be, 0x0000}, +	{0x00c0, 0x0000}, +	{0x00c1, 0x0aaa}, +	{0x00c2, 0xaa80}, +	{0x00c3, 0x0003}, +	{0x00c4, 0x0000}, +	{0x00d0, 0x0000}, +	{0x00d1, 0x2244}, +	{0x00d3, 0x3300}, +	{0x00d4, 0x2200}, +	{0x00d9, 0x0809}, +	{0x00da, 0x0000}, +	{0x00db, 0x0008}, +	{0x00dc, 0x00c0}, +	{0x00dd, 0x6724}, +	{0x00de, 0x3131}, +	{0x00df, 0x0008}, +	{0x00e0, 0x4000}, +	{0x00e1, 0x3131}, +	{0x00e2, 0x600c}, +	{0x00ea, 0xb320}, +	{0x00eb, 0x0000}, +	{0x00ec, 0xb300}, +	{0x00ed, 0x0000}, +	{0x00ee, 0xb320}, +	{0x00ef, 0x0000}, +	{0x00f0, 0x0201}, +	{0x00f1, 0x0ddd}, +	{0x00f2, 0x0ddd}, +	{0x00f6, 0x0000}, +	{0x00f7, 0x0000}, +	{0x00f8, 0x0000}, +	{0x00fa, 0x0000}, +	{0x00fb, 0x0000}, +	{0x00fc, 0x0000}, +	{0x00fd, 0x0000}, +	{0x00fe, 0x10ec}, +	{0x00ff, 0x6451}, +	{0x0100, 0xaaaa}, +	{0x0101, 0x000a}, +	{0x010a, 0xaaaa}, +	{0x010b, 0xa0a0}, +	{0x010c, 0xaeae}, +	{0x010d, 0xaaaa}, +	{0x010e, 0xaaaa}, +	{0x010f, 0xaaaa}, +	{0x0110, 0xe002}, +	{0x0111, 0xa402}, +	{0x0112, 0xaaaa}, +	{0x0113, 0x2000}, +	{0x0117, 0x0f00}, +	{0x0125, 0x0410}, +	{0x0132, 0x0000}, +	{0x0133, 0x0000}, +	{0x0137, 0x5540}, +	{0x0138, 0x3700}, +	{0x0139, 0x79a1}, +	{0x013a, 0x2020}, +	{0x013b, 0x2020}, +	{0x013c, 0x2005}, +	{0x013f, 0x0000}, +	{0x0145, 0x0002}, +	{0x0146, 0x0000}, +	{0x0147, 0x0000}, +	{0x0148, 0x0000}, +	{0x0150, 0x0000}, +	{0x0160, 0x4eff}, +	{0x0161, 0x0080}, +	{0x0162, 0x0200}, +	{0x0163, 0x0800}, +	{0x0164, 0x0000}, +	{0x0165, 0x0000}, +	{0x0166, 0x0000}, +	{0x0167, 0x000f}, +	{0x0170, 0x4e87}, +	{0x0171, 0x0080}, +	{0x0172, 0x0200}, +	{0x0173, 0x0800}, +	{0x0174, 0x00ff}, +	{0x0175, 0x0000}, +	{0x0190, 0x413d}, +	{0x0191, 0x4139}, +	{0x0192, 0x4135}, +	{0x0193, 0x413d}, +	{0x0194, 0x0000}, +	{0x0195, 0x0000}, +	{0x0196, 0x0000}, +	{0x0197, 0x0000}, +	{0x0198, 0x0000}, +	{0x0199, 0x0000}, +	{0x01a0, 0x1e64}, +	{0x01a1, 0x06a3}, +	{0x01a2, 0x0000}, +	{0x01a3, 0x0000}, +	{0x01a4, 0x0000}, +	{0x01a5, 0x0000}, +	{0x01a6, 0x0000}, +	{0x01a7, 0x8000}, +	{0x01a8, 0x0000}, +	{0x01a9, 0x0000}, +	{0x01aa, 0x0000}, +	{0x01ab, 0x0000}, +	{0x01b5, 0x0000}, +	{0x01b6, 0x01c3}, +	{0x01b7, 0x02a0}, +	{0x01b8, 0x03e9}, +	{0x01b9, 0x1389}, +	{0x01ba, 0xc351}, +	{0x01bb, 0x0009}, +	{0x01bc, 0x0018}, +	{0x01bd, 0x002a}, +	{0x01be, 0x004c}, +	{0x01bf, 0x0097}, +	{0x01c0, 0x433d}, +	{0x01c1, 0x0000}, +	{0x01c2, 0x0000}, +	{0x01c3, 0x0000}, +	{0x01c4, 0x0000}, +	{0x01c5, 0x0000}, +	{0x01c6, 0x0000}, +	{0x01c7, 0x0000}, +	{0x01c8, 0x40af}, +	{0x01c9, 0x0702}, +	{0x01ca, 0x0000}, +	{0x01cb, 0x0000}, +	{0x01cc, 0x5757}, +	{0x01cd, 0x5757}, +	{0x01ce, 0x5757}, +	{0x01cf, 0x5757}, +	{0x01d0, 0x5757}, +	{0x01d1, 0x5757}, +	{0x01d2, 0x5757}, +	{0x01d3, 0x5757}, +	{0x01d4, 0x5757}, +	{0x01d5, 0x5757}, +	{0x01d6, 0x003c}, +	{0x01da, 0x0000}, +	{0x01db, 0x0000}, +	{0x01dc, 0x0000}, +	{0x01de, 0x7c00}, +	{0x01df, 0x0320}, +	{0x01e0, 0x06a1}, +	{0x01e1, 0x0000}, +	{0x01e2, 0x0000}, +	{0x01e3, 0x0000}, +	{0x01e4, 0x0000}, +	{0x01e6, 0x0001}, +	{0x01e7, 0x0000}, +	{0x01e8, 0x0000}, +	{0x01ea, 0xbf3f}, +	{0x01eb, 0x0000}, +	{0x01ec, 0x0000}, +	{0x01ed, 0x0000}, +	{0x01ee, 0x0000}, +	{0x01ef, 0x0000}, +	{0x01f0, 0x0000}, +	{0x01f1, 0x0000}, +	{0x01f2, 0x0000}, +	{0x01f3, 0x0000}, +	{0x01f4, 0x0000}, +	{0x0200, 0x0000}, +	{0x0201, 0x0000}, +	{0x0202, 0x0000}, +	{0x0203, 0x0000}, +	{0x0204, 0x0000}, +	{0x0205, 0x0000}, +	{0x0206, 0x0000}, +	{0x0207, 0x0000}, +	{0x0208, 0x0000}, +	{0x0210, 0x60b1}, +	{0x0211, 0xa005}, +	{0x0212, 0x024c}, +	{0x0213, 0xf7ff}, +	{0x0214, 0x024c}, +	{0x0215, 0x0102}, +	{0x0216, 0x00a3}, +	{0x0217, 0x0048}, +	{0x0218, 0xa2c0}, +	{0x0219, 0x0400}, +	{0x021a, 0x00c8}, +	{0x021b, 0x00c0}, +	{0x02ff, 0x0110}, +	{0x0300, 0x001f}, +	{0x0301, 0x032c}, +	{0x0302, 0x5f21}, +	{0x0303, 0x4000}, +	{0x0304, 0x4000}, +	{0x0305, 0x06d5}, +	{0x0306, 0x8000}, +	{0x0307, 0x0700}, +	{0x0310, 0x4560}, +	{0x0311, 0xa4a8}, +	{0x0312, 0x7418}, +	{0x0313, 0x0000}, +	{0x0314, 0x0006}, +	{0x0315, 0xffff}, +	{0x0316, 0xc400}, +	{0x0317, 0x0000}, +	{0x0330, 0x00a6}, +	{0x0331, 0x04c3}, +	{0x0332, 0x27c8}, +	{0x0333, 0xbf50}, +	{0x0334, 0x0045}, +	{0x0335, 0x0007}, +	{0x0336, 0x7418}, +	{0x0337, 0x0501}, +	{0x0338, 0x0000}, +	{0x0339, 0x0010}, +	{0x033a, 0x1010}, +	{0x03c0, 0x7e00}, +	{0x03c1, 0x8000}, +	{0x03c2, 0x8000}, +	{0x03c3, 0x8000}, +	{0x03c4, 0x8000}, +	{0x03c5, 0x8000}, +	{0x03c6, 0x8000}, +	{0x03c7, 0x8000}, +	{0x03c8, 0x8000}, +	{0x03c9, 0x8000}, +	{0x03ca, 0x8000}, +	{0x03cb, 0x8000}, +	{0x03cc, 0x8000}, +	{0x03d0, 0x0000}, +	{0x03d1, 0x0000}, +	{0x03d2, 0x0000}, +	{0x03d3, 0x0000}, +	{0x03d4, 0x2000}, +	{0x03d5, 0x2000}, +	{0x03d6, 0x0000}, +	{0x03d7, 0x0000}, +	{0x03d8, 0x2000}, +	{0x03d9, 0x2000}, +	{0x03da, 0x2000}, +	{0x03db, 0x2000}, +	{0x03dc, 0x0000}, +	{0x03dd, 0x0000}, +	{0x03de, 0x0000}, +	{0x03df, 0x2000}, +	{0x03e0, 0x0000}, +	{0x03e1, 0x0000}, +	{0x03e2, 0x0000}, +	{0x03e3, 0x0000}, +	{0x03e4, 0x0000}, +	{0x03e5, 0x0000}, +	{0x03e6, 0x0000}, +	{0x03e7, 0x0000}, +	{0x03e8, 0x0000}, +	{0x03e9, 0x0000}, +	{0x03ea, 0x0000}, +	{0x03eb, 0x0000}, +	{0x03ec, 0x0000}, +	{0x03ed, 0x0000}, +	{0x03ee, 0x0000}, +	{0x03ef, 0x0000}, +	{0x03f0, 0x0800}, +	{0x03f1, 0x0800}, +	{0x03f2, 0x0800}, +	{0x03f3, 0x0800}, +}; + +static bool rt5665_volatile_register(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case RT5665_RESET: +	case RT5665_EJD_CTRL_2: +	case RT5665_GPIO_STA: +	case RT5665_INT_ST_1: +	case RT5665_IL_CMD_1: +	case RT5665_4BTN_IL_CMD_1: +	case RT5665_PSV_IL_CMD_1: +	case RT5665_AJD1_CTRL: +	case RT5665_JD_CTRL_3: +	case RT5665_STO_NG2_CTRL_1: +	case RT5665_SAR_IL_CMD_4: +	case RT5665_DEVICE_ID: +	case RT5665_STO1_DAC_SIL_DET ... RT5665_STO2_DAC_SIL_DET: +	case RT5665_MONO_AMP_CALIB_STA1 ... RT5665_MONO_AMP_CALIB_STA6: +	case RT5665_HP_IMP_SENS_CTRL_12 ... RT5665_HP_IMP_SENS_CTRL_15: +	case RT5665_HP_CALIB_STA_1 ... RT5665_HP_CALIB_STA_11: +		return true; +	default: +		return false; +	} +} + +static bool rt5665_readable_register(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case RT5665_RESET: +	case RT5665_VENDOR_ID: +	case RT5665_VENDOR_ID_1: +	case RT5665_DEVICE_ID: +	case RT5665_LOUT: +	case RT5665_HP_CTRL_1: +	case RT5665_HP_CTRL_2: +	case RT5665_MONO_OUT: +	case RT5665_HPL_GAIN: +	case RT5665_HPR_GAIN: +	case RT5665_MONO_GAIN: +	case RT5665_CAL_BST_CTRL: +	case RT5665_CBJ_BST_CTRL: +	case RT5665_IN1_IN2: +	case RT5665_IN3_IN4: +	case RT5665_INL1_INR1_VOL: +	case RT5665_EJD_CTRL_1: +	case RT5665_EJD_CTRL_2: +	case RT5665_EJD_CTRL_3: +	case RT5665_EJD_CTRL_4: +	case RT5665_EJD_CTRL_5: +	case RT5665_EJD_CTRL_6: +	case RT5665_EJD_CTRL_7: +	case RT5665_DAC2_CTRL: +	case RT5665_DAC2_DIG_VOL: +	case RT5665_DAC1_DIG_VOL: +	case RT5665_DAC3_DIG_VOL: +	case RT5665_DAC3_CTRL: +	case RT5665_STO1_ADC_DIG_VOL: +	case RT5665_MONO_ADC_DIG_VOL: +	case RT5665_STO2_ADC_DIG_VOL: +	case RT5665_STO1_ADC_BOOST: +	case RT5665_MONO_ADC_BOOST: +	case RT5665_STO2_ADC_BOOST: +	case RT5665_HP_IMP_GAIN_1: +	case RT5665_HP_IMP_GAIN_2: +	case RT5665_STO1_ADC_MIXER: +	case RT5665_MONO_ADC_MIXER: +	case RT5665_STO2_ADC_MIXER: +	case RT5665_AD_DA_MIXER: +	case RT5665_STO1_DAC_MIXER: +	case RT5665_MONO_DAC_MIXER: +	case RT5665_STO2_DAC_MIXER: +	case RT5665_A_DAC1_MUX: +	case RT5665_A_DAC2_MUX: +	case RT5665_DIG_INF2_DATA: +	case RT5665_DIG_INF3_DATA: +	case RT5665_PDM_OUT_CTRL: +	case RT5665_PDM_DATA_CTRL_1: +	case RT5665_PDM_DATA_CTRL_2: +	case RT5665_PDM_DATA_CTRL_3: +	case RT5665_PDM_DATA_CTRL_4: +	case RT5665_REC1_GAIN: +	case RT5665_REC1_L1_MIXER: +	case RT5665_REC1_L2_MIXER: +	case RT5665_REC1_R1_MIXER: +	case RT5665_REC1_R2_MIXER: +	case RT5665_REC2_GAIN: +	case RT5665_REC2_L1_MIXER: +	case RT5665_REC2_L2_MIXER: +	case RT5665_REC2_R1_MIXER: +	case RT5665_REC2_R2_MIXER: +	case RT5665_CAL_REC: +	case RT5665_ALC_BACK_GAIN: +	case RT5665_MONOMIX_GAIN: +	case RT5665_MONOMIX_IN_GAIN: +	case RT5665_OUT_L_GAIN: +	case RT5665_OUT_L_MIXER: +	case RT5665_OUT_R_GAIN: +	case RT5665_OUT_R_MIXER: +	case RT5665_LOUT_MIXER: +	case RT5665_PWR_DIG_1: +	case RT5665_PWR_DIG_2: +	case RT5665_PWR_ANLG_1: +	case RT5665_PWR_ANLG_2: +	case RT5665_PWR_ANLG_3: +	case RT5665_PWR_MIXER: +	case RT5665_PWR_VOL: +	case RT5665_CLK_DET: +	case RT5665_HPF_CTRL1: +	case RT5665_DMIC_CTRL_1: +	case RT5665_DMIC_CTRL_2: +	case RT5665_I2S1_SDP: +	case RT5665_I2S2_SDP: +	case RT5665_I2S3_SDP: +	case RT5665_ADDA_CLK_1: +	case RT5665_ADDA_CLK_2: +	case RT5665_I2S1_F_DIV_CTRL_1: +	case RT5665_I2S1_F_DIV_CTRL_2: +	case RT5665_TDM_CTRL_1: +	case RT5665_TDM_CTRL_2: +	case RT5665_TDM_CTRL_3: +	case RT5665_TDM_CTRL_4: +	case RT5665_TDM_CTRL_5: +	case RT5665_TDM_CTRL_6: +	case RT5665_TDM_CTRL_7: +	case RT5665_TDM_CTRL_8: +	case RT5665_GLB_CLK: +	case RT5665_PLL_CTRL_1: +	case RT5665_PLL_CTRL_2: +	case RT5665_ASRC_1: +	case RT5665_ASRC_2: +	case RT5665_ASRC_3: +	case RT5665_ASRC_4: +	case RT5665_ASRC_5: +	case RT5665_ASRC_6: +	case RT5665_ASRC_7: +	case RT5665_ASRC_8: +	case RT5665_ASRC_9: +	case RT5665_ASRC_10: +	case RT5665_DEPOP_1: +	case RT5665_DEPOP_2: +	case RT5665_HP_CHARGE_PUMP_1: +	case RT5665_HP_CHARGE_PUMP_2: +	case RT5665_MICBIAS_1: +	case RT5665_MICBIAS_2: +	case RT5665_ASRC_12: +	case RT5665_ASRC_13: +	case RT5665_ASRC_14: +	case RT5665_RC_CLK_CTRL: +	case RT5665_I2S_M_CLK_CTRL_1: +	case RT5665_I2S2_F_DIV_CTRL_1: +	case RT5665_I2S2_F_DIV_CTRL_2: +	case RT5665_I2S3_F_DIV_CTRL_1: +	case RT5665_I2S3_F_DIV_CTRL_2: +	case RT5665_EQ_CTRL_1: +	case RT5665_EQ_CTRL_2: +	case RT5665_IRQ_CTRL_1: +	case RT5665_IRQ_CTRL_2: +	case RT5665_IRQ_CTRL_3: +	case RT5665_IRQ_CTRL_4: +	case RT5665_IRQ_CTRL_5: +	case RT5665_IRQ_CTRL_6: +	case RT5665_INT_ST_1: +	case RT5665_GPIO_CTRL_1: +	case RT5665_GPIO_CTRL_2: +	case RT5665_GPIO_CTRL_3: +	case RT5665_GPIO_CTRL_4: +	case RT5665_GPIO_STA: +	case RT5665_HP_AMP_DET_CTRL_1: +	case RT5665_HP_AMP_DET_CTRL_2: +	case RT5665_MID_HP_AMP_DET: +	case RT5665_LOW_HP_AMP_DET: +	case RT5665_SV_ZCD_1: +	case RT5665_SV_ZCD_2: +	case RT5665_IL_CMD_1: +	case RT5665_IL_CMD_2: +	case RT5665_IL_CMD_3: +	case RT5665_IL_CMD_4: +	case RT5665_4BTN_IL_CMD_1: +	case RT5665_4BTN_IL_CMD_2: +	case RT5665_4BTN_IL_CMD_3: +	case RT5665_PSV_IL_CMD_1: +	case RT5665_ADC_STO1_HP_CTRL_1: +	case RT5665_ADC_STO1_HP_CTRL_2: +	case RT5665_ADC_MONO_HP_CTRL_1: +	case RT5665_ADC_MONO_HP_CTRL_2: +	case RT5665_ADC_STO2_HP_CTRL_1: +	case RT5665_ADC_STO2_HP_CTRL_2: +	case RT5665_AJD1_CTRL: +	case RT5665_JD1_THD: +	case RT5665_JD2_THD: +	case RT5665_JD_CTRL_1: +	case RT5665_JD_CTRL_2: +	case RT5665_JD_CTRL_3: +	case RT5665_DIG_MISC: +	case RT5665_DUMMY_2: +	case RT5665_DUMMY_3: +	case RT5665_DAC_ADC_DIG_VOL1: +	case RT5665_DAC_ADC_DIG_VOL2: +	case RT5665_BIAS_CUR_CTRL_1: +	case RT5665_BIAS_CUR_CTRL_2: +	case RT5665_BIAS_CUR_CTRL_3: +	case RT5665_BIAS_CUR_CTRL_4: +	case RT5665_BIAS_CUR_CTRL_5: +	case RT5665_BIAS_CUR_CTRL_6: +	case RT5665_BIAS_CUR_CTRL_7: +	case RT5665_BIAS_CUR_CTRL_8: +	case RT5665_BIAS_CUR_CTRL_9: +	case RT5665_BIAS_CUR_CTRL_10: +	case RT5665_VREF_REC_OP_FB_CAP_CTRL: +	case RT5665_CHARGE_PUMP_1: +	case RT5665_DIG_IN_CTRL_1: +	case RT5665_DIG_IN_CTRL_2: +	case RT5665_PAD_DRIVING_CTRL: +	case RT5665_SOFT_RAMP_DEPOP: +	case RT5665_PLL: +	case RT5665_CHOP_DAC: +	case RT5665_CHOP_ADC: +	case RT5665_CALIB_ADC_CTRL: +	case RT5665_VOL_TEST: +	case RT5665_TEST_MODE_CTRL_1: +	case RT5665_TEST_MODE_CTRL_2: +	case RT5665_TEST_MODE_CTRL_3: +	case RT5665_TEST_MODE_CTRL_4: +	case RT5665_BASSBACK_CTRL: +	case RT5665_STO_NG2_CTRL_1: +	case RT5665_STO_NG2_CTRL_2: +	case RT5665_STO_NG2_CTRL_3: +	case RT5665_STO_NG2_CTRL_4: +	case RT5665_STO_NG2_CTRL_5: +	case RT5665_STO_NG2_CTRL_6: +	case RT5665_STO_NG2_CTRL_7: +	case RT5665_STO_NG2_CTRL_8: +	case RT5665_MONO_NG2_CTRL_1: +	case RT5665_MONO_NG2_CTRL_2: +	case RT5665_MONO_NG2_CTRL_3: +	case RT5665_MONO_NG2_CTRL_4: +	case RT5665_MONO_NG2_CTRL_5: +	case RT5665_MONO_NG2_CTRL_6: +	case RT5665_STO1_DAC_SIL_DET: +	case RT5665_MONOL_DAC_SIL_DET: +	case RT5665_MONOR_DAC_SIL_DET: +	case RT5665_STO2_DAC_SIL_DET: +	case RT5665_SIL_PSV_CTRL1: +	case RT5665_SIL_PSV_CTRL2: +	case RT5665_SIL_PSV_CTRL3: +	case RT5665_SIL_PSV_CTRL4: +	case RT5665_SIL_PSV_CTRL5: +	case RT5665_SIL_PSV_CTRL6: +	case RT5665_MONO_AMP_CALIB_CTRL_1: +	case RT5665_MONO_AMP_CALIB_CTRL_2: +	case RT5665_MONO_AMP_CALIB_CTRL_3: +	case RT5665_MONO_AMP_CALIB_CTRL_4: +	case RT5665_MONO_AMP_CALIB_CTRL_5: +	case RT5665_MONO_AMP_CALIB_CTRL_6: +	case RT5665_MONO_AMP_CALIB_CTRL_7: +	case RT5665_MONO_AMP_CALIB_STA1: +	case RT5665_MONO_AMP_CALIB_STA2: +	case RT5665_MONO_AMP_CALIB_STA3: +	case RT5665_MONO_AMP_CALIB_STA4: +	case RT5665_MONO_AMP_CALIB_STA6: +	case RT5665_HP_IMP_SENS_CTRL_01: +	case RT5665_HP_IMP_SENS_CTRL_02: +	case RT5665_HP_IMP_SENS_CTRL_03: +	case RT5665_HP_IMP_SENS_CTRL_04: +	case RT5665_HP_IMP_SENS_CTRL_05: +	case RT5665_HP_IMP_SENS_CTRL_06: +	case RT5665_HP_IMP_SENS_CTRL_07: +	case RT5665_HP_IMP_SENS_CTRL_08: +	case RT5665_HP_IMP_SENS_CTRL_09: +	case RT5665_HP_IMP_SENS_CTRL_10: +	case RT5665_HP_IMP_SENS_CTRL_11: +	case RT5665_HP_IMP_SENS_CTRL_12: +	case RT5665_HP_IMP_SENS_CTRL_13: +	case RT5665_HP_IMP_SENS_CTRL_14: +	case RT5665_HP_IMP_SENS_CTRL_15: +	case RT5665_HP_IMP_SENS_CTRL_16: +	case RT5665_HP_IMP_SENS_CTRL_17: +	case RT5665_HP_IMP_SENS_CTRL_18: +	case RT5665_HP_IMP_SENS_CTRL_19: +	case RT5665_HP_IMP_SENS_CTRL_20: +	case RT5665_HP_IMP_SENS_CTRL_21: +	case RT5665_HP_IMP_SENS_CTRL_22: +	case RT5665_HP_IMP_SENS_CTRL_23: +	case RT5665_HP_IMP_SENS_CTRL_24: +	case RT5665_HP_IMP_SENS_CTRL_25: +	case RT5665_HP_IMP_SENS_CTRL_26: +	case RT5665_HP_IMP_SENS_CTRL_27: +	case RT5665_HP_IMP_SENS_CTRL_28: +	case RT5665_HP_IMP_SENS_CTRL_29: +	case RT5665_HP_IMP_SENS_CTRL_30: +	case RT5665_HP_IMP_SENS_CTRL_31: +	case RT5665_HP_IMP_SENS_CTRL_32: +	case RT5665_HP_IMP_SENS_CTRL_33: +	case RT5665_HP_IMP_SENS_CTRL_34: +	case RT5665_HP_LOGIC_CTRL_1: +	case RT5665_HP_LOGIC_CTRL_2: +	case RT5665_HP_LOGIC_CTRL_3: +	case RT5665_HP_CALIB_CTRL_1: +	case RT5665_HP_CALIB_CTRL_2: +	case RT5665_HP_CALIB_CTRL_3: +	case RT5665_HP_CALIB_CTRL_4: +	case RT5665_HP_CALIB_CTRL_5: +	case RT5665_HP_CALIB_CTRL_6: +	case RT5665_HP_CALIB_CTRL_7: +	case RT5665_HP_CALIB_CTRL_9: +	case RT5665_HP_CALIB_CTRL_10: +	case RT5665_HP_CALIB_CTRL_11: +	case RT5665_HP_CALIB_STA_1: +	case RT5665_HP_CALIB_STA_2: +	case RT5665_HP_CALIB_STA_3: +	case RT5665_HP_CALIB_STA_4: +	case RT5665_HP_CALIB_STA_5: +	case RT5665_HP_CALIB_STA_6: +	case RT5665_HP_CALIB_STA_7: +	case RT5665_HP_CALIB_STA_8: +	case RT5665_HP_CALIB_STA_9: +	case RT5665_HP_CALIB_STA_10: +	case RT5665_HP_CALIB_STA_11: +	case RT5665_PGM_TAB_CTRL1: +	case RT5665_PGM_TAB_CTRL2: +	case RT5665_PGM_TAB_CTRL3: +	case RT5665_PGM_TAB_CTRL4: +	case RT5665_PGM_TAB_CTRL5: +	case RT5665_PGM_TAB_CTRL6: +	case RT5665_PGM_TAB_CTRL7: +	case RT5665_PGM_TAB_CTRL8: +	case RT5665_PGM_TAB_CTRL9: +	case RT5665_SAR_IL_CMD_1: +	case RT5665_SAR_IL_CMD_2: +	case RT5665_SAR_IL_CMD_3: +	case RT5665_SAR_IL_CMD_4: +	case RT5665_SAR_IL_CMD_5: +	case RT5665_SAR_IL_CMD_6: +	case RT5665_SAR_IL_CMD_7: +	case RT5665_SAR_IL_CMD_8: +	case RT5665_SAR_IL_CMD_9: +	case RT5665_SAR_IL_CMD_10: +	case RT5665_SAR_IL_CMD_11: +	case RT5665_SAR_IL_CMD_12: +	case RT5665_DRC1_CTRL_0: +	case RT5665_DRC1_CTRL_1: +	case RT5665_DRC1_CTRL_2: +	case RT5665_DRC1_CTRL_3: +	case RT5665_DRC1_CTRL_4: +	case RT5665_DRC1_CTRL_5: +	case RT5665_DRC1_CTRL_6: +	case RT5665_DRC1_HARD_LMT_CTRL_1: +	case RT5665_DRC1_HARD_LMT_CTRL_2: +	case RT5665_DRC1_PRIV_1: +	case RT5665_DRC1_PRIV_2: +	case RT5665_DRC1_PRIV_3: +	case RT5665_DRC1_PRIV_4: +	case RT5665_DRC1_PRIV_5: +	case RT5665_DRC1_PRIV_6: +	case RT5665_DRC1_PRIV_7: +	case RT5665_DRC1_PRIV_8: +	case RT5665_ALC_PGA_CTRL_1: +	case RT5665_ALC_PGA_CTRL_2: +	case RT5665_ALC_PGA_CTRL_3: +	case RT5665_ALC_PGA_CTRL_4: +	case RT5665_ALC_PGA_CTRL_5: +	case RT5665_ALC_PGA_CTRL_6: +	case RT5665_ALC_PGA_CTRL_7: +	case RT5665_ALC_PGA_CTRL_8: +	case RT5665_ALC_PGA_STA_1: +	case RT5665_ALC_PGA_STA_2: +	case RT5665_ALC_PGA_STA_3: +	case RT5665_EQ_AUTO_RCV_CTRL1: +	case RT5665_EQ_AUTO_RCV_CTRL2: +	case RT5665_EQ_AUTO_RCV_CTRL3: +	case RT5665_EQ_AUTO_RCV_CTRL4: +	case RT5665_EQ_AUTO_RCV_CTRL5: +	case RT5665_EQ_AUTO_RCV_CTRL6: +	case RT5665_EQ_AUTO_RCV_CTRL7: +	case RT5665_EQ_AUTO_RCV_CTRL8: +	case RT5665_EQ_AUTO_RCV_CTRL9: +	case RT5665_EQ_AUTO_RCV_CTRL10: +	case RT5665_EQ_AUTO_RCV_CTRL11: +	case RT5665_EQ_AUTO_RCV_CTRL12: +	case RT5665_EQ_AUTO_RCV_CTRL13: +	case RT5665_ADC_L_EQ_LPF1_A1: +	case RT5665_R_EQ_LPF1_A1: +	case RT5665_L_EQ_LPF1_H0: +	case RT5665_R_EQ_LPF1_H0: +	case RT5665_L_EQ_BPF1_A1: +	case RT5665_R_EQ_BPF1_A1: +	case RT5665_L_EQ_BPF1_A2: +	case RT5665_R_EQ_BPF1_A2: +	case RT5665_L_EQ_BPF1_H0: +	case RT5665_R_EQ_BPF1_H0: +	case RT5665_L_EQ_BPF2_A1: +	case RT5665_R_EQ_BPF2_A1: +	case RT5665_L_EQ_BPF2_A2: +	case RT5665_R_EQ_BPF2_A2: +	case RT5665_L_EQ_BPF2_H0: +	case RT5665_R_EQ_BPF2_H0: +	case RT5665_L_EQ_BPF3_A1: +	case RT5665_R_EQ_BPF3_A1: +	case RT5665_L_EQ_BPF3_A2: +	case RT5665_R_EQ_BPF3_A2: +	case RT5665_L_EQ_BPF3_H0: +	case RT5665_R_EQ_BPF3_H0: +	case RT5665_L_EQ_BPF4_A1: +	case RT5665_R_EQ_BPF4_A1: +	case RT5665_L_EQ_BPF4_A2: +	case RT5665_R_EQ_BPF4_A2: +	case RT5665_L_EQ_BPF4_H0: +	case RT5665_R_EQ_BPF4_H0: +	case RT5665_L_EQ_HPF1_A1: +	case RT5665_R_EQ_HPF1_A1: +	case RT5665_L_EQ_HPF1_H0: +	case RT5665_R_EQ_HPF1_H0: +	case RT5665_L_EQ_PRE_VOL: +	case RT5665_R_EQ_PRE_VOL: +	case RT5665_L_EQ_POST_VOL: +	case RT5665_R_EQ_POST_VOL: +	case RT5665_SCAN_MODE_CTRL: +	case RT5665_I2C_MODE: +		return true; +	default: +		return false; +	} +} + +static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2250, 150, 0); +static const DECLARE_TLV_DB_SCALE(mono_vol_tlv, -1400, 150, 0); +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); +static const DECLARE_TLV_DB_SCALE(in_bst_tlv, -1200, 75, 0); + +/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ +static const DECLARE_TLV_DB_RANGE(bst_tlv, +	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), +	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), +	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), +	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), +	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), +	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), +	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0) +); + +/* Interface data select */ +static const char * const rt5665_data_select[] = { +	"L/R", "R/L", "L/L", "R/R" +}; + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_01_adc_enum, +	RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT01_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_23_adc_enum, +	RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT23_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_45_adc_enum, +	RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT45_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_67_adc_enum, +	RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT67_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_01_adc_enum, +	RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT01_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_23_adc_enum, +	RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT23_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_45_adc_enum, +	RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT45_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_67_adc_enum, +	RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT67_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if2_1_dac_enum, +	RT5665_DIG_INF2_DATA, RT5665_IF2_1_DAC_SEL_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if2_1_adc_enum, +	RT5665_DIG_INF2_DATA, RT5665_IF2_1_ADC_SEL_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if2_2_dac_enum, +	RT5665_DIG_INF2_DATA, RT5665_IF2_2_DAC_SEL_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if2_2_adc_enum, +	RT5665_DIG_INF2_DATA, RT5665_IF2_2_ADC_SEL_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if3_dac_enum, +	RT5665_DIG_INF3_DATA, RT5665_IF3_DAC_SEL_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if3_adc_enum, +	RT5665_DIG_INF3_DATA, RT5665_IF3_ADC_SEL_SFT, rt5665_data_select); + +static const struct snd_kcontrol_new rt5665_if1_1_01_adc_swap_mux = +	SOC_DAPM_ENUM("IF1_1 01 ADC Swap Mux", rt5665_if1_1_01_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_1_23_adc_swap_mux = +	SOC_DAPM_ENUM("IF1_1 23 ADC Swap Mux", rt5665_if1_1_23_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_1_45_adc_swap_mux = +	SOC_DAPM_ENUM("IF1_1 45 ADC Swap Mux", rt5665_if1_1_45_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_1_67_adc_swap_mux = +	SOC_DAPM_ENUM("IF1_1 67 ADC Swap Mux", rt5665_if1_1_67_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_2_01_adc_swap_mux = +	SOC_DAPM_ENUM("IF1_2 01 ADC Swap Mux", rt5665_if1_2_01_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_2_23_adc_swap_mux = +	SOC_DAPM_ENUM("IF1_2 23 ADC1 Swap Mux", rt5665_if1_2_23_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_2_45_adc_swap_mux = +	SOC_DAPM_ENUM("IF1_2 45 ADC1 Swap Mux", rt5665_if1_2_45_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_2_67_adc_swap_mux = +	SOC_DAPM_ENUM("IF1_2 67 ADC1 Swap Mux", rt5665_if1_2_67_adc_enum); + +static const struct snd_kcontrol_new rt5665_if2_1_dac_swap_mux = +	SOC_DAPM_ENUM("IF2_1 DAC Swap Source", rt5665_if2_1_dac_enum); + +static const struct snd_kcontrol_new rt5665_if2_1_adc_swap_mux = +	SOC_DAPM_ENUM("IF2_1 ADC Swap Source", rt5665_if2_1_adc_enum); + +static const struct snd_kcontrol_new rt5665_if2_2_dac_swap_mux = +	SOC_DAPM_ENUM("IF2_2 DAC Swap Source", rt5665_if2_2_dac_enum); + +static const struct snd_kcontrol_new rt5665_if2_2_adc_swap_mux = +	SOC_DAPM_ENUM("IF2_2 ADC Swap Source", rt5665_if2_2_adc_enum); + +static const struct snd_kcontrol_new rt5665_if3_dac_swap_mux = +	SOC_DAPM_ENUM("IF3 DAC Swap Source", rt5665_if3_dac_enum); + +static const struct snd_kcontrol_new rt5665_if3_adc_swap_mux = +	SOC_DAPM_ENUM("IF3 ADC Swap Source", rt5665_if3_adc_enum); + +static int rt5665_hp_vol_put(struct snd_kcontrol *kcontrol, +		struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); +	int ret = snd_soc_put_volsw(kcontrol, ucontrol); + +	if (snd_soc_read(codec, RT5665_STO_NG2_CTRL_1) & RT5665_NG2_EN) { +		snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1, +			RT5665_NG2_EN_MASK, RT5665_NG2_DIS); +		snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1, +			RT5665_NG2_EN_MASK, RT5665_NG2_EN); +	} + +	return ret; +} + +static int rt5665_mono_vol_put(struct snd_kcontrol *kcontrol, +		struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); +	int ret = snd_soc_put_volsw(kcontrol, ucontrol); + +	if (snd_soc_read(codec, RT5665_MONO_NG2_CTRL_1) & RT5665_NG2_EN) { +		snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1, +			RT5665_NG2_EN_MASK, RT5665_NG2_DIS); +		snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1, +			RT5665_NG2_EN_MASK, RT5665_NG2_EN); +	} + +	return ret; +} + +/** + * rt5665_sel_asrc_clk_src - select ASRC clock source for a set of filters + * @codec: SoC audio codec device. + * @filter_mask: mask of filters. + * @clk_src: clock source + * + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5665 can + * only support standard 32fs or 64fs i2s format, ASRC should be enabled to + * support special i2s clock format such as Intel's 100fs(100 * sampling rate). + * ASRC function will track i2s clock and generate a corresponding system clock + * for codec. This function provides an API to select the clock source for a + * set of filters specified by the mask. And the codec driver will turn on ASRC + * for these filters if ASRC is selected as their clock source. + */ +int rt5665_sel_asrc_clk_src(struct snd_soc_codec *codec, +		unsigned int filter_mask, unsigned int clk_src) +{ +	unsigned int asrc2_mask = 0; +	unsigned int asrc2_value = 0; +	unsigned int asrc3_mask = 0; +	unsigned int asrc3_value = 0; + +	switch (clk_src) { +	case RT5665_CLK_SEL_SYS: +	case RT5665_CLK_SEL_I2S1_ASRC: +	case RT5665_CLK_SEL_I2S2_ASRC: +	case RT5665_CLK_SEL_I2S3_ASRC: +	case RT5665_CLK_SEL_SYS2: +	case RT5665_CLK_SEL_SYS3: +	case RT5665_CLK_SEL_SYS4: +		break; + +	default: +		return -EINVAL; +	} + +	if (filter_mask & RT5665_DA_STEREO1_FILTER) { +		asrc2_mask |= RT5665_DA_STO1_CLK_SEL_MASK; +		asrc2_value = (asrc2_value & ~RT5665_DA_STO1_CLK_SEL_MASK) +			| (clk_src << RT5665_DA_STO1_CLK_SEL_SFT); +	} + +	if (filter_mask & RT5665_DA_STEREO2_FILTER) { +		asrc2_mask |= RT5665_DA_STO2_CLK_SEL_MASK; +		asrc2_value = (asrc2_value & ~RT5665_DA_STO2_CLK_SEL_MASK) +			| (clk_src << RT5665_DA_STO2_CLK_SEL_SFT); +	} + +	if (filter_mask & RT5665_DA_MONO_L_FILTER) { +		asrc2_mask |= RT5665_DA_MONOL_CLK_SEL_MASK; +		asrc2_value = (asrc2_value & ~RT5665_DA_MONOL_CLK_SEL_MASK) +			| (clk_src << RT5665_DA_MONOL_CLK_SEL_SFT); +	} + +	if (filter_mask & RT5665_DA_MONO_R_FILTER) { +		asrc2_mask |= RT5665_DA_MONOR_CLK_SEL_MASK; +		asrc2_value = (asrc2_value & ~RT5665_DA_MONOR_CLK_SEL_MASK) +			| (clk_src << RT5665_DA_MONOR_CLK_SEL_SFT); +	} + +	if (filter_mask & RT5665_AD_STEREO1_FILTER) { +		asrc3_mask |= RT5665_AD_STO1_CLK_SEL_MASK; +		asrc3_value = (asrc2_value & ~RT5665_AD_STO1_CLK_SEL_MASK) +			| (clk_src << RT5665_AD_STO1_CLK_SEL_SFT); +	} + +	if (filter_mask & RT5665_AD_STEREO2_FILTER) { +		asrc3_mask |= RT5665_AD_STO2_CLK_SEL_MASK; +		asrc3_value = (asrc2_value & ~RT5665_AD_STO2_CLK_SEL_MASK) +			| (clk_src << RT5665_AD_STO2_CLK_SEL_SFT); +	} + +	if (filter_mask & RT5665_AD_MONO_L_FILTER) { +		asrc3_mask |= RT5665_AD_MONOL_CLK_SEL_MASK; +		asrc3_value = (asrc3_value & ~RT5665_AD_MONOL_CLK_SEL_MASK) +			| (clk_src << RT5665_AD_MONOL_CLK_SEL_SFT); +	} + +	if (filter_mask & RT5665_AD_MONO_R_FILTER)  { +		asrc3_mask |= RT5665_AD_MONOR_CLK_SEL_MASK; +		asrc3_value = (asrc3_value & ~RT5665_AD_MONOR_CLK_SEL_MASK) +			| (clk_src << RT5665_AD_MONOR_CLK_SEL_SFT); +	} + +	if (asrc2_mask) +		snd_soc_update_bits(codec, RT5665_ASRC_2, +			asrc2_mask, asrc2_value); + +	if (asrc3_mask) +		snd_soc_update_bits(codec, RT5665_ASRC_3, +			asrc3_mask, asrc3_value); + +	return 0; +} +EXPORT_SYMBOL_GPL(rt5665_sel_asrc_clk_src); + +static int rt5665_button_detect(struct snd_soc_codec *codec) +{ +	int btn_type, val; + +	val = snd_soc_read(codec, RT5665_4BTN_IL_CMD_1); +	btn_type = val & 0xfff0; +	snd_soc_write(codec, RT5665_4BTN_IL_CMD_1, val); + +	return btn_type; +} + +static void rt5665_enable_push_button_irq(struct snd_soc_codec *codec, +	bool enable) +{ +	if (enable) { +		snd_soc_write(codec, RT5665_4BTN_IL_CMD_1, 0x000b); +		snd_soc_write(codec, RT5665_IL_CMD_1, 0x0048); +		snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2, +				RT5665_4BTN_IL_MASK | RT5665_4BTN_IL_RST_MASK, +				RT5665_4BTN_IL_EN | RT5665_4BTN_IL_NOR); +		snd_soc_update_bits(codec, RT5665_IRQ_CTRL_3, +				RT5665_IL_IRQ_MASK, RT5665_IL_IRQ_EN); +	} else { +		snd_soc_update_bits(codec, RT5665_IRQ_CTRL_3, +				RT5665_IL_IRQ_MASK, RT5665_IL_IRQ_DIS); +		snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2, +				RT5665_4BTN_IL_MASK, RT5665_4BTN_IL_DIS); +		snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2, +				RT5665_4BTN_IL_RST_MASK, RT5665_4BTN_IL_RST); +	} +} + +/** + * rt5665_headset_detect - Detect headset. + * @codec: SoC audio codec device. + * @jack_insert: Jack insert or not. + * + * Detect whether is headset or not when jack inserted. + * + * Returns detect status. + */ +static int rt5665_headset_detect(struct snd_soc_codec *codec, int jack_insert) +{ +	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); +	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); +	unsigned int sar_hs_type, val; + +	if (jack_insert) { +		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); +		snd_soc_dapm_sync(dapm); + +		regmap_update_bits(rt5665->regmap, RT5665_MICBIAS_2, 0x100, +			0x100); + +		regmap_read(rt5665->regmap, RT5665_GPIO_STA, &val); +		if (val & 0x4) { +			regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1, +				0x100, 0); + +			regmap_read(rt5665->regmap, RT5665_GPIO_STA, &val); +			while (val & 0x4) { +				usleep_range(10000, 15000); +				regmap_read(rt5665->regmap, RT5665_GPIO_STA, +					&val); +			} +		} + +		regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1, +			0x180, 0x180); +		regmap_write(rt5665->regmap, RT5665_EJD_CTRL_3, 0x3424); +		regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1, 0xa291); + +		rt5665->sar_adc_value = snd_soc_read(rt5665->codec, +			RT5665_SAR_IL_CMD_4) & 0x7ff; + +		sar_hs_type = rt5665->pdata.sar_hs_type ? +			rt5665->pdata.sar_hs_type : 729; + +		if (rt5665->sar_adc_value > sar_hs_type) { +			rt5665->jack_type = SND_JACK_HEADSET; +			rt5665_enable_push_button_irq(codec, true); +			} else { +			rt5665->jack_type = SND_JACK_HEADPHONE; +			regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1, +				0x2291); +			regmap_update_bits(rt5665->regmap, RT5665_MICBIAS_2, +				0x100, 0); +			snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); +			snd_soc_dapm_sync(dapm); +		} +	} else { +		regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1, 0x2291); +		regmap_update_bits(rt5665->regmap, RT5665_MICBIAS_2, 0x100, 0); +		snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); +		snd_soc_dapm_sync(dapm); +		if (rt5665->jack_type == SND_JACK_HEADSET) +			rt5665_enable_push_button_irq(codec, false); +		rt5665->jack_type = 0; +	} + +	dev_dbg(codec->dev, "jack_type = %d\n", rt5665->jack_type); +	return rt5665->jack_type; +} + +static irqreturn_t rt5665_irq(int irq, void *data) +{ +	struct rt5665_priv *rt5665 = data; + +	mod_delayed_work(system_power_efficient_wq, +			   &rt5665->jack_detect_work, msecs_to_jiffies(250)); + +	return IRQ_HANDLED; +} + +static void rt5665_jd_check_handler(struct work_struct *work) +{ +	struct rt5665_priv *rt5665 = container_of(work, struct rt5665_priv, +		calibrate_work.work); + +	if (snd_soc_read(rt5665->codec, RT5665_AJD1_CTRL) & 0x0010) { +		/* jack out */ +		rt5665->jack_type = rt5665_headset_detect(rt5665->codec, 0); + +		snd_soc_jack_report(rt5665->hs_jack, rt5665->jack_type, +				SND_JACK_HEADSET | +				SND_JACK_BTN_0 | SND_JACK_BTN_1 | +				SND_JACK_BTN_2 | SND_JACK_BTN_3); +	} else { +		schedule_delayed_work(&rt5665->jd_check_work, 500); +	} +} + +int rt5665_set_jack_detect(struct snd_soc_codec *codec, +	struct snd_soc_jack *hs_jack) +{ +	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + +	switch (rt5665->pdata.jd_src) { +	case RT5665_JD1: +		regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1, +			RT5665_GP1_PIN_MASK, RT5665_GP1_PIN_IRQ); +		regmap_update_bits(rt5665->regmap, RT5665_RC_CLK_CTRL, +				0xc000, 0xc000); +		regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_2, +			RT5665_PWR_JD1, RT5665_PWR_JD1); +		regmap_update_bits(rt5665->regmap, RT5665_IRQ_CTRL_1, 0x8, 0x8); +		break; + +	case RT5665_JD_NULL: +		break; + +	default: +		dev_warn(codec->dev, "Wrong JD source\n"); +		break; +	} + +	rt5665->hs_jack = hs_jack; + +	return 0; +} +EXPORT_SYMBOL_GPL(rt5665_set_jack_detect); + +static void rt5665_jack_detect_handler(struct work_struct *work) +{ +	struct rt5665_priv *rt5665 = +		container_of(work, struct rt5665_priv, jack_detect_work.work); +	int val, btn_type; + +	while (!rt5665->codec) { +		pr_debug("%s codec = null\n", __func__); +		usleep_range(10000, 15000); +	} + +	while (!rt5665->codec->component.card->instantiated) { +		pr_debug("%s\n", __func__); +		usleep_range(10000, 15000); +	} + +	mutex_lock(&rt5665->calibrate_mutex); + +	val = snd_soc_read(rt5665->codec, RT5665_AJD1_CTRL) & 0x0010; +	if (!val) { +		/* jack in */ +		if (rt5665->jack_type == 0) { +			/* jack was out, report jack type */ +			rt5665->jack_type = +				rt5665_headset_detect(rt5665->codec, 1); +		} else { +			/* jack is already in, report button event */ +			rt5665->jack_type = SND_JACK_HEADSET; +			btn_type = rt5665_button_detect(rt5665->codec); +			/** +			 * rt5665 can report three kinds of button behavior, +			 * one click, double click and hold. However, +			 * currently we will report button pressed/released +			 * event. So all the three button behaviors are +			 * treated as button pressed. +			 */ +			switch (btn_type) { +			case 0x8000: +			case 0x4000: +			case 0x2000: +				rt5665->jack_type |= SND_JACK_BTN_0; +				break; +			case 0x1000: +			case 0x0800: +			case 0x0400: +				rt5665->jack_type |= SND_JACK_BTN_1; +				break; +			case 0x0200: +			case 0x0100: +			case 0x0080: +				rt5665->jack_type |= SND_JACK_BTN_2; +				break; +			case 0x0040: +			case 0x0020: +			case 0x0010: +				rt5665->jack_type |= SND_JACK_BTN_3; +				break; +			case 0x0000: /* unpressed */ +				break; +			default: +				btn_type = 0; +				dev_err(rt5665->codec->dev, +					"Unexpected button code 0x%04x\n", +					btn_type); +				break; +			} +		} +	} else { +		/* jack out */ +		rt5665->jack_type = rt5665_headset_detect(rt5665->codec, 0); +	} + +	snd_soc_jack_report(rt5665->hs_jack, rt5665->jack_type, +			SND_JACK_HEADSET | +			    SND_JACK_BTN_0 | SND_JACK_BTN_1 | +			    SND_JACK_BTN_2 | SND_JACK_BTN_3); + +	if (rt5665->jack_type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 | +		SND_JACK_BTN_2 | SND_JACK_BTN_3)) +		schedule_delayed_work(&rt5665->jd_check_work, 0); +	else +		cancel_delayed_work_sync(&rt5665->jd_check_work); + +	mutex_unlock(&rt5665->calibrate_mutex); +} + +static const struct snd_kcontrol_new rt5665_snd_controls[] = { +	/* Headphone Output Volume */ +	SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", RT5665_HPL_GAIN, +		RT5665_HPR_GAIN, RT5665_G_HP_SFT, 15, 1, snd_soc_get_volsw, +		rt5665_hp_vol_put, hp_vol_tlv), + +	/* Mono Output Volume */ +	SOC_SINGLE_EXT_TLV("Mono Playback Volume", RT5665_MONO_GAIN, +		RT5665_L_VOL_SFT, 15, 1, snd_soc_get_volsw, +		rt5665_mono_vol_put, mono_vol_tlv), + +	/* Output Volume */ +	SOC_DOUBLE_TLV("OUT Playback Volume", RT5665_LOUT, RT5665_L_VOL_SFT, +		RT5665_R_VOL_SFT, 39, 1, out_vol_tlv), + +	/* DAC Digital Volume */ +	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5665_DAC1_DIG_VOL, +		RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 175, 0, dac_vol_tlv), +	SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5665_DAC2_DIG_VOL, +		RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 175, 0, dac_vol_tlv), +	SOC_DOUBLE("DAC2 Playback Switch", RT5665_DAC2_CTRL, +		RT5665_M_DAC2_L_VOL_SFT, RT5665_M_DAC2_R_VOL_SFT, 1, 1), + +	/* IN1/IN2/IN3/IN4 Volume */ +	SOC_SINGLE_TLV("IN1 Boost Volume", RT5665_IN1_IN2, +		RT5665_BST1_SFT, 69, 0, in_bst_tlv), +	SOC_SINGLE_TLV("IN2 Boost Volume", RT5665_IN1_IN2, +		RT5665_BST2_SFT, 69, 0, in_bst_tlv), +	SOC_SINGLE_TLV("IN3 Boost Volume", RT5665_IN3_IN4, +		RT5665_BST3_SFT, 69, 0, in_bst_tlv), +	SOC_SINGLE_TLV("IN4 Boost Volume", RT5665_IN3_IN4, +		RT5665_BST4_SFT, 69, 0, in_bst_tlv), +	SOC_SINGLE_TLV("CBJ Boost Volume", RT5665_CBJ_BST_CTRL, +		RT5665_BST_CBJ_SFT, 8, 0, bst_tlv), + +	/* INL/INR Volume Control */ +	SOC_DOUBLE_TLV("IN Capture Volume", RT5665_INL1_INR1_VOL, +		RT5665_INL_VOL_SFT, RT5665_INR_VOL_SFT, 31, 1, in_vol_tlv), + +	/* ADC Digital Volume Control */ +	SOC_DOUBLE("STO1 ADC Capture Switch", RT5665_STO1_ADC_DIG_VOL, +		RT5665_L_MUTE_SFT, RT5665_R_MUTE_SFT, 1, 1), +	SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5665_STO1_ADC_DIG_VOL, +		RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 127, 0, adc_vol_tlv), +	SOC_DOUBLE("Mono ADC Capture Switch", RT5665_MONO_ADC_DIG_VOL, +		RT5665_L_MUTE_SFT, RT5665_R_MUTE_SFT, 1, 1), +	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5665_MONO_ADC_DIG_VOL, +		RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 127, 0, adc_vol_tlv), +	SOC_DOUBLE("STO2 ADC Capture Switch", RT5665_STO2_ADC_DIG_VOL, +		RT5665_L_MUTE_SFT, RT5665_R_MUTE_SFT, 1, 1), +	SOC_DOUBLE_TLV("STO2 ADC Capture Volume", RT5665_STO2_ADC_DIG_VOL, +		RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 127, 0, adc_vol_tlv), + +	/* ADC Boost Volume Control */ +	SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5665_STO1_ADC_BOOST, +		RT5665_STO1_ADC_L_BST_SFT, RT5665_STO1_ADC_R_BST_SFT, +		3, 0, adc_bst_tlv), + +	SOC_DOUBLE_TLV("Mono ADC Boost Gain Volume", RT5665_MONO_ADC_BOOST, +		RT5665_MONO_ADC_L_BST_SFT, RT5665_MONO_ADC_R_BST_SFT, +		3, 0, adc_bst_tlv), + +	SOC_DOUBLE_TLV("STO2 ADC Boost Gain Volume", RT5665_STO2_ADC_BOOST, +		RT5665_STO2_ADC_L_BST_SFT, RT5665_STO2_ADC_R_BST_SFT, +		3, 0, adc_bst_tlv), +}; + +/** + * set_dmic_clk - Set parameter of dmic. + * + * @w: DAPM widget. + * @kcontrol: The kcontrol of this widget. + * @event: Event id. + * + * Choose dmic clock between 1MHz and 3MHz. + * It is better for clock to approximate 3MHz. + */ +static int set_dmic_clk(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); +	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); +	int pd, idx = -EINVAL; + +	pd = rl6231_get_pre_div(rt5665->regmap, +		RT5665_ADDA_CLK_1, RT5665_I2S_PD1_SFT); +	idx = rl6231_calc_dmic_clk(rt5665->sysclk / pd); + +	if (idx < 0) +		dev_err(codec->dev, "Failed to set DMIC clock\n"); +	else { +		snd_soc_update_bits(codec, RT5665_DMIC_CTRL_1, +			RT5665_DMIC_CLK_MASK, idx << RT5665_DMIC_CLK_SFT); +	} +	return idx; +} + +static int rt5665_charge_pump_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + +	switch (event) { +	case SND_SOC_DAPM_PRE_PMU: +		snd_soc_update_bits(codec, RT5665_HP_CHARGE_PUMP_1, +			RT5665_PM_HP_MASK | RT5665_OSW_L_MASK, +			RT5665_PM_HP_HV | RT5665_OSW_L_EN); +		break; +	case SND_SOC_DAPM_POST_PMD: +		snd_soc_update_bits(codec, RT5665_HP_CHARGE_PUMP_1, +			RT5665_PM_HP_MASK | RT5665_OSW_L_MASK, +			RT5665_PM_HP_LV | RT5665_OSW_L_DIS); +		break; +	default: +		return 0; +	} + +	return 0; +} + +static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *w, +			 struct snd_soc_dapm_widget *sink) +{ +	unsigned int val; +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + +	val = snd_soc_read(codec, RT5665_GLB_CLK); +	val &= RT5665_SCLK_SRC_MASK; +	if (val == RT5665_SCLK_SRC_PLL1) +		return 1; +	else +		return 0; +} + +static int is_using_asrc(struct snd_soc_dapm_widget *w, +			 struct snd_soc_dapm_widget *sink) +{ +	unsigned int reg, shift, val; +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + +	switch (w->shift) { +	case RT5665_ADC_MONO_R_ASRC_SFT: +		reg = RT5665_ASRC_3; +		shift = RT5665_AD_MONOR_CLK_SEL_SFT; +		break; +	case RT5665_ADC_MONO_L_ASRC_SFT: +		reg = RT5665_ASRC_3; +		shift = RT5665_AD_MONOL_CLK_SEL_SFT; +		break; +	case RT5665_ADC_STO1_ASRC_SFT: +		reg = RT5665_ASRC_3; +		shift = RT5665_AD_STO1_CLK_SEL_SFT; +		break; +	case RT5665_ADC_STO2_ASRC_SFT: +		reg = RT5665_ASRC_3; +		shift = RT5665_AD_STO2_CLK_SEL_SFT; +		break; +	case RT5665_DAC_MONO_R_ASRC_SFT: +		reg = RT5665_ASRC_2; +		shift = RT5665_DA_MONOR_CLK_SEL_SFT; +		break; +	case RT5665_DAC_MONO_L_ASRC_SFT: +		reg = RT5665_ASRC_2; +		shift = RT5665_DA_MONOL_CLK_SEL_SFT; +		break; +	case RT5665_DAC_STO1_ASRC_SFT: +		reg = RT5665_ASRC_2; +		shift = RT5665_DA_STO1_CLK_SEL_SFT; +		break; +	case RT5665_DAC_STO2_ASRC_SFT: +		reg = RT5665_ASRC_2; +		shift = RT5665_DA_STO2_CLK_SEL_SFT; +		break; +	default: +		return 0; +	} + +	val = (snd_soc_read(codec, reg) >> shift) & 0xf; +	switch (val) { +	case RT5665_CLK_SEL_I2S1_ASRC: +	case RT5665_CLK_SEL_I2S2_ASRC: +	case RT5665_CLK_SEL_I2S3_ASRC: +		/* I2S_Pre_Div1 should be 1 in asrc mode */ +		snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, +			RT5665_I2S_PD1_MASK, RT5665_I2S_PD1_2); +		return 1; +	default: +		return 0; +	} + +} + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5665_sto1_adc_l_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO1_ADC_MIXER, +			RT5665_M_STO1_ADC_L1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO1_ADC_MIXER, +			RT5665_M_STO1_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto1_adc_r_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO1_ADC_MIXER, +			RT5665_M_STO1_ADC_R1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO1_ADC_MIXER, +			RT5665_M_STO1_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto2_adc_l_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO2_ADC_MIXER, +			RT5665_M_STO2_ADC_L1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO2_ADC_MIXER, +			RT5665_M_STO2_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto2_adc_r_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO2_ADC_MIXER, +			RT5665_M_STO2_ADC_R1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO2_ADC_MIXER, +			RT5665_M_STO2_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_mono_adc_l_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5665_MONO_ADC_MIXER, +			RT5665_M_MONO_ADC_L1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5665_MONO_ADC_MIXER, +			RT5665_M_MONO_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_mono_adc_r_mix[] = { +	SOC_DAPM_SINGLE("ADC1 Switch", RT5665_MONO_ADC_MIXER, +			RT5665_M_MONO_ADC_R1_SFT, 1, 1), +	SOC_DAPM_SINGLE("ADC2 Switch", RT5665_MONO_ADC_MIXER, +			RT5665_M_MONO_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_dac_l_mix[] = { +	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5665_AD_DA_MIXER, +			RT5665_M_ADCMIX_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC1 Switch", RT5665_AD_DA_MIXER, +			RT5665_M_DAC1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_dac_r_mix[] = { +	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5665_AD_DA_MIXER, +			RT5665_M_ADCMIX_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC1 Switch", RT5665_AD_DA_MIXER, +			RT5665_M_DAC1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto1_dac_l_mix[] = { +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_STO1_DAC_MIXER, +			RT5665_M_DAC_L1_STO_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_STO1_DAC_MIXER, +			RT5665_M_DAC_R1_STO_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_STO1_DAC_MIXER, +			RT5665_M_DAC_L2_STO_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_STO1_DAC_MIXER, +			RT5665_M_DAC_R2_STO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto1_dac_r_mix[] = { +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_STO1_DAC_MIXER, +			RT5665_M_DAC_L1_STO_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_STO1_DAC_MIXER, +			RT5665_M_DAC_R1_STO_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_STO1_DAC_MIXER, +			RT5665_M_DAC_L2_STO_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_STO1_DAC_MIXER, +			RT5665_M_DAC_R2_STO_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto2_dac_l_mix[] = { +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_STO2_DAC_MIXER, +			RT5665_M_DAC_L1_STO2_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_STO2_DAC_MIXER, +			RT5665_M_DAC_L2_STO2_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L3 Switch", RT5665_STO2_DAC_MIXER, +			RT5665_M_DAC_L3_STO2_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto2_dac_r_mix[] = { +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_STO2_DAC_MIXER, +			RT5665_M_DAC_R1_STO2_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_STO2_DAC_MIXER, +			RT5665_M_DAC_R2_STO2_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R3 Switch", RT5665_STO2_DAC_MIXER, +			RT5665_M_DAC_R3_STO2_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_mono_dac_l_mix[] = { +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_MONO_DAC_MIXER, +			RT5665_M_DAC_L1_MONO_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_MONO_DAC_MIXER, +			RT5665_M_DAC_R1_MONO_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONO_DAC_MIXER, +			RT5665_M_DAC_L2_MONO_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_MONO_DAC_MIXER, +			RT5665_M_DAC_R2_MONO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_mono_dac_r_mix[] = { +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_MONO_DAC_MIXER, +			RT5665_M_DAC_L1_MONO_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_MONO_DAC_MIXER, +			RT5665_M_DAC_R1_MONO_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONO_DAC_MIXER, +			RT5665_M_DAC_L2_MONO_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_MONO_DAC_MIXER, +			RT5665_M_DAC_R2_MONO_R_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt5665_rec1_l_mix[] = { +	SOC_DAPM_SINGLE("CBJ Switch", RT5665_REC1_L2_MIXER, +			RT5665_M_CBJ_RM1_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("INL Switch", RT5665_REC1_L2_MIXER, +			RT5665_M_INL_RM1_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("INR Switch", RT5665_REC1_L2_MIXER, +			RT5665_M_INR_RM1_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC1_L2_MIXER, +			RT5665_M_BST4_RM1_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC1_L2_MIXER, +			RT5665_M_BST3_RM1_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC1_L2_MIXER, +			RT5665_M_BST2_RM1_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC1_L2_MIXER, +			RT5665_M_BST1_RM1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_rec1_r_mix[] = { +	SOC_DAPM_SINGLE("MONOVOL Switch", RT5665_REC1_R2_MIXER, +			RT5665_M_AEC_REF_RM1_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("INR Switch", RT5665_REC1_R2_MIXER, +			RT5665_M_INR_RM1_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC1_R2_MIXER, +			RT5665_M_BST4_RM1_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC1_R2_MIXER, +			RT5665_M_BST3_RM1_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC1_R2_MIXER, +			RT5665_M_BST2_RM1_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC1_R2_MIXER, +			RT5665_M_BST1_RM1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_rec2_l_mix[] = { +	SOC_DAPM_SINGLE("INL Switch", RT5665_REC2_L2_MIXER, +			RT5665_M_INL_RM2_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("INR Switch", RT5665_REC2_L2_MIXER, +			RT5665_M_INR_RM2_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("CBJ Switch", RT5665_REC2_L2_MIXER, +			RT5665_M_CBJ_RM2_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC2_L2_MIXER, +			RT5665_M_BST4_RM2_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC2_L2_MIXER, +			RT5665_M_BST3_RM2_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC2_L2_MIXER, +			RT5665_M_BST2_RM2_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC2_L2_MIXER, +			RT5665_M_BST1_RM2_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_rec2_r_mix[] = { +	SOC_DAPM_SINGLE("MONOVOL Switch", RT5665_REC2_R2_MIXER, +			RT5665_M_MONOVOL_RM2_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("INL Switch", RT5665_REC2_R2_MIXER, +			RT5665_M_INL_RM2_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("INR Switch", RT5665_REC2_R2_MIXER, +			RT5665_M_INR_RM2_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC2_R2_MIXER, +			RT5665_M_BST4_RM2_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC2_R2_MIXER, +			RT5665_M_BST3_RM2_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC2_R2_MIXER, +			RT5665_M_BST2_RM2_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC2_R2_MIXER, +			RT5665_M_BST1_RM2_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_monovol_mix[] = { +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONOMIX_IN_GAIN, +			RT5665_M_DAC_L2_MM_SFT, 1, 1), +	SOC_DAPM_SINGLE("RECMIX2L Switch", RT5665_MONOMIX_IN_GAIN, +			RT5665_M_RECMIC2L_MM_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST1 Switch", RT5665_MONOMIX_IN_GAIN, +			RT5665_M_BST1_MM_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST2 Switch", RT5665_MONOMIX_IN_GAIN, +			RT5665_M_BST2_MM_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST3 Switch", RT5665_MONOMIX_IN_GAIN, +			RT5665_M_BST3_MM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_out_l_mix[] = { +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_OUT_L_MIXER, +			RT5665_M_DAC_L2_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("INL Switch", RT5665_OUT_L_MIXER, +			RT5665_M_IN_L_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST1 Switch", RT5665_OUT_L_MIXER, +			RT5665_M_BST1_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST2 Switch", RT5665_OUT_L_MIXER, +			RT5665_M_BST2_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST3 Switch", RT5665_OUT_L_MIXER, +			RT5665_M_BST3_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_out_r_mix[] = { +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_OUT_R_MIXER, +			RT5665_M_DAC_R2_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("INR Switch", RT5665_OUT_R_MIXER, +			RT5665_M_IN_R_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST2 Switch", RT5665_OUT_R_MIXER, +			RT5665_M_BST2_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST3 Switch", RT5665_OUT_R_MIXER, +			RT5665_M_BST3_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST4 Switch", RT5665_OUT_R_MIXER, +			RT5665_M_BST4_OM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_mono_mix[] = { +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONOMIX_IN_GAIN, +			RT5665_M_DAC_L2_MA_SFT, 1, 1), +	SOC_DAPM_SINGLE("MONOVOL Switch", RT5665_MONOMIX_IN_GAIN, +			RT5665_M_MONOVOL_MA_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_lout_l_mix[] = { +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_LOUT_MIXER, +			RT5665_M_DAC_L2_LM_SFT, 1, 1), +	SOC_DAPM_SINGLE("OUTVOL L Switch", RT5665_LOUT_MIXER, +			RT5665_M_OV_L_LM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_lout_r_mix[] = { +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_LOUT_MIXER, +			RT5665_M_DAC_R2_LM_SFT, 1, 1), +	SOC_DAPM_SINGLE("OUTVOL R Switch", RT5665_LOUT_MIXER, +			RT5665_M_OV_R_LM_SFT, 1, 1), +}; + +/*DAC L2, DAC R2*/ +/*MX-17 [6:4], MX-17 [2:0]*/ +static const char * const rt5665_dac2_src[] = { +	"IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC", "Mono ADC MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_dac_l2_enum, RT5665_DAC2_CTRL, +	RT5665_DAC_L2_SEL_SFT, rt5665_dac2_src); + +static const struct snd_kcontrol_new rt5665_dac_l2_mux = +	SOC_DAPM_ENUM("Digital DAC L2 Source", rt5665_dac_l2_enum); + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_dac_r2_enum, RT5665_DAC2_CTRL, +	RT5665_DAC_R2_SEL_SFT, rt5665_dac2_src); + +static const struct snd_kcontrol_new rt5665_dac_r2_mux = +	SOC_DAPM_ENUM("Digital DAC R2 Source", rt5665_dac_r2_enum); + +/*DAC L3, DAC R3*/ +/*MX-1B [6:4], MX-1B [2:0]*/ +static const char * const rt5665_dac3_src[] = { +	"IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC", "STO2 ADC MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_dac_l3_enum, RT5665_DAC3_CTRL, +	RT5665_DAC_L3_SEL_SFT, rt5665_dac3_src); + +static const struct snd_kcontrol_new rt5665_dac_l3_mux = +	SOC_DAPM_ENUM("Digital DAC L3 Source", rt5665_dac_l3_enum); + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_dac_r3_enum, RT5665_DAC3_CTRL, +	RT5665_DAC_R3_SEL_SFT, rt5665_dac3_src); + +static const struct snd_kcontrol_new rt5665_dac_r3_mux = +	SOC_DAPM_ENUM("Digital DAC R3 Source", rt5665_dac_r3_enum); + +/* STO1 ADC1 Source */ +/* MX-26 [13] [5] */ +static const char * const rt5665_sto1_adc1_src[] = { +	"DD Mux", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto1_adc1l_enum, RT5665_STO1_ADC_MIXER, +	RT5665_STO1_ADC1L_SRC_SFT, rt5665_sto1_adc1_src); + +static const struct snd_kcontrol_new rt5665_sto1_adc1l_mux = +	SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5665_sto1_adc1l_enum); + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto1_adc1r_enum, RT5665_STO1_ADC_MIXER, +	RT5665_STO1_ADC1R_SRC_SFT, rt5665_sto1_adc1_src); + +static const struct snd_kcontrol_new rt5665_sto1_adc1r_mux = +	SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5665_sto1_adc1r_enum); + +/* STO1 ADC Source */ +/* MX-26 [11:10] [3:2] */ +static const char * const rt5665_sto1_adc_src[] = { +	"ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto1_adcl_enum, RT5665_STO1_ADC_MIXER, +	RT5665_STO1_ADCL_SRC_SFT, rt5665_sto1_adc_src); + +static const struct snd_kcontrol_new rt5665_sto1_adcl_mux = +	SOC_DAPM_ENUM("Stereo1 ADCL Source", rt5665_sto1_adcl_enum); + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto1_adcr_enum, RT5665_STO1_ADC_MIXER, +	RT5665_STO1_ADCR_SRC_SFT, rt5665_sto1_adc_src); + +static const struct snd_kcontrol_new rt5665_sto1_adcr_mux = +	SOC_DAPM_ENUM("Stereo1 ADCR Source", rt5665_sto1_adcr_enum); + +/* STO1 ADC2 Source */ +/* MX-26 [12] [4] */ +static const char * const rt5665_sto1_adc2_src[] = { +	"DAC MIX", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto1_adc2l_enum, RT5665_STO1_ADC_MIXER, +	RT5665_STO1_ADC2L_SRC_SFT, rt5665_sto1_adc2_src); + +static const struct snd_kcontrol_new rt5665_sto1_adc2l_mux = +	SOC_DAPM_ENUM("Stereo1 ADC2L Source", rt5665_sto1_adc2l_enum); + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto1_adc2r_enum, RT5665_STO1_ADC_MIXER, +	RT5665_STO1_ADC2R_SRC_SFT, rt5665_sto1_adc2_src); + +static const struct snd_kcontrol_new rt5665_sto1_adc2r_mux = +	SOC_DAPM_ENUM("Stereo1 ADC2R Source", rt5665_sto1_adc2r_enum); + +/* STO1 DMIC Source */ +/* MX-26 [8] */ +static const char * const rt5665_sto1_dmic_src[] = { +	"DMIC1", "DMIC2" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto1_dmic_enum, RT5665_STO1_ADC_MIXER, +	RT5665_STO1_DMIC_SRC_SFT, rt5665_sto1_dmic_src); + +static const struct snd_kcontrol_new rt5665_sto1_dmic_mux = +	SOC_DAPM_ENUM("Stereo1 DMIC Mux", rt5665_sto1_dmic_enum); + +/* MX-26 [9] */ +static const char * const rt5665_sto1_dd_l_src[] = { +	"STO2 DAC", "MONO DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto1_dd_l_enum, RT5665_STO1_ADC_MIXER, +	RT5665_STO1_DD_L_SRC_SFT, rt5665_sto1_dd_l_src); + +static const struct snd_kcontrol_new rt5665_sto1_dd_l_mux = +	SOC_DAPM_ENUM("Stereo1 DD L Source", rt5665_sto1_dd_l_enum); + +/* MX-26 [1:0] */ +static const char * const rt5665_sto1_dd_r_src[] = { +	"STO2 DAC", "MONO DAC", "AEC REF" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto1_dd_r_enum, RT5665_STO1_ADC_MIXER, +	RT5665_STO1_DD_R_SRC_SFT, rt5665_sto1_dd_r_src); + +static const struct snd_kcontrol_new rt5665_sto1_dd_r_mux = +	SOC_DAPM_ENUM("Stereo1 DD R Source", rt5665_sto1_dd_r_enum); + +/* MONO ADC L2 Source */ +/* MX-27 [12] */ +static const char * const rt5665_mono_adc_l2_src[] = { +	"DAC MIXL", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_mono_adc_l2_enum, RT5665_MONO_ADC_MIXER, +	RT5665_MONO_ADC_L2_SRC_SFT, rt5665_mono_adc_l2_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_l2_mux = +	SOC_DAPM_ENUM("Mono ADC L2 Source", rt5665_mono_adc_l2_enum); + + +/* MONO ADC L1 Source */ +/* MX-27 [13] */ +static const char * const rt5665_mono_adc_l1_src[] = { +	"DD Mux", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_mono_adc_l1_enum, RT5665_MONO_ADC_MIXER, +	RT5665_MONO_ADC_L1_SRC_SFT, rt5665_mono_adc_l1_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_l1_mux = +	SOC_DAPM_ENUM("Mono ADC L1 Source", rt5665_mono_adc_l1_enum); + +/* MX-27 [9][1]*/ +static const char * const rt5665_mono_dd_src[] = { +	"STO2 DAC", "MONO DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_mono_dd_l_enum, RT5665_MONO_ADC_MIXER, +	RT5665_MONO_DD_L_SRC_SFT, rt5665_mono_dd_src); + +static const struct snd_kcontrol_new rt5665_mono_dd_l_mux = +	SOC_DAPM_ENUM("Mono DD L Source", rt5665_mono_dd_l_enum); + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_mono_dd_r_enum, RT5665_MONO_ADC_MIXER, +	RT5665_MONO_DD_R_SRC_SFT, rt5665_mono_dd_src); + +static const struct snd_kcontrol_new rt5665_mono_dd_r_mux = +	SOC_DAPM_ENUM("Mono DD R Source", rt5665_mono_dd_r_enum); + +/* MONO ADC L Source, MONO ADC R Source*/ +/* MX-27 [11:10], MX-27 [3:2] */ +static const char * const rt5665_mono_adc_src[] = { +	"ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_mono_adc_l_enum, RT5665_MONO_ADC_MIXER, +	RT5665_MONO_ADC_L_SRC_SFT, rt5665_mono_adc_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_l_mux = +	SOC_DAPM_ENUM("Mono ADC L Source", rt5665_mono_adc_l_enum); + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_mono_adcr_enum, RT5665_MONO_ADC_MIXER, +	RT5665_MONO_ADC_R_SRC_SFT, rt5665_mono_adc_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_r_mux = +	SOC_DAPM_ENUM("Mono ADC R Source", rt5665_mono_adcr_enum); + +/* MONO DMIC L Source */ +/* MX-27 [8] */ +static const char * const rt5665_mono_dmic_l_src[] = { +	"DMIC1 L", "DMIC2 L" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_mono_dmic_l_enum, RT5665_MONO_ADC_MIXER, +	RT5665_MONO_DMIC_L_SRC_SFT, rt5665_mono_dmic_l_src); + +static const struct snd_kcontrol_new rt5665_mono_dmic_l_mux = +	SOC_DAPM_ENUM("Mono DMIC L Source", rt5665_mono_dmic_l_enum); + +/* MONO ADC R2 Source */ +/* MX-27 [4] */ +static const char * const rt5665_mono_adc_r2_src[] = { +	"DAC MIXR", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_mono_adc_r2_enum, RT5665_MONO_ADC_MIXER, +	RT5665_MONO_ADC_R2_SRC_SFT, rt5665_mono_adc_r2_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_r2_mux = +	SOC_DAPM_ENUM("Mono ADC R2 Source", rt5665_mono_adc_r2_enum); + +/* MONO ADC R1 Source */ +/* MX-27 [5] */ +static const char * const rt5665_mono_adc_r1_src[] = { +	"DD Mux", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_mono_adc_r1_enum, RT5665_MONO_ADC_MIXER, +	RT5665_MONO_ADC_R1_SRC_SFT, rt5665_mono_adc_r1_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_r1_mux = +	SOC_DAPM_ENUM("Mono ADC R1 Source", rt5665_mono_adc_r1_enum); + +/* MONO DMIC R Source */ +/* MX-27 [0] */ +static const char * const rt5665_mono_dmic_r_src[] = { +	"DMIC1 R", "DMIC2 R" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_mono_dmic_r_enum, RT5665_MONO_ADC_MIXER, +	RT5665_MONO_DMIC_R_SRC_SFT, rt5665_mono_dmic_r_src); + +static const struct snd_kcontrol_new rt5665_mono_dmic_r_mux = +	SOC_DAPM_ENUM("Mono DMIC R Source", rt5665_mono_dmic_r_enum); + + +/* STO2 ADC1 Source */ +/* MX-28 [13] [5] */ +static const char * const rt5665_sto2_adc1_src[] = { +	"DD Mux", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto2_adc1l_enum, RT5665_STO2_ADC_MIXER, +	RT5665_STO2_ADC1L_SRC_SFT, rt5665_sto2_adc1_src); + +static const struct snd_kcontrol_new rt5665_sto2_adc1l_mux = +	SOC_DAPM_ENUM("Stereo2 ADC1L Source", rt5665_sto2_adc1l_enum); + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto2_adc1r_enum, RT5665_STO2_ADC_MIXER, +	RT5665_STO2_ADC1R_SRC_SFT, rt5665_sto2_adc1_src); + +static const struct snd_kcontrol_new rt5665_sto2_adc1r_mux = +	SOC_DAPM_ENUM("Stereo2 ADC1L Source", rt5665_sto2_adc1r_enum); + +/* STO2 ADC Source */ +/* MX-28 [11:10] [3:2] */ +static const char * const rt5665_sto2_adc_src[] = { +	"ADC1 L", "ADC1 R", "ADC2 L" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto2_adcl_enum, RT5665_STO2_ADC_MIXER, +	RT5665_STO2_ADCL_SRC_SFT, rt5665_sto2_adc_src); + +static const struct snd_kcontrol_new rt5665_sto2_adcl_mux = +	SOC_DAPM_ENUM("Stereo2 ADCL Source", rt5665_sto2_adcl_enum); + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto2_adcr_enum, RT5665_STO2_ADC_MIXER, +	RT5665_STO2_ADCR_SRC_SFT, rt5665_sto2_adc_src); + +static const struct snd_kcontrol_new rt5665_sto2_adcr_mux = +	SOC_DAPM_ENUM("Stereo2 ADCR Source", rt5665_sto2_adcr_enum); + +/* STO2 ADC2 Source */ +/* MX-28 [12] [4] */ +static const char * const rt5665_sto2_adc2_src[] = { +	"DAC MIX", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto2_adc2l_enum, RT5665_STO2_ADC_MIXER, +	RT5665_STO2_ADC2L_SRC_SFT, rt5665_sto2_adc2_src); + +static const struct snd_kcontrol_new rt5665_sto2_adc2l_mux = +	SOC_DAPM_ENUM("Stereo2 ADC2L Source", rt5665_sto2_adc2l_enum); + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto2_adc2r_enum, RT5665_STO2_ADC_MIXER, +	RT5665_STO2_ADC2R_SRC_SFT, rt5665_sto2_adc2_src); + +static const struct snd_kcontrol_new rt5665_sto2_adc2r_mux = +	SOC_DAPM_ENUM("Stereo2 ADC2R Source", rt5665_sto2_adc2r_enum); + +/* STO2 DMIC Source */ +/* MX-28 [8] */ +static const char * const rt5665_sto2_dmic_src[] = { +	"DMIC1", "DMIC2" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto2_dmic_enum, RT5665_STO2_ADC_MIXER, +	RT5665_STO2_DMIC_SRC_SFT, rt5665_sto2_dmic_src); + +static const struct snd_kcontrol_new rt5665_sto2_dmic_mux = +	SOC_DAPM_ENUM("Stereo2 DMIC Source", rt5665_sto2_dmic_enum); + +/* MX-28 [9] */ +static const char * const rt5665_sto2_dd_l_src[] = { +	"STO2 DAC", "MONO DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto2_dd_l_enum, RT5665_STO2_ADC_MIXER, +	RT5665_STO2_DD_L_SRC_SFT, rt5665_sto2_dd_l_src); + +static const struct snd_kcontrol_new rt5665_sto2_dd_l_mux = +	SOC_DAPM_ENUM("Stereo2 DD L Source", rt5665_sto2_dd_l_enum); + +/* MX-28 [1] */ +static const char * const rt5665_sto2_dd_r_src[] = { +	"STO2 DAC", "MONO DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_sto2_dd_r_enum, RT5665_STO2_ADC_MIXER, +	RT5665_STO2_DD_R_SRC_SFT, rt5665_sto2_dd_r_src); + +static const struct snd_kcontrol_new rt5665_sto2_dd_r_mux = +	SOC_DAPM_ENUM("Stereo2 DD R Source", rt5665_sto2_dd_r_enum); + +/* DAC R1 Source, DAC L1 Source*/ +/* MX-29 [11:10], MX-29 [9:8]*/ +static const char * const rt5665_dac1_src[] = { +	"IF1 DAC1", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_dac_r1_enum, RT5665_AD_DA_MIXER, +	RT5665_DAC1_R_SEL_SFT, rt5665_dac1_src); + +static const struct snd_kcontrol_new rt5665_dac_r1_mux = +	SOC_DAPM_ENUM("DAC R1 Source", rt5665_dac_r1_enum); + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_dac_l1_enum, RT5665_AD_DA_MIXER, +	RT5665_DAC1_L_SEL_SFT, rt5665_dac1_src); + +static const struct snd_kcontrol_new rt5665_dac_l1_mux = +	SOC_DAPM_ENUM("DAC L1 Source", rt5665_dac_l1_enum); + +/* DAC Digital Mixer L Source, DAC Digital Mixer R Source*/ +/* MX-2D [13:12], MX-2D [9:8]*/ +static const char * const rt5665_dig_dac_mix_src[] = { +	"Stereo1 DAC Mixer", "Stereo2 DAC Mixer", "Mono DAC Mixer" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_dig_dac_mixl_enum, RT5665_A_DAC1_MUX, +	RT5665_DAC_MIX_L_SFT, rt5665_dig_dac_mix_src); + +static const struct snd_kcontrol_new rt5665_dig_dac_mixl_mux = +	SOC_DAPM_ENUM("DAC Digital Mixer L Source", rt5665_dig_dac_mixl_enum); + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_dig_dac_mixr_enum, RT5665_A_DAC1_MUX, +	RT5665_DAC_MIX_R_SFT, rt5665_dig_dac_mix_src); + +static const struct snd_kcontrol_new rt5665_dig_dac_mixr_mux = +	SOC_DAPM_ENUM("DAC Digital Mixer R Source", rt5665_dig_dac_mixr_enum); + +/* Analog DAC L1 Source, Analog DAC R1 Source*/ +/* MX-2D [5:4], MX-2D [1:0]*/ +static const char * const rt5665_alg_dac1_src[] = { +	"Stereo1 DAC Mixer", "DAC1", "DMIC1" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_alg_dac_l1_enum, RT5665_A_DAC1_MUX, +	RT5665_A_DACL1_SFT, rt5665_alg_dac1_src); + +static const struct snd_kcontrol_new rt5665_alg_dac_l1_mux = +	SOC_DAPM_ENUM("Analog DAC L1 Source", rt5665_alg_dac_l1_enum); + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_alg_dac_r1_enum, RT5665_A_DAC1_MUX, +	RT5665_A_DACR1_SFT, rt5665_alg_dac1_src); + +static const struct snd_kcontrol_new rt5665_alg_dac_r1_mux = +	SOC_DAPM_ENUM("Analog DAC R1 Source", rt5665_alg_dac_r1_enum); + +/* Analog DAC LR Source, Analog DAC R2 Source*/ +/* MX-2E [5:4], MX-2E [0]*/ +static const char * const rt5665_alg_dac2_src[] = { +	"Mono DAC Mixer", "DAC2" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_alg_dac_l2_enum, RT5665_A_DAC2_MUX, +	RT5665_A_DACL2_SFT, rt5665_alg_dac2_src); + +static const struct snd_kcontrol_new rt5665_alg_dac_l2_mux = +	SOC_DAPM_ENUM("Analog DAC L2 Source", rt5665_alg_dac_l2_enum); + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_alg_dac_r2_enum, RT5665_A_DAC2_MUX, +	RT5665_A_DACR2_SFT, rt5665_alg_dac2_src); + +static const struct snd_kcontrol_new rt5665_alg_dac_r2_mux = +	SOC_DAPM_ENUM("Analog DAC R2 Source", rt5665_alg_dac_r2_enum); + +/* Interface2 ADC Data Input*/ +/* MX-2F [14:12] */ +static const char * const rt5665_if2_1_adc_in_src[] = { +	"STO1 ADC", "STO2 ADC", "MONO ADC", "IF1 DAC1", +	"IF1 DAC2", "IF2_2 DAC", "IF3 DAC", "DAC1 MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_if2_1_adc_in_enum, RT5665_DIG_INF2_DATA, +	RT5665_IF3_ADC_IN_SFT, rt5665_if2_1_adc_in_src); + +static const struct snd_kcontrol_new rt5665_if2_1_adc_in_mux = +	SOC_DAPM_ENUM("IF2_1 ADC IN Source", rt5665_if2_1_adc_in_enum); + +/* MX-2F [6:4] */ +static const char * const rt5665_if2_2_adc_in_src[] = { +	"STO1 ADC", "STO2 ADC", "MONO ADC", "IF1 DAC1", +	"IF1 DAC2", "IF2_1 DAC", "IF3 DAC", "DAC1 MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_if2_2_adc_in_enum, RT5665_DIG_INF2_DATA, +	RT5665_IF2_2_ADC_IN_SFT, rt5665_if2_2_adc_in_src); + +static const struct snd_kcontrol_new rt5665_if2_2_adc_in_mux = +	SOC_DAPM_ENUM("IF2_1 ADC IN Source", rt5665_if2_2_adc_in_enum); + +/* Interface3 ADC Data Input*/ +/* MX-30 [6:4] */ +static const char * const rt5665_if3_adc_in_src[] = { +	"STO1 ADC", "STO2 ADC", "MONO ADC", "IF1 DAC1", +	"IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "DAC1 MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_if3_adc_in_enum, RT5665_DIG_INF3_DATA, +	RT5665_IF3_ADC_IN_SFT, rt5665_if3_adc_in_src); + +static const struct snd_kcontrol_new rt5665_if3_adc_in_mux = +	SOC_DAPM_ENUM("IF3 ADC IN Source", rt5665_if3_adc_in_enum); + +/* PDM 1 L/R*/ +/* MX-31 [11:10] [9:8] */ +static const char * const rt5665_pdm_src[] = { +	"Stereo1 DAC", "Stereo2 DAC", "Mono DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_pdm_l_enum, RT5665_PDM_OUT_CTRL, +	RT5665_PDM1_L_SFT, rt5665_pdm_src); + +static const struct snd_kcontrol_new rt5665_pdm_l_mux = +	SOC_DAPM_ENUM("PDM L Source", rt5665_pdm_l_enum); + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_pdm_r_enum, RT5665_PDM_OUT_CTRL, +	RT5665_PDM1_R_SFT, rt5665_pdm_src); + +static const struct snd_kcontrol_new rt5665_pdm_r_mux = +	SOC_DAPM_ENUM("PDM R Source", rt5665_pdm_r_enum); + + +/* I2S1 TDM ADCDAT Source */ +/* MX-7a[10] */ +static const char * const rt5665_if1_1_adc1_data_src[] = { +	"STO1 ADC", "IF2_1 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_if1_1_adc1_data_enum, RT5665_TDM_CTRL_3, +	RT5665_IF1_ADC1_SEL_SFT, rt5665_if1_1_adc1_data_src); + +static const struct snd_kcontrol_new rt5665_if1_1_adc1_mux = +	SOC_DAPM_ENUM("IF1_1 ADC1 Source", rt5665_if1_1_adc1_data_enum); + +/* MX-7a[9] */ +static const char * const rt5665_if1_1_adc2_data_src[] = { +	"STO2 ADC", "IF2_2 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_if1_1_adc2_data_enum, RT5665_TDM_CTRL_3, +	RT5665_IF1_ADC2_SEL_SFT, rt5665_if1_1_adc2_data_src); + +static const struct snd_kcontrol_new rt5665_if1_1_adc2_mux = +	SOC_DAPM_ENUM("IF1_1 ADC2 Source", rt5665_if1_1_adc2_data_enum); + +/* MX-7a[8] */ +static const char * const rt5665_if1_1_adc3_data_src[] = { +	"MONO ADC", "IF3 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_if1_1_adc3_data_enum, RT5665_TDM_CTRL_3, +	RT5665_IF1_ADC3_SEL_SFT, rt5665_if1_1_adc3_data_src); + +static const struct snd_kcontrol_new rt5665_if1_1_adc3_mux = +	SOC_DAPM_ENUM("IF1_1 ADC3 Source", rt5665_if1_1_adc3_data_enum); + +/* MX-7b[10] */ +static const char * const rt5665_if1_2_adc1_data_src[] = { +	"STO1 ADC", "IF1 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_if1_2_adc1_data_enum, RT5665_TDM_CTRL_4, +	RT5665_IF1_ADC1_SEL_SFT, rt5665_if1_2_adc1_data_src); + +static const struct snd_kcontrol_new rt5665_if1_2_adc1_mux = +	SOC_DAPM_ENUM("IF1_2 ADC1 Source", rt5665_if1_2_adc1_data_enum); + +/* MX-7b[9] */ +static const char * const rt5665_if1_2_adc2_data_src[] = { +	"STO2 ADC", "IF2_1 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_if1_2_adc2_data_enum, RT5665_TDM_CTRL_4, +	RT5665_IF1_ADC2_SEL_SFT, rt5665_if1_2_adc2_data_src); + +static const struct snd_kcontrol_new rt5665_if1_2_adc2_mux = +	SOC_DAPM_ENUM("IF1_2 ADC2 Source", rt5665_if1_2_adc2_data_enum); + +/* MX-7b[8] */ +static const char * const rt5665_if1_2_adc3_data_src[] = { +	"MONO ADC", "IF2_2 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_if1_2_adc3_data_enum, RT5665_TDM_CTRL_4, +	RT5665_IF1_ADC3_SEL_SFT, rt5665_if1_2_adc3_data_src); + +static const struct snd_kcontrol_new rt5665_if1_2_adc3_mux = +	SOC_DAPM_ENUM("IF1_2 ADC3 Source", rt5665_if1_2_adc3_data_enum); + +/* MX-7b[7] */ +static const char * const rt5665_if1_2_adc4_data_src[] = { +	"DAC1", "IF3 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_if1_2_adc4_data_enum, RT5665_TDM_CTRL_4, +	RT5665_IF1_ADC4_SEL_SFT, rt5665_if1_2_adc4_data_src); + +static const struct snd_kcontrol_new rt5665_if1_2_adc4_mux = +	SOC_DAPM_ENUM("IF1_2 ADC4 Source", rt5665_if1_2_adc4_data_enum); + +/* MX-7a[4:0] MX-7b[4:0] */ +static const char * const rt5665_tdm_adc_data_src[] = { +	"1234", "1243", "1324",	"1342", "1432", "1423", +	"2134", "2143", "2314",	"2341", "2431", "2413", +	"3124", "3142", "3214", "3241", "3412", "3421", +	"4123", "4132", "4213", "4231", "4312", "4321" +}; + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_tdm1_adc_data_enum, RT5665_TDM_CTRL_3, +	RT5665_TDM_ADC_SEL_SFT, rt5665_tdm_adc_data_src); + +static const struct snd_kcontrol_new rt5665_tdm1_adc_mux = +	SOC_DAPM_ENUM("TDM1 ADC Mux", rt5665_tdm1_adc_data_enum); + +static const SOC_ENUM_SINGLE_DECL( +	rt5665_tdm2_adc_data_enum, RT5665_TDM_CTRL_4, +	RT5665_TDM_ADC_SEL_SFT, rt5665_tdm_adc_data_src); + +static const struct snd_kcontrol_new rt5665_tdm2_adc_mux = +	SOC_DAPM_ENUM("TDM2 ADCDAT Source", rt5665_tdm2_adc_data_enum); + +/* Out Volume Switch */ +static const struct snd_kcontrol_new monovol_switch = +	SOC_DAPM_SINGLE("Switch", RT5665_MONO_OUT, RT5665_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new outvol_l_switch = +	SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new outvol_r_switch = +	SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_VOL_R_SFT, 1, 1); + +/* Out Switch */ +static const struct snd_kcontrol_new mono_switch = +	SOC_DAPM_SINGLE("Switch", RT5665_MONO_OUT, RT5665_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hpo_switch = +	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5665_HP_CTRL_2, +					RT5665_VOL_L_SFT, 1, 0); + +static const struct snd_kcontrol_new lout_l_switch = +	SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new lout_r_switch = +	SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_R_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new pdm_l_switch = +	SOC_DAPM_SINGLE("Switch", RT5665_PDM_OUT_CTRL, +			RT5665_M_PDM1_L_SFT, 1,	1); + +static const struct snd_kcontrol_new pdm_r_switch = +	SOC_DAPM_SINGLE("Switch", RT5665_PDM_OUT_CTRL, +			RT5665_M_PDM1_R_SFT, 1,	1); + +static int rt5665_mono_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + +	switch (event) { +	case SND_SOC_DAPM_PRE_PMU: +		snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1, +			RT5665_NG2_EN_MASK, RT5665_NG2_EN); +		snd_soc_update_bits(codec, RT5665_MONO_AMP_CALIB_CTRL_1, 0x40, +			0x0); +		snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x10, 0x10); +		snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x20, 0x20); +		break; + +	case SND_SOC_DAPM_POST_PMD: +		snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x20, 0); +		snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x10, 0); +		snd_soc_update_bits(codec, RT5665_MONO_AMP_CALIB_CTRL_1, 0x40, +			0x40); +		snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1, +			RT5665_NG2_EN_MASK, RT5665_NG2_DIS); +		break; + +	default: +		return 0; +	} + +	return 0; + +} + +static int rt5665_hp_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + +	switch (event) { +	case SND_SOC_DAPM_PRE_PMU: +		snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1, +			RT5665_NG2_EN_MASK, RT5665_NG2_EN); +		snd_soc_write(codec, RT5665_HP_LOGIC_CTRL_2, 0x0003); +		break; + +	case SND_SOC_DAPM_POST_PMD: +		snd_soc_write(codec, RT5665_HP_LOGIC_CTRL_2, 0x0002); +		snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1, +			RT5665_NG2_EN_MASK, RT5665_NG2_DIS); +		break; + +	default: +		return 0; +	} + +	return 0; + +} + +static int rt5665_lout_event(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		snd_soc_update_bits(codec, RT5665_DEPOP_1, +			RT5665_PUMP_EN, RT5665_PUMP_EN); +		break; + +	case SND_SOC_DAPM_PRE_PMD: +		snd_soc_update_bits(codec, RT5665_DEPOP_1, +			RT5665_PUMP_EN, 0); +		break; + +	default: +		return 0; +	} + +	return 0; + +} + +static int set_dmic_power(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	switch (event) { +	case SND_SOC_DAPM_POST_PMU: +		/*Add delay to avoid pop noise*/ +		msleep(150); +		break; + +	default: +		return 0; +	} + +	return 0; +} + +static int rt5655_set_verf(struct snd_soc_dapm_widget *w, +	struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + +	switch (event) { +	case SND_SOC_DAPM_PRE_PMU: +		switch (w->shift) { +		case RT5665_PWR_VREF1_BIT: +			snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, +				RT5665_PWR_FV1, 0); +			break; + +		case RT5665_PWR_VREF2_BIT: +			snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, +				RT5665_PWR_FV2, 0); +			break; + +		case RT5665_PWR_VREF3_BIT: +			snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, +				RT5665_PWR_FV3, 0); +			break; + +		default: +			break; +		} +		break; + +	case SND_SOC_DAPM_POST_PMU: +		usleep_range(15000, 20000); +		switch (w->shift) { +		case RT5665_PWR_VREF1_BIT: +			snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, +				RT5665_PWR_FV1, RT5665_PWR_FV1); +			break; + +		case RT5665_PWR_VREF2_BIT: +			snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, +				RT5665_PWR_FV2, RT5665_PWR_FV2); +			break; + +		case RT5665_PWR_VREF3_BIT: +			snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, +				RT5665_PWR_FV3, RT5665_PWR_FV3); +			break; + +		default: +			break; +		} +		break; + +	default: +		return 0; +	} + +	return 0; +} + + +static const struct snd_soc_dapm_widget rt5665_dapm_widgets[] = { +	SND_SOC_DAPM_SUPPLY("LDO2", RT5665_PWR_ANLG_3, RT5665_PWR_LDO2_BIT, 0, +		NULL, 0), +	SND_SOC_DAPM_SUPPLY("PLL", RT5665_PWR_ANLG_3, RT5665_PWR_PLL_BIT, 0, +		NULL, 0), +	SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5665_PWR_VOL, +		RT5665_PWR_MIC_DET_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("Vref1", RT5665_PWR_ANLG_1, RT5665_PWR_VREF1_BIT, 0, +		rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +	SND_SOC_DAPM_SUPPLY("Vref2", RT5665_PWR_ANLG_1, RT5665_PWR_VREF2_BIT, 0, +		rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +	SND_SOC_DAPM_SUPPLY("Vref3", RT5665_PWR_ANLG_1, RT5665_PWR_VREF3_BIT, 0, +		rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + +	/* ASRC */ +	SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5665_ASRC_1, +		RT5665_I2S1_ASRC_SFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5665_ASRC_1, +		RT5665_I2S2_ASRC_SFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5665_ASRC_1, +		RT5665_I2S3_ASRC_SFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5665_ASRC_1, +		RT5665_DAC_STO1_ASRC_SFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("DAC STO2 ASRC", 1, RT5665_ASRC_1, +		RT5665_DAC_STO2_ASRC_SFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("DAC Mono L ASRC", 1, RT5665_ASRC_1, +		RT5665_DAC_MONO_L_ASRC_SFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("DAC Mono R ASRC", 1, RT5665_ASRC_1, +		RT5665_DAC_MONO_R_ASRC_SFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5665_ASRC_1, +		RT5665_ADC_STO1_ASRC_SFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("ADC Mono L ASRC", 1, RT5665_ASRC_1, +		RT5665_ADC_MONO_L_ASRC_SFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("ADC Mono R ASRC", 1, RT5665_ASRC_1, +		RT5665_ADC_MONO_R_ASRC_SFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5665_ASRC_1, +		RT5665_DMIC_STO1_ASRC_SFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5665_ASRC_1, +		RT5665_DMIC_STO2_ASRC_SFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5665_ASRC_1, +		RT5665_DMIC_MONO_L_ASRC_SFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5665_ASRC_1, +		RT5665_DMIC_MONO_R_ASRC_SFT, 0, NULL, 0), + +	/* Input Side */ +	SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5665_PWR_ANLG_2, RT5665_PWR_MB1_BIT, +		0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5665_PWR_ANLG_2, RT5665_PWR_MB2_BIT, +		0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("MICBIAS3", RT5665_PWR_ANLG_2, RT5665_PWR_MB3_BIT, +		0, NULL, 0), + +	/* Input Lines */ +	SND_SOC_DAPM_INPUT("DMIC L1"), +	SND_SOC_DAPM_INPUT("DMIC R1"), +	SND_SOC_DAPM_INPUT("DMIC L2"), +	SND_SOC_DAPM_INPUT("DMIC R2"), + +	SND_SOC_DAPM_INPUT("IN1P"), +	SND_SOC_DAPM_INPUT("IN1N"), +	SND_SOC_DAPM_INPUT("IN2P"), +	SND_SOC_DAPM_INPUT("IN2N"), +	SND_SOC_DAPM_INPUT("IN3P"), +	SND_SOC_DAPM_INPUT("IN3N"), +	SND_SOC_DAPM_INPUT("IN4P"), +	SND_SOC_DAPM_INPUT("IN4N"), + +	SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, +		set_dmic_clk, SND_SOC_DAPM_PRE_PMU), +	SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5665_DMIC_CTRL_1, +		RT5665_DMIC_1_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU), +	SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5665_DMIC_CTRL_1, +		RT5665_DMIC_2_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU), + +	/* Boost */ +	SND_SOC_DAPM_PGA("BST1", SND_SOC_NOPM, +		0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("BST2", SND_SOC_NOPM, +		0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("BST3", SND_SOC_NOPM, +		0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("BST4", SND_SOC_NOPM, +		0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM, +		0, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("BST1 Power", RT5665_PWR_ANLG_2, +		RT5665_PWR_BST1_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("BST2 Power", RT5665_PWR_ANLG_2, +		RT5665_PWR_BST2_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("BST3 Power", RT5665_PWR_ANLG_2, +		RT5665_PWR_BST3_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("BST4 Power", RT5665_PWR_ANLG_2, +		RT5665_PWR_BST4_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("BST1P Power", RT5665_PWR_ANLG_2, +		RT5665_PWR_BST1_P_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("BST2P Power", RT5665_PWR_ANLG_2, +		RT5665_PWR_BST2_P_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("BST3P Power", RT5665_PWR_ANLG_2, +		RT5665_PWR_BST3_P_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("BST4P Power", RT5665_PWR_ANLG_2, +		RT5665_PWR_BST4_P_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("CBJ Power", RT5665_PWR_ANLG_3, +		RT5665_PWR_CBJ_BIT, 0, NULL, 0), + + +	/* Input Volume */ +	SND_SOC_DAPM_PGA("INL VOL", RT5665_PWR_VOL, RT5665_PWR_IN_L_BIT, +		0, NULL, 0), +	SND_SOC_DAPM_PGA("INR VOL", RT5665_PWR_VOL, RT5665_PWR_IN_R_BIT, +		0, NULL, 0), + +	/* REC Mixer */ +	SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5665_rec1_l_mix, +		ARRAY_SIZE(rt5665_rec1_l_mix)), +	SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5665_rec1_r_mix, +		ARRAY_SIZE(rt5665_rec1_r_mix)), +	SND_SOC_DAPM_MIXER("RECMIX2L", SND_SOC_NOPM, 0, 0, rt5665_rec2_l_mix, +		ARRAY_SIZE(rt5665_rec2_l_mix)), +	SND_SOC_DAPM_MIXER("RECMIX2R", SND_SOC_NOPM, 0, 0, rt5665_rec2_r_mix, +		ARRAY_SIZE(rt5665_rec2_r_mix)), +	SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5665_PWR_ANLG_2, +		RT5665_PWR_RM1_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("RECMIX1R Power", RT5665_PWR_ANLG_2, +		RT5665_PWR_RM1_R_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("RECMIX2L Power", RT5665_PWR_MIXER, +		RT5665_PWR_RM2_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("RECMIX2R Power", RT5665_PWR_MIXER, +		RT5665_PWR_RM2_R_BIT, 0, NULL, 0), + +	/* ADCs */ +	SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_ADC("ADC2 L", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_ADC("ADC2 R", NULL, SND_SOC_NOPM, 0, 0), + +	SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5665_PWR_DIG_1, +		RT5665_PWR_ADC_L1_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5665_PWR_DIG_1, +		RT5665_PWR_ADC_R1_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("ADC2 L Power", RT5665_PWR_DIG_1, +		RT5665_PWR_ADC_L2_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("ADC2 R Power", RT5665_PWR_DIG_1, +		RT5665_PWR_ADC_R2_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("ADC1 clock", RT5665_CHOP_ADC, +		RT5665_CKGEN_ADC1_SFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("ADC2 clock", RT5665_CHOP_ADC, +		RT5665_CKGEN_ADC2_SFT, 0, NULL, 0), + +	/* ADC Mux */ +	SND_SOC_DAPM_MUX("Stereo1 DMIC L Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto1_dmic_mux), +	SND_SOC_DAPM_MUX("Stereo1 DMIC R Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto1_dmic_mux), +	SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto1_adc1l_mux), +	SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto1_adc1r_mux), +	SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto1_adc2l_mux), +	SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto1_adc2r_mux), +	SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto1_adcl_mux), +	SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto1_adcr_mux), +	SND_SOC_DAPM_MUX("Stereo1 DD L Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto1_dd_l_mux), +	SND_SOC_DAPM_MUX("Stereo1 DD R Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto1_dd_r_mux), +	SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_mono_adc_l2_mux), +	SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_mono_adc_r2_mux), +	SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_mono_adc_l1_mux), +	SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_mono_adc_r1_mux), +	SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_mono_dmic_l_mux), +	SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_mono_dmic_r_mux), +	SND_SOC_DAPM_MUX("Mono ADC L Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_mono_adc_l_mux), +	SND_SOC_DAPM_MUX("Mono ADC R Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_mono_adc_r_mux), +	SND_SOC_DAPM_MUX("Mono DD L Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_mono_dd_l_mux), +	SND_SOC_DAPM_MUX("Mono DD R Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_mono_dd_r_mux), +	SND_SOC_DAPM_MUX("Stereo2 DMIC L Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto2_dmic_mux), +	SND_SOC_DAPM_MUX("Stereo2 DMIC R Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto2_dmic_mux), +	SND_SOC_DAPM_MUX("Stereo2 ADC L1 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto2_adc1l_mux), +	SND_SOC_DAPM_MUX("Stereo2 ADC R1 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto2_adc1r_mux), +	SND_SOC_DAPM_MUX("Stereo2 ADC L2 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto2_adc2l_mux), +	SND_SOC_DAPM_MUX("Stereo2 ADC R2 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto2_adc2r_mux), +	SND_SOC_DAPM_MUX("Stereo2 ADC L Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto2_adcl_mux), +	SND_SOC_DAPM_MUX("Stereo2 ADC R Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto2_adcr_mux), +	SND_SOC_DAPM_MUX("Stereo2 DD L Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto2_dd_l_mux), +	SND_SOC_DAPM_MUX("Stereo2 DD R Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_sto2_dd_r_mux), +	/* ADC Mixer */ +	SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5665_PWR_DIG_2, +		RT5665_PWR_ADC_S1F_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("ADC Stereo2 Filter", RT5665_PWR_DIG_2, +		RT5665_PWR_ADC_S2F_BIT, 0, NULL, 0), +	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", RT5665_STO1_ADC_DIG_VOL, +		RT5665_L_MUTE_SFT, 1, rt5665_sto1_adc_l_mix, +		ARRAY_SIZE(rt5665_sto1_adc_l_mix)), +	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", RT5665_STO1_ADC_DIG_VOL, +		RT5665_R_MUTE_SFT, 1, rt5665_sto1_adc_r_mix, +		ARRAY_SIZE(rt5665_sto1_adc_r_mix)), +	SND_SOC_DAPM_MIXER("Stereo2 ADC MIXL", RT5665_STO2_ADC_DIG_VOL, +		RT5665_L_MUTE_SFT, 1, rt5665_sto2_adc_l_mix, +		ARRAY_SIZE(rt5665_sto2_adc_l_mix)), +	SND_SOC_DAPM_MIXER("Stereo2 ADC MIXR", RT5665_STO2_ADC_DIG_VOL, +		RT5665_R_MUTE_SFT, 1, rt5665_sto2_adc_r_mix, +		ARRAY_SIZE(rt5665_sto2_adc_r_mix)), +	SND_SOC_DAPM_SUPPLY("ADC Mono Left Filter", RT5665_PWR_DIG_2, +		RT5665_PWR_ADC_MF_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_MIXER("Mono ADC MIXL", RT5665_MONO_ADC_DIG_VOL, +		RT5665_L_MUTE_SFT, 1, rt5665_mono_adc_l_mix, +		ARRAY_SIZE(rt5665_mono_adc_l_mix)), +	SND_SOC_DAPM_SUPPLY("ADC Mono Right Filter", RT5665_PWR_DIG_2, +		RT5665_PWR_ADC_MF_R_BIT, 0, NULL, 0), +	SND_SOC_DAPM_MIXER("Mono ADC MIXR", RT5665_MONO_ADC_DIG_VOL, +		RT5665_R_MUTE_SFT, 1, rt5665_mono_adc_r_mix, +		ARRAY_SIZE(rt5665_mono_adc_r_mix)), + +	/* ADC PGA */ +	SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Stereo2 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + +	/* Digital Interface */ +	SND_SOC_DAPM_SUPPLY("I2S1_1", RT5665_PWR_DIG_1, RT5665_PWR_I2S1_1_BIT, +		0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("I2S1_2", RT5665_PWR_DIG_1, RT5665_PWR_I2S1_2_BIT, +		0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("I2S2_1", RT5665_PWR_DIG_1, RT5665_PWR_I2S2_1_BIT, +		0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("I2S2_2", RT5665_PWR_DIG_1, RT5665_PWR_I2S2_2_BIT, +		0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("I2S3", RT5665_PWR_DIG_1, RT5665_PWR_I2S3_BIT, +		0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC3 L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF1 DAC3 R", SND_SOC_NOPM, 0, 0, NULL, 0), + +	SND_SOC_DAPM_PGA("IF2_1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2_2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2_1 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2_1 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2_2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2_2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2_1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF2_2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + +	SND_SOC_DAPM_PGA("IF3 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF3 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF3 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_PGA("IF3 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + +	/* Digital Interface Select */ +	SND_SOC_DAPM_MUX("IF1_1_ADC1 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_if1_1_adc1_mux), +	SND_SOC_DAPM_MUX("IF1_1_ADC2 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_if1_1_adc2_mux), +	SND_SOC_DAPM_MUX("IF1_1_ADC3 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_if1_1_adc3_mux), +	SND_SOC_DAPM_PGA("IF1_1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), +	SND_SOC_DAPM_MUX("IF1_2_ADC1 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_if1_2_adc1_mux), +	SND_SOC_DAPM_MUX("IF1_2_ADC2 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_if1_2_adc2_mux), +	SND_SOC_DAPM_MUX("IF1_2_ADC3 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_if1_2_adc3_mux), +	SND_SOC_DAPM_MUX("IF1_2_ADC4 Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_if1_2_adc4_mux), +	SND_SOC_DAPM_MUX("TDM1 slot 01 Data Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_tdm1_adc_mux), +	SND_SOC_DAPM_MUX("TDM1 slot 23 Data Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_tdm1_adc_mux), +	SND_SOC_DAPM_MUX("TDM1 slot 45 Data Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_tdm1_adc_mux), +	SND_SOC_DAPM_MUX("TDM1 slot 67 Data Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_tdm1_adc_mux), +	SND_SOC_DAPM_MUX("TDM2 slot 01 Data Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_tdm2_adc_mux), +	SND_SOC_DAPM_MUX("TDM2 slot 23 Data Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_tdm2_adc_mux), +	SND_SOC_DAPM_MUX("TDM2 slot 45 Data Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_tdm2_adc_mux), +	SND_SOC_DAPM_MUX("TDM2 slot 67 Data Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_tdm2_adc_mux), +	SND_SOC_DAPM_MUX("IF2_1 ADC Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_if2_1_adc_in_mux), +	SND_SOC_DAPM_MUX("IF2_2 ADC Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_if2_2_adc_in_mux), +	SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0, +		&rt5665_if3_adc_in_mux), +	SND_SOC_DAPM_MUX("IF1_1 0 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if1_1_01_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF1_1 1 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if1_1_01_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF1_1 2 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if1_1_23_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF1_1 3 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if1_1_23_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF1_1 4 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if1_1_45_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF1_1 5 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if1_1_45_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF1_1 6 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if1_1_67_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF1_1 7 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if1_1_67_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF1_2 0 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if1_2_01_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF1_2 1 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if1_2_01_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF1_2 2 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if1_2_23_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF1_2 3 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if1_2_23_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF1_2 4 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if1_2_45_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF1_2 5 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if1_2_45_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF1_2 6 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if1_2_67_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF1_2 7 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if1_2_67_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF2_1 DAC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if2_1_dac_swap_mux), +	SND_SOC_DAPM_MUX("IF2_1 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if2_1_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF2_2 DAC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if2_2_dac_swap_mux), +	SND_SOC_DAPM_MUX("IF2_2 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if2_2_adc_swap_mux), +	SND_SOC_DAPM_MUX("IF3 DAC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if3_dac_swap_mux), +	SND_SOC_DAPM_MUX("IF3 ADC Swap Mux", SND_SOC_NOPM, 0, 0, +			&rt5665_if3_adc_swap_mux), + +	/* Audio Interface */ +	SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 0", "AIF1_1 Capture", +				0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 1", "AIF1_1 Capture", +				1, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 2", "AIF1_1 Capture", +				2, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 3", "AIF1_1 Capture", +				3, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 4", "AIF1_1 Capture", +				4, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 5", "AIF1_1 Capture", +				5, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 6", "AIF1_1 Capture", +				6, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 7", "AIF1_1 Capture", +				7, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 0", "AIF1_2 Capture", +				0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 1", "AIF1_2 Capture", +				1, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 2", "AIF1_2 Capture", +				2, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 3", "AIF1_2 Capture", +				3, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 4", "AIF1_2 Capture", +				4, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 5", "AIF1_2 Capture", +				5, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 6", "AIF1_2 Capture", +				6, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 7", "AIF1_2 Capture", +				7, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF2_1TX", "AIF2_1 Capture", +				0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF2_2TX", "AIF2_2 Capture", +				0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_OUT("AIF3TX", "AIF3 Capture", +				0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", +				0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_IN("AIF2_1RX", "AIF2_1 Playback", +				0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_IN("AIF2_2RX", "AIF2_2 Playback", +				0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_IN("AIF3RX", "AIF3 Playback", +				0, SND_SOC_NOPM, 0, 0), + +	/* Output Side */ +	/* DAC mixer before sound effect  */ +	SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, +		rt5665_dac_l_mix, ARRAY_SIZE(rt5665_dac_l_mix)), +	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, +		rt5665_dac_r_mix, ARRAY_SIZE(rt5665_dac_r_mix)), + +	/* DAC channel Mux */ +	SND_SOC_DAPM_MUX("DAC L1 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_l1_mux), +	SND_SOC_DAPM_MUX("DAC R1 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_r1_mux), +	SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_l2_mux), +	SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_r2_mux), +	SND_SOC_DAPM_MUX("DAC L3 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_l3_mux), +	SND_SOC_DAPM_MUX("DAC R3 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_r3_mux), + +	SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0, +		&rt5665_alg_dac_l1_mux), +	SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0, +		&rt5665_alg_dac_r1_mux), +	SND_SOC_DAPM_MUX("DAC L2 Source", SND_SOC_NOPM, 0, 0, +		&rt5665_alg_dac_l2_mux), +	SND_SOC_DAPM_MUX("DAC R2 Source", SND_SOC_NOPM, 0, 0, +		&rt5665_alg_dac_r2_mux), + +	/* DAC Mixer */ +	SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5665_PWR_DIG_2, +		RT5665_PWR_DAC_S1F_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("DAC Stereo2 Filter", RT5665_PWR_DIG_2, +		RT5665_PWR_DAC_S2F_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("DAC Mono Left Filter", RT5665_PWR_DIG_2, +		RT5665_PWR_DAC_MF_L_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("DAC Mono Right Filter", RT5665_PWR_DIG_2, +		RT5665_PWR_DAC_MF_R_BIT, 0, NULL, 0), +	SND_SOC_DAPM_MIXER("Stereo1 DAC MIXL", SND_SOC_NOPM, 0, 0, +		rt5665_sto1_dac_l_mix, ARRAY_SIZE(rt5665_sto1_dac_l_mix)), +	SND_SOC_DAPM_MIXER("Stereo1 DAC MIXR", SND_SOC_NOPM, 0, 0, +		rt5665_sto1_dac_r_mix, ARRAY_SIZE(rt5665_sto1_dac_r_mix)), +	SND_SOC_DAPM_MIXER("Stereo2 DAC MIXL", SND_SOC_NOPM, 0, 0, +		rt5665_sto2_dac_l_mix, ARRAY_SIZE(rt5665_sto2_dac_l_mix)), +	SND_SOC_DAPM_MIXER("Stereo2 DAC MIXR", SND_SOC_NOPM, 0, 0, +		rt5665_sto2_dac_r_mix, ARRAY_SIZE(rt5665_sto2_dac_r_mix)), +	SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0, +		rt5665_mono_dac_l_mix, ARRAY_SIZE(rt5665_mono_dac_l_mix)), +	SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0, +		rt5665_mono_dac_r_mix, ARRAY_SIZE(rt5665_mono_dac_r_mix)), +	SND_SOC_DAPM_MUX("DAC MIXL", SND_SOC_NOPM, 0, 0, +		&rt5665_dig_dac_mixl_mux), +	SND_SOC_DAPM_MUX("DAC MIXR", SND_SOC_NOPM, 0, 0, +		&rt5665_dig_dac_mixr_mux), + +	/* DACs */ +	SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0), + +	SND_SOC_DAPM_SUPPLY("DAC L2 Power", RT5665_PWR_DIG_1, +		RT5665_PWR_DAC_L2_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("DAC R2 Power", RT5665_PWR_DIG_1, +		RT5665_PWR_DAC_R2_BIT, 0, NULL, 0), +	SND_SOC_DAPM_DAC("DAC L2", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_DAC("DAC R2", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_PGA("DAC1 MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY_S("DAC 1 Clock", 1, RT5665_CHOP_DAC, +		RT5665_CKGEN_DAC1_SFT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY_S("DAC 2 Clock", 1, RT5665_CHOP_DAC, +		RT5665_CKGEN_DAC2_SFT, 0, NULL, 0), + +	/* OUT Mixer */ +	SND_SOC_DAPM_MIXER("MONOVOL MIX", RT5665_PWR_MIXER, RT5665_PWR_MM_BIT, +		0, rt5665_monovol_mix, ARRAY_SIZE(rt5665_monovol_mix)), +	SND_SOC_DAPM_MIXER("OUT MIXL", RT5665_PWR_MIXER, RT5665_PWR_OM_L_BIT, +		0, rt5665_out_l_mix, ARRAY_SIZE(rt5665_out_l_mix)), +	SND_SOC_DAPM_MIXER("OUT MIXR", RT5665_PWR_MIXER, RT5665_PWR_OM_R_BIT, +		0, rt5665_out_r_mix, ARRAY_SIZE(rt5665_out_r_mix)), + +	/* Output Volume */ +	SND_SOC_DAPM_SWITCH("MONOVOL", RT5665_PWR_VOL, RT5665_PWR_MV_BIT, 0, +		&monovol_switch), +	SND_SOC_DAPM_SWITCH("OUTVOL L", RT5665_PWR_VOL, RT5665_PWR_OV_L_BIT, 0, +		&outvol_l_switch), +	SND_SOC_DAPM_SWITCH("OUTVOL R", RT5665_PWR_VOL, RT5665_PWR_OV_R_BIT, 0, +		&outvol_r_switch), + +	/* MONO/HPO/LOUT */ +	SND_SOC_DAPM_MIXER("Mono MIX", SND_SOC_NOPM, 0,	0, rt5665_mono_mix, +		ARRAY_SIZE(rt5665_mono_mix)), +	SND_SOC_DAPM_MIXER("LOUT L MIX", SND_SOC_NOPM, 0, 0, rt5665_lout_l_mix, +		ARRAY_SIZE(rt5665_lout_l_mix)), +	SND_SOC_DAPM_MIXER("LOUT R MIX", SND_SOC_NOPM, 0, 0, rt5665_lout_r_mix, +		ARRAY_SIZE(rt5665_lout_r_mix)), +	SND_SOC_DAPM_PGA_S("Mono Amp", 1, RT5665_PWR_ANLG_1, RT5665_PWR_MA_BIT, +		0, rt5665_mono_event, SND_SOC_DAPM_POST_PMD | +		SND_SOC_DAPM_PRE_PMU), +	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5665_hp_event, +		SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU), +	SND_SOC_DAPM_PGA_S("LOUT Amp", 1, RT5665_PWR_ANLG_1, +		RT5665_PWR_LM_BIT, 0, rt5665_lout_event, +		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | +		SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU), + +	SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0, +		rt5665_charge_pump_event, SND_SOC_DAPM_PRE_PMU | +		SND_SOC_DAPM_POST_PMD), + +	SND_SOC_DAPM_SWITCH("Mono Playback", SND_SOC_NOPM, 0, 0, +		&mono_switch), +	SND_SOC_DAPM_SWITCH("HPO Playback", SND_SOC_NOPM, 0, 0, +		&hpo_switch), +	SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0, +		&lout_l_switch), +	SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0, +		&lout_r_switch), +	SND_SOC_DAPM_SWITCH("PDM L Playback", SND_SOC_NOPM, 0, 0, +		&pdm_l_switch), +	SND_SOC_DAPM_SWITCH("PDM R Playback", SND_SOC_NOPM, 0, 0, +		&pdm_r_switch), + +	/* PDM */ +	SND_SOC_DAPM_SUPPLY("PDM Power", RT5665_PWR_DIG_2, +		RT5665_PWR_PDM1_BIT, 0, NULL, 0), +	SND_SOC_DAPM_MUX("PDM L Mux", SND_SOC_NOPM, +		0, 1, &rt5665_pdm_l_mux), +	SND_SOC_DAPM_MUX("PDM R Mux", SND_SOC_NOPM, +		0, 1, &rt5665_pdm_r_mux), + +	/* CLK DET */ +	SND_SOC_DAPM_SUPPLY("CLKDET SYS", RT5665_CLK_DET, RT5665_SYS_CLK_DET, +		0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("CLKDET HP", RT5665_CLK_DET, RT5665_HP_CLK_DET, +		0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("CLKDET MONO", RT5665_CLK_DET, RT5665_MONO_CLK_DET, +		0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("CLKDET LOUT", RT5665_CLK_DET, RT5665_LOUT_CLK_DET, +		0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("CLKDET", RT5665_CLK_DET, RT5665_POW_CLK_DET, +		0, NULL, 0), + +	/* Output Lines */ +	SND_SOC_DAPM_OUTPUT("HPOL"), +	SND_SOC_DAPM_OUTPUT("HPOR"), +	SND_SOC_DAPM_OUTPUT("LOUTL"), +	SND_SOC_DAPM_OUTPUT("LOUTR"), +	SND_SOC_DAPM_OUTPUT("MONOOUT"), +	SND_SOC_DAPM_OUTPUT("PDML"), +	SND_SOC_DAPM_OUTPUT("PDMR"), +}; + +static const struct snd_soc_dapm_route rt5665_dapm_routes[] = { +	/*PLL*/ +	{"ADC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll}, +	{"ADC Stereo2 Filter", NULL, "PLL", is_sys_clk_from_pll}, +	{"ADC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll}, +	{"ADC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll}, +	{"DAC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll}, +	{"DAC Stereo2 Filter", NULL, "PLL", is_sys_clk_from_pll}, +	{"DAC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll}, +	{"DAC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll}, + +	/*ASRC*/ +	{"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc}, +	{"ADC Mono Left Filter", NULL, "ADC Mono L ASRC", is_using_asrc}, +	{"ADC Mono Right Filter", NULL, "ADC Mono R ASRC", is_using_asrc}, +	{"DAC Mono Left Filter", NULL, "DAC Mono L ASRC", is_using_asrc}, +	{"DAC Mono Right Filter", NULL, "DAC Mono R ASRC", is_using_asrc}, +	{"DAC Stereo1 Filter", NULL, "DAC STO1 ASRC", is_using_asrc}, +	{"DAC Stereo2 Filter", NULL, "DAC STO2 ASRC", is_using_asrc}, + +	/*Vref*/ +	{"Mic Det Power", NULL, "Vref2"}, +	{"MICBIAS1", NULL, "Vref1"}, +	{"MICBIAS1", NULL, "Vref2"}, +	{"MICBIAS2", NULL, "Vref1"}, +	{"MICBIAS2", NULL, "Vref2"}, +	{"MICBIAS3", NULL, "Vref1"}, +	{"MICBIAS3", NULL, "Vref2"}, + +	{"Stereo1 DMIC L Mux", NULL, "DMIC STO1 ASRC"}, +	{"Stereo1 DMIC R Mux", NULL, "DMIC STO1 ASRC"}, +	{"Stereo2 DMIC L Mux", NULL, "DMIC STO2 ASRC"}, +	{"Stereo2 DMIC R Mux", NULL, "DMIC STO2 ASRC"}, +	{"Mono DMIC L Mux", NULL, "DMIC MONO L ASRC"}, +	{"Mono DMIC R Mux", NULL, "DMIC MONO R ASRC"}, + +	{"I2S1_1", NULL, "I2S1 ASRC"}, +	{"I2S1_2", NULL, "I2S1 ASRC"}, +	{"I2S2_1", NULL, "I2S2 ASRC"}, +	{"I2S2_2", NULL, "I2S2 ASRC"}, +	{"I2S3", NULL, "I2S3 ASRC"}, + +	{"CLKDET SYS", NULL, "CLKDET"}, +	{"CLKDET HP", NULL, "CLKDET"}, +	{"CLKDET MONO", NULL, "CLKDET"}, +	{"CLKDET LOUT", NULL, "CLKDET"}, + +	{"IN1P", NULL, "LDO2"}, +	{"IN2P", NULL, "LDO2"}, +	{"IN3P", NULL, "LDO2"}, +	{"IN4P", NULL, "LDO2"}, + +	{"DMIC1", NULL, "DMIC L1"}, +	{"DMIC1", NULL, "DMIC R1"}, +	{"DMIC2", NULL, "DMIC L2"}, +	{"DMIC2", NULL, "DMIC R2"}, + +	{"BST1", NULL, "IN1P"}, +	{"BST1", NULL, "IN1N"}, +	{"BST1", NULL, "BST1 Power"}, +	{"BST1", NULL, "BST1P Power"}, +	{"BST2", NULL, "IN2P"}, +	{"BST2", NULL, "IN2N"}, +	{"BST2", NULL, "BST2 Power"}, +	{"BST2", NULL, "BST2P Power"}, +	{"BST3", NULL, "IN3P"}, +	{"BST3", NULL, "IN3N"}, +	{"BST3", NULL, "BST3 Power"}, +	{"BST3", NULL, "BST3P Power"}, +	{"BST4", NULL, "IN4P"}, +	{"BST4", NULL, "IN4N"}, +	{"BST4", NULL, "BST4 Power"}, +	{"BST4", NULL, "BST4P Power"}, +	{"BST1 CBJ", NULL, "IN1P"}, +	{"BST1 CBJ", NULL, "IN1N"}, +	{"BST1 CBJ", NULL, "CBJ Power"}, +	{"CBJ Power", NULL, "Vref2"}, + +	{"INL VOL", NULL, "IN3P"}, +	{"INR VOL", NULL, "IN3N"}, + +	{"RECMIX1L", "CBJ Switch", "BST1 CBJ"}, +	{"RECMIX1L", "INL Switch", "INL VOL"}, +	{"RECMIX1L", "INR Switch", "INR VOL"}, +	{"RECMIX1L", "BST4 Switch", "BST4"}, +	{"RECMIX1L", "BST3 Switch", "BST3"}, +	{"RECMIX1L", "BST2 Switch", "BST2"}, +	{"RECMIX1L", "BST1 Switch", "BST1"}, +	{"RECMIX1L", NULL, "RECMIX1L Power"}, + +	{"RECMIX1R", "MONOVOL Switch", "MONOVOL"}, +	{"RECMIX1R", "INR Switch", "INR VOL"}, +	{"RECMIX1R", "BST4 Switch", "BST4"}, +	{"RECMIX1R", "BST3 Switch", "BST3"}, +	{"RECMIX1R", "BST2 Switch", "BST2"}, +	{"RECMIX1R", "BST1 Switch", "BST1"}, +	{"RECMIX1R", NULL, "RECMIX1R Power"}, + +	{"RECMIX2L", "CBJ Switch", "BST1 CBJ"}, +	{"RECMIX2L", "INL Switch", "INL VOL"}, +	{"RECMIX2L", "INR Switch", "INR VOL"}, +	{"RECMIX2L", "BST4 Switch", "BST4"}, +	{"RECMIX2L", "BST3 Switch", "BST3"}, +	{"RECMIX2L", "BST2 Switch", "BST2"}, +	{"RECMIX2L", "BST1 Switch", "BST1"}, +	{"RECMIX2L", NULL, "RECMIX2L Power"}, + +	{"RECMIX2R", "MONOVOL Switch", "MONOVOL"}, +	{"RECMIX2R", "INL Switch", "INL VOL"}, +	{"RECMIX2R", "INR Switch", "INR VOL"}, +	{"RECMIX2R", "BST4 Switch", "BST4"}, +	{"RECMIX2R", "BST3 Switch", "BST3"}, +	{"RECMIX2R", "BST2 Switch", "BST2"}, +	{"RECMIX2R", "BST1 Switch", "BST1"}, +	{"RECMIX2R", NULL, "RECMIX2R Power"}, + +	{"ADC1 L", NULL, "RECMIX1L"}, +	{"ADC1 L", NULL, "ADC1 L Power"}, +	{"ADC1 L", NULL, "ADC1 clock"}, +	{"ADC1 R", NULL, "RECMIX1R"}, +	{"ADC1 R", NULL, "ADC1 R Power"}, +	{"ADC1 R", NULL, "ADC1 clock"}, + +	{"ADC2 L", NULL, "RECMIX2L"}, +	{"ADC2 L", NULL, "ADC2 L Power"}, +	{"ADC2 L", NULL, "ADC2 clock"}, +	{"ADC2 R", NULL, "RECMIX2R"}, +	{"ADC2 R", NULL, "ADC2 R Power"}, +	{"ADC2 R", NULL, "ADC2 clock"}, + +	{"DMIC L1", NULL, "DMIC CLK"}, +	{"DMIC L1", NULL, "DMIC1 Power"}, +	{"DMIC R1", NULL, "DMIC CLK"}, +	{"DMIC R1", NULL, "DMIC1 Power"}, +	{"DMIC L2", NULL, "DMIC CLK"}, +	{"DMIC L2", NULL, "DMIC2 Power"}, +	{"DMIC R2", NULL, "DMIC CLK"}, +	{"DMIC R2", NULL, "DMIC2 Power"}, + +	{"Stereo1 DMIC L Mux", "DMIC1", "DMIC L1"}, +	{"Stereo1 DMIC L Mux", "DMIC2", "DMIC L2"}, + +	{"Stereo1 DMIC R Mux", "DMIC1", "DMIC R1"}, +	{"Stereo1 DMIC R Mux", "DMIC2", "DMIC R2"}, + +	{"Mono DMIC L Mux", "DMIC1 L", "DMIC L1"}, +	{"Mono DMIC L Mux", "DMIC2 L", "DMIC L2"}, + +	{"Mono DMIC R Mux", "DMIC1 R", "DMIC R1"}, +	{"Mono DMIC R Mux", "DMIC2 R", "DMIC R2"}, + +	{"Stereo2 DMIC L Mux", "DMIC1", "DMIC L1"}, +	{"Stereo2 DMIC L Mux", "DMIC2", "DMIC L2"}, + +	{"Stereo2 DMIC R Mux", "DMIC1", "DMIC R1"}, +	{"Stereo2 DMIC R Mux", "DMIC2", "DMIC R2"}, + +	{"Stereo1 ADC L Mux", "ADC1 L", "ADC1 L"}, +	{"Stereo1 ADC L Mux", "ADC1 R", "ADC1 R"}, +	{"Stereo1 ADC L Mux", "ADC2 L", "ADC2 L"}, +	{"Stereo1 ADC L Mux", "ADC2 R", "ADC2 R"}, +	{"Stereo1 ADC R Mux", "ADC1 L", "ADC1 L"}, +	{"Stereo1 ADC R Mux", "ADC1 R", "ADC1 R"}, +	{"Stereo1 ADC R Mux", "ADC2 L", "ADC2 L"}, +	{"Stereo1 ADC R Mux", "ADC2 R", "ADC2 R"}, + +	{"Stereo1 DD L Mux", "STO2 DAC", "Stereo2 DAC MIXL"}, +	{"Stereo1 DD L Mux", "MONO DAC", "Mono DAC MIXL"}, + +	{"Stereo1 DD R Mux", "STO2 DAC", "Stereo2 DAC MIXR"}, +	{"Stereo1 DD R Mux", "MONO DAC", "Mono DAC MIXR"}, + +	{"Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux"}, +	{"Stereo1 ADC L1 Mux", "DD Mux", "Stereo1 DD L Mux"}, +	{"Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC L Mux"}, +	{"Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL"}, + +	{"Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux"}, +	{"Stereo1 ADC R1 Mux", "DD Mux", "Stereo1 DD R Mux"}, +	{"Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC R Mux"}, +	{"Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR"}, + +	{"Mono ADC L Mux", "ADC1 L", "ADC1 L"}, +	{"Mono ADC L Mux", "ADC1 R", "ADC1 R"}, +	{"Mono ADC L Mux", "ADC2 L", "ADC2 L"}, +	{"Mono ADC L Mux", "ADC2 R", "ADC2 R"}, + +	{"Mono ADC R Mux", "ADC1 L", "ADC1 L"}, +	{"Mono ADC R Mux", "ADC1 R", "ADC1 R"}, +	{"Mono ADC R Mux", "ADC2 L", "ADC2 L"}, +	{"Mono ADC R Mux", "ADC2 R", "ADC2 R"}, + +	{"Mono DD L Mux", "STO2 DAC", "Stereo2 DAC MIXL"}, +	{"Mono DD L Mux", "MONO DAC", "Mono DAC MIXL"}, + +	{"Mono DD R Mux", "STO2 DAC", "Stereo2 DAC MIXR"}, +	{"Mono DD R Mux", "MONO DAC", "Mono DAC MIXR"}, + +	{"Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux"}, +	{"Mono ADC L2 Mux", "DAC MIXL", "DAC MIXL"}, +	{"Mono ADC L1 Mux", "DD Mux", "Mono DD L Mux"}, +	{"Mono ADC L1 Mux", "ADC",  "Mono ADC L Mux"}, + +	{"Mono ADC R1 Mux", "DD Mux", "Mono DD R Mux"}, +	{"Mono ADC R1 Mux", "ADC", "Mono ADC R Mux"}, +	{"Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux"}, +	{"Mono ADC R2 Mux", "DAC MIXR", "DAC MIXR"}, + +	{"Stereo2 ADC L Mux", "ADC1 L", "ADC1 L"}, +	{"Stereo2 ADC L Mux", "ADC2 L", "ADC2 L"}, +	{"Stereo2 ADC L Mux", "ADC1 R", "ADC1 R"}, +	{"Stereo2 ADC R Mux", "ADC1 L", "ADC1 L"}, +	{"Stereo2 ADC R Mux", "ADC2 L", "ADC2 L"}, +	{"Stereo2 ADC R Mux", "ADC1 R", "ADC1 R"}, + +	{"Stereo2 DD L Mux", "STO2 DAC", "Stereo2 DAC MIXL"}, +	{"Stereo2 DD L Mux", "MONO DAC", "Mono DAC MIXL"}, + +	{"Stereo2 DD R Mux", "STO2 DAC", "Stereo2 DAC MIXR"}, +	{"Stereo2 DD R Mux", "MONO DAC", "Mono DAC MIXR"}, + +	{"Stereo2 ADC L1 Mux", "ADC", "Stereo2 ADC L Mux"}, +	{"Stereo2 ADC L1 Mux", "DD Mux", "Stereo2 DD L Mux"}, +	{"Stereo2 ADC L2 Mux", "DMIC", "Stereo2 DMIC L Mux"}, +	{"Stereo2 ADC L2 Mux", "DAC MIX", "DAC MIXL"}, + +	{"Stereo2 ADC R1 Mux", "ADC", "Stereo2 ADC R Mux"}, +	{"Stereo2 ADC R1 Mux", "DD Mux", "Stereo2 DD R Mux"}, +	{"Stereo2 ADC R2 Mux", "DMIC", "Stereo2 DMIC R Mux"}, +	{"Stereo2 ADC R2 Mux", "DAC MIX", "DAC MIXR"}, + +	{"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"}, +	{"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"}, +	{"Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter"}, + +	{"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"}, +	{"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"}, +	{"Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter"}, + +	{"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"}, +	{"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"}, +	{"Mono ADC MIXL", NULL, "ADC Mono Left Filter"}, + +	{"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"}, +	{"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"}, +	{"Mono ADC MIXR", NULL, "ADC Mono Right Filter"}, + +	{"Stereo2 ADC MIXL", "ADC1 Switch", "Stereo2 ADC L1 Mux"}, +	{"Stereo2 ADC MIXL", "ADC2 Switch", "Stereo2 ADC L2 Mux"}, +	{"Stereo2 ADC MIXL", NULL, "ADC Stereo2 Filter"}, + +	{"Stereo2 ADC MIXR", "ADC1 Switch", "Stereo2 ADC R1 Mux"}, +	{"Stereo2 ADC MIXR", "ADC2 Switch", "Stereo2 ADC R2 Mux"}, +	{"Stereo2 ADC MIXR", NULL, "ADC Stereo2 Filter"}, + +	{"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL"}, +	{"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR"}, +	{"Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXL"}, +	{"Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXR"}, +	{"Mono ADC MIX", NULL, "Mono ADC MIXL"}, +	{"Mono ADC MIX", NULL, "Mono ADC MIXR"}, + +	{"IF1_1_ADC1 Mux", "STO1 ADC", "Stereo1 ADC MIX"}, +	{"IF1_1_ADC1 Mux", "IF2_1 DAC", "IF2_1 DAC"}, +	{"IF1_1_ADC2 Mux", "STO2 ADC", "Stereo2 ADC MIX"}, +	{"IF1_1_ADC2 Mux", "IF2_2 DAC", "IF2_2 DAC"}, +	{"IF1_1_ADC3 Mux", "MONO ADC", "Mono ADC MIX"}, +	{"IF1_1_ADC3 Mux", "IF3 DAC", "IF3 DAC"}, +	{"IF1_1_ADC4", NULL, "DAC1 MIX"}, + +	{"IF1_2_ADC1 Mux", "STO1 ADC", "Stereo1 ADC MIX"}, +	{"IF1_2_ADC1 Mux", "IF1 DAC", "IF1 DAC1"}, +	{"IF1_2_ADC2 Mux", "STO2 ADC", "Stereo2 ADC MIX"}, +	{"IF1_2_ADC2 Mux", "IF2_1 DAC", "IF2_1 DAC"}, +	{"IF1_2_ADC3 Mux", "MONO ADC", "Mono ADC MIX"}, +	{"IF1_2_ADC3 Mux", "IF2_2 DAC", "IF2_2 DAC"}, +	{"IF1_2_ADC4 Mux", "DAC1", "DAC1 MIX"}, +	{"IF1_2_ADC4 Mux", "IF3 DAC", "IF3 DAC"}, + +	{"TDM1 slot 01 Data Mux", "1234", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 01 Data Mux", "1243", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 01 Data Mux", "1324", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 01 Data Mux", "1342", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 01 Data Mux", "1432", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 01 Data Mux", "1423", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 01 Data Mux", "2134", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 01 Data Mux", "2143", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 01 Data Mux", "2314", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 01 Data Mux", "2341", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 01 Data Mux", "2431", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 01 Data Mux", "2413", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 01 Data Mux", "3124", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 01 Data Mux", "3142", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 01 Data Mux", "3214", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 01 Data Mux", "3241", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 01 Data Mux", "3412", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 01 Data Mux", "3421", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 01 Data Mux", "4123", "IF1_1_ADC4"}, +	{"TDM1 slot 01 Data Mux", "4132", "IF1_1_ADC4"}, +	{"TDM1 slot 01 Data Mux", "4213", "IF1_1_ADC4"}, +	{"TDM1 slot 01 Data Mux", "4231", "IF1_1_ADC4"}, +	{"TDM1 slot 01 Data Mux", "4312", "IF1_1_ADC4"}, +	{"TDM1 slot 01 Data Mux", "4321", "IF1_1_ADC4"}, +	{"TDM1 slot 01 Data Mux", NULL, "I2S1_1"}, + +	{"TDM1 slot 23 Data Mux", "1234", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 23 Data Mux", "1243", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 23 Data Mux", "1324", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 23 Data Mux", "1342", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 23 Data Mux", "1432", "IF1_1_ADC4"}, +	{"TDM1 slot 23 Data Mux", "1423", "IF1_1_ADC4"}, +	{"TDM1 slot 23 Data Mux", "2134", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 23 Data Mux", "2143", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 23 Data Mux", "2314", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 23 Data Mux", "2341", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 23 Data Mux", "2431", "IF1_1_ADC4"}, +	{"TDM1 slot 23 Data Mux", "2413", "IF1_1_ADC4"}, +	{"TDM1 slot 23 Data Mux", "3124", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 23 Data Mux", "3142", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 23 Data Mux", "3214", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 23 Data Mux", "3241", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 23 Data Mux", "3412", "IF1_1_ADC4"}, +	{"TDM1 slot 23 Data Mux", "3421", "IF1_1_ADC4"}, +	{"TDM1 slot 23 Data Mux", "4123", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 23 Data Mux", "4132", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 23 Data Mux", "4213", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 23 Data Mux", "4231", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 23 Data Mux", "4312", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 23 Data Mux", "4321", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 23 Data Mux", NULL, "I2S1_1"}, + +	{"TDM1 slot 45 Data Mux", "1234", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 45 Data Mux", "1243", "IF1_1_ADC4"}, +	{"TDM1 slot 45 Data Mux", "1324", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 45 Data Mux", "1342", "IF1_1_ADC4"}, +	{"TDM1 slot 45 Data Mux", "1432", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 45 Data Mux", "1423", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 45 Data Mux", "2134", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 45 Data Mux", "2143", "IF1_1_ADC4"}, +	{"TDM1 slot 45 Data Mux", "2314", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 45 Data Mux", "2341", "IF1_1_ADC4"}, +	{"TDM1 slot 45 Data Mux", "2431", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 45 Data Mux", "2413", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 45 Data Mux", "3124", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 45 Data Mux", "3142", "IF1_1_ADC4"}, +	{"TDM1 slot 45 Data Mux", "3214", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 45 Data Mux", "3241", "IF1_1_ADC4"}, +	{"TDM1 slot 45 Data Mux", "3412", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 45 Data Mux", "3421", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 45 Data Mux", "4123", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 45 Data Mux", "4132", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 45 Data Mux", "4213", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 45 Data Mux", "4231", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 45 Data Mux", "4312", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 45 Data Mux", "4321", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 45 Data Mux", NULL, "I2S1_1"}, + +	{"TDM1 slot 67 Data Mux", "1234", "IF1_1_ADC4"}, +	{"TDM1 slot 67 Data Mux", "1243", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 67 Data Mux", "1324", "IF1_1_ADC4"}, +	{"TDM1 slot 67 Data Mux", "1342", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 67 Data Mux", "1432", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 67 Data Mux", "1423", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 67 Data Mux", "2134", "IF1_1_ADC4"}, +	{"TDM1 slot 67 Data Mux", "2143", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 67 Data Mux", "2314", "IF1_1_ADC4"}, +	{"TDM1 slot 67 Data Mux", "2341", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 67 Data Mux", "2431", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 67 Data Mux", "2413", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 67 Data Mux", "3124", "IF1_1_ADC4"}, +	{"TDM1 slot 67 Data Mux", "3142", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 67 Data Mux", "3214", "IF1_1_ADC4"}, +	{"TDM1 slot 67 Data Mux", "3241", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 67 Data Mux", "3412", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 67 Data Mux", "3421", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 67 Data Mux", "4123", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 67 Data Mux", "4132", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 67 Data Mux", "4213", "IF1_1_ADC3 Mux"}, +	{"TDM1 slot 67 Data Mux", "4231", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 67 Data Mux", "4312", "IF1_1_ADC2 Mux"}, +	{"TDM1 slot 67 Data Mux", "4321", "IF1_1_ADC1 Mux"}, +	{"TDM1 slot 67 Data Mux", NULL, "I2S1_1"}, + + +	{"TDM2 slot 01 Data Mux", "1234", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 01 Data Mux", "1243", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 01 Data Mux", "1324", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 01 Data Mux", "1342", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 01 Data Mux", "1432", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 01 Data Mux", "1423", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 01 Data Mux", "2134", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 01 Data Mux", "2143", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 01 Data Mux", "2314", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 01 Data Mux", "2341", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 01 Data Mux", "2431", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 01 Data Mux", "2413", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 01 Data Mux", "3124", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 01 Data Mux", "3142", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 01 Data Mux", "3214", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 01 Data Mux", "3241", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 01 Data Mux", "3412", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 01 Data Mux", "3421", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 01 Data Mux", "4123", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 01 Data Mux", "4132", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 01 Data Mux", "4213", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 01 Data Mux", "4231", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 01 Data Mux", "4312", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 01 Data Mux", "4321", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 01 Data Mux", NULL, "I2S1_2"}, + +	{"TDM2 slot 23 Data Mux", "1234", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 23 Data Mux", "1243", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 23 Data Mux", "1324", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 23 Data Mux", "1342", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 23 Data Mux", "1432", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 23 Data Mux", "1423", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 23 Data Mux", "2134", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 23 Data Mux", "2143", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 23 Data Mux", "2314", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 23 Data Mux", "2341", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 23 Data Mux", "2431", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 23 Data Mux", "2413", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 23 Data Mux", "3124", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 23 Data Mux", "3142", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 23 Data Mux", "3214", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 23 Data Mux", "3241", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 23 Data Mux", "3412", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 23 Data Mux", "3421", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 23 Data Mux", "4123", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 23 Data Mux", "4132", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 23 Data Mux", "4213", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 23 Data Mux", "4231", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 23 Data Mux", "4312", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 23 Data Mux", "4321", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 23 Data Mux", NULL, "I2S1_2"}, + +	{"TDM2 slot 45 Data Mux", "1234", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 45 Data Mux", "1243", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 45 Data Mux", "1324", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 45 Data Mux", "1342", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 45 Data Mux", "1432", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 45 Data Mux", "1423", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 45 Data Mux", "2134", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 45 Data Mux", "2143", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 45 Data Mux", "2314", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 45 Data Mux", "2341", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 45 Data Mux", "2431", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 45 Data Mux", "2413", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 45 Data Mux", "3124", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 45 Data Mux", "3142", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 45 Data Mux", "3214", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 45 Data Mux", "3241", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 45 Data Mux", "3412", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 45 Data Mux", "3421", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 45 Data Mux", "4123", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 45 Data Mux", "4132", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 45 Data Mux", "4213", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 45 Data Mux", "4231", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 45 Data Mux", "4312", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 45 Data Mux", "4321", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 45 Data Mux", NULL, "I2S1_2"}, + +	{"TDM2 slot 67 Data Mux", "1234", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 67 Data Mux", "1243", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 67 Data Mux", "1324", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 67 Data Mux", "1342", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 67 Data Mux", "1432", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 67 Data Mux", "1423", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 67 Data Mux", "2134", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 67 Data Mux", "2143", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 67 Data Mux", "2314", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 67 Data Mux", "2341", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 67 Data Mux", "2431", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 67 Data Mux", "2413", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 67 Data Mux", "3124", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 67 Data Mux", "3142", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 67 Data Mux", "3214", "IF1_2_ADC4 Mux"}, +	{"TDM2 slot 67 Data Mux", "3241", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 67 Data Mux", "3412", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 67 Data Mux", "3421", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 67 Data Mux", "4123", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 67 Data Mux", "4132", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 67 Data Mux", "4213", "IF1_2_ADC3 Mux"}, +	{"TDM2 slot 67 Data Mux", "4231", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 67 Data Mux", "4312", "IF1_2_ADC2 Mux"}, +	{"TDM2 slot 67 Data Mux", "4321", "IF1_2_ADC1 Mux"}, +	{"TDM2 slot 67 Data Mux", NULL, "I2S1_2"}, + +	{"IF1_1 0 ADC Swap Mux", "L/R", "TDM1 slot 01 Data Mux"}, +	{"IF1_1 0 ADC Swap Mux", "L/L", "TDM1 slot 01 Data Mux"}, +	{"IF1_1 1 ADC Swap Mux", "R/L", "TDM1 slot 01 Data Mux"}, +	{"IF1_1 1 ADC Swap Mux", "R/R", "TDM1 slot 01 Data Mux"}, +	{"IF1_1 2 ADC Swap Mux", "L/R", "TDM1 slot 23 Data Mux"}, +	{"IF1_1 2 ADC Swap Mux", "R/L", "TDM1 slot 23 Data Mux"}, +	{"IF1_1 3 ADC Swap Mux", "L/L", "TDM1 slot 23 Data Mux"}, +	{"IF1_1 3 ADC Swap Mux", "R/R", "TDM1 slot 23 Data Mux"}, +	{"IF1_1 4 ADC Swap Mux", "L/R", "TDM1 slot 45 Data Mux"}, +	{"IF1_1 4 ADC Swap Mux", "R/L", "TDM1 slot 45 Data Mux"}, +	{"IF1_1 5 ADC Swap Mux", "L/L", "TDM1 slot 45 Data Mux"}, +	{"IF1_1 5 ADC Swap Mux", "R/R", "TDM1 slot 45 Data Mux"}, +	{"IF1_1 6 ADC Swap Mux", "L/R", "TDM1 slot 67 Data Mux"}, +	{"IF1_1 6 ADC Swap Mux", "R/L", "TDM1 slot 67 Data Mux"}, +	{"IF1_1 7 ADC Swap Mux", "L/L", "TDM1 slot 67 Data Mux"}, +	{"IF1_1 7 ADC Swap Mux", "R/R", "TDM1 slot 67 Data Mux"}, +	{"IF1_2 0 ADC Swap Mux", "L/R", "TDM2 slot 01 Data Mux"}, +	{"IF1_2 0 ADC Swap Mux", "R/L", "TDM2 slot 01 Data Mux"}, +	{"IF1_2 1 ADC Swap Mux", "L/L", "TDM2 slot 01 Data Mux"}, +	{"IF1_2 1 ADC Swap Mux", "R/R", "TDM2 slot 01 Data Mux"}, +	{"IF1_2 2 ADC Swap Mux", "L/R", "TDM2 slot 23 Data Mux"}, +	{"IF1_2 2 ADC Swap Mux", "R/L", "TDM2 slot 23 Data Mux"}, +	{"IF1_2 3 ADC Swap Mux", "L/L", "TDM2 slot 23 Data Mux"}, +	{"IF1_2 3 ADC Swap Mux", "R/R", "TDM2 slot 23 Data Mux"}, +	{"IF1_2 4 ADC Swap Mux", "L/R", "TDM2 slot 45 Data Mux"}, +	{"IF1_2 4 ADC Swap Mux", "R/L", "TDM2 slot 45 Data Mux"}, +	{"IF1_2 5 ADC Swap Mux", "L/L", "TDM2 slot 45 Data Mux"}, +	{"IF1_2 5 ADC Swap Mux", "R/R", "TDM2 slot 45 Data Mux"}, +	{"IF1_2 6 ADC Swap Mux", "L/R", "TDM2 slot 67 Data Mux"}, +	{"IF1_2 6 ADC Swap Mux", "R/L", "TDM2 slot 67 Data Mux"}, +	{"IF1_2 7 ADC Swap Mux", "L/L", "TDM2 slot 67 Data Mux"}, +	{"IF1_2 7 ADC Swap Mux", "R/R", "TDM2 slot 67 Data Mux"}, + +	{"IF2_1 ADC Mux", "STO1 ADC", "Stereo1 ADC MIX"}, +	{"IF2_1 ADC Mux", "STO2 ADC", "Stereo2 ADC MIX"}, +	{"IF2_1 ADC Mux", "MONO ADC", "Mono ADC MIX"}, +	{"IF2_1 ADC Mux", "IF1 DAC1", "IF1 DAC1"}, +	{"IF2_1 ADC Mux", "IF1 DAC2", "IF1 DAC2"}, +	{"IF2_1 ADC Mux", "IF2_2 DAC", "IF2_2 DAC"}, +	{"IF2_1 ADC Mux", "IF3 DAC", "IF3 DAC"}, +	{"IF2_1 ADC Mux", "DAC1 MIX", "DAC1 MIX"}, +	{"IF2_1 ADC", NULL, "IF2_1 ADC Mux"}, +	{"IF2_1 ADC", NULL, "I2S2_1"}, + +	{"IF2_2 ADC Mux", "STO1 ADC", "Stereo1 ADC MIX"}, +	{"IF2_2 ADC Mux", "STO2 ADC", "Stereo2 ADC MIX"}, +	{"IF2_2 ADC Mux", "MONO ADC", "Mono ADC MIX"}, +	{"IF2_2 ADC Mux", "IF1 DAC1", "IF1 DAC1"}, +	{"IF2_2 ADC Mux", "IF1 DAC2", "IF1 DAC2"}, +	{"IF2_2 ADC Mux", "IF2_1 DAC", "IF2_1 DAC"}, +	{"IF2_2 ADC Mux", "IF3 DAC", "IF3 DAC"}, +	{"IF2_2 ADC Mux", "DAC1 MIX", "DAC1 MIX"}, +	{"IF2_2 ADC", NULL, "IF2_2 ADC Mux"}, +	{"IF2_2 ADC", NULL, "I2S2_2"}, + +	{"IF3 ADC Mux", "STO1 ADC", "Stereo1 ADC MIX"}, +	{"IF3 ADC Mux", "STO2 ADC", "Stereo2 ADC MIX"}, +	{"IF3 ADC Mux", "MONO ADC", "Mono ADC MIX"}, +	{"IF3 ADC Mux", "IF1 DAC1", "IF1 DAC1"}, +	{"IF3 ADC Mux", "IF1 DAC2", "IF1 DAC2"}, +	{"IF3 ADC Mux", "IF2_1 DAC", "IF2_1 DAC"}, +	{"IF3 ADC Mux", "IF2_2 DAC", "IF2_2 DAC"}, +	{"IF3 ADC Mux", "DAC1 MIX", "DAC1 MIX"}, +	{"IF3 ADC", NULL, "IF3 ADC Mux"}, +	{"IF3 ADC", NULL, "I2S3"}, + +	{"AIF1_1TX slot 0", NULL, "IF1_1 0 ADC Swap Mux"}, +	{"AIF1_1TX slot 1", NULL, "IF1_1 1 ADC Swap Mux"}, +	{"AIF1_1TX slot 2", NULL, "IF1_1 2 ADC Swap Mux"}, +	{"AIF1_1TX slot 3", NULL, "IF1_1 3 ADC Swap Mux"}, +	{"AIF1_1TX slot 4", NULL, "IF1_1 4 ADC Swap Mux"}, +	{"AIF1_1TX slot 5", NULL, "IF1_1 5 ADC Swap Mux"}, +	{"AIF1_1TX slot 6", NULL, "IF1_1 6 ADC Swap Mux"}, +	{"AIF1_1TX slot 7", NULL, "IF1_1 7 ADC Swap Mux"}, +	{"AIF1_2TX slot 0", NULL, "IF1_2 0 ADC Swap Mux"}, +	{"AIF1_2TX slot 1", NULL, "IF1_2 1 ADC Swap Mux"}, +	{"AIF1_2TX slot 2", NULL, "IF1_2 2 ADC Swap Mux"}, +	{"AIF1_2TX slot 3", NULL, "IF1_2 3 ADC Swap Mux"}, +	{"AIF1_2TX slot 4", NULL, "IF1_2 4 ADC Swap Mux"}, +	{"AIF1_2TX slot 5", NULL, "IF1_2 5 ADC Swap Mux"}, +	{"AIF1_2TX slot 6", NULL, "IF1_2 6 ADC Swap Mux"}, +	{"AIF1_2TX slot 7", NULL, "IF1_2 7 ADC Swap Mux"}, +	{"IF2_1 ADC Swap Mux", "L/R", "IF2_1 ADC"}, +	{"IF2_1 ADC Swap Mux", "R/L", "IF2_1 ADC"}, +	{"IF2_1 ADC Swap Mux", "L/L", "IF2_1 ADC"}, +	{"IF2_1 ADC Swap Mux", "R/R", "IF2_1 ADC"}, +	{"AIF2_1TX", NULL, "IF2_1 ADC Swap Mux"}, +	{"IF2_2 ADC Swap Mux", "L/R", "IF2_2 ADC"}, +	{"IF2_2 ADC Swap Mux", "R/L", "IF2_2 ADC"}, +	{"IF2_2 ADC Swap Mux", "L/L", "IF2_2 ADC"}, +	{"IF2_2 ADC Swap Mux", "R/R", "IF2_2 ADC"}, +	{"AIF2_2TX", NULL, "IF2_2 ADC Swap Mux"}, +	{"IF3 ADC Swap Mux", "L/R", "IF3 ADC"}, +	{"IF3 ADC Swap Mux", "R/L", "IF3 ADC"}, +	{"IF3 ADC Swap Mux", "L/L", "IF3 ADC"}, +	{"IF3 ADC Swap Mux", "R/R", "IF3 ADC"}, +	{"AIF3TX", NULL, "IF3 ADC Swap Mux"}, + +	{"IF1 DAC1", NULL, "AIF1RX"}, +	{"IF1 DAC2", NULL, "AIF1RX"}, +	{"IF1 DAC3", NULL, "AIF1RX"}, +	{"IF2_1 DAC Swap Mux", "L/R", "AIF2_1RX"}, +	{"IF2_1 DAC Swap Mux", "R/L", "AIF2_1RX"}, +	{"IF2_1 DAC Swap Mux", "L/L", "AIF2_1RX"}, +	{"IF2_1 DAC Swap Mux", "R/R", "AIF2_1RX"}, +	{"IF2_2 DAC Swap Mux", "L/R", "AIF2_2RX"}, +	{"IF2_2 DAC Swap Mux", "R/L", "AIF2_2RX"}, +	{"IF2_2 DAC Swap Mux", "L/L", "AIF2_2RX"}, +	{"IF2_2 DAC Swap Mux", "R/R", "AIF2_2RX"}, +	{"IF2_1 DAC", NULL, "IF2_1 DAC Swap Mux"}, +	{"IF2_2 DAC", NULL, "IF2_2 DAC Swap Mux"}, +	{"IF3 DAC Swap Mux", "L/R", "AIF3RX"}, +	{"IF3 DAC Swap Mux", "R/L", "AIF3RX"}, +	{"IF3 DAC Swap Mux", "L/L", "AIF3RX"}, +	{"IF3 DAC Swap Mux", "R/R", "AIF3RX"}, +	{"IF3 DAC", NULL, "IF3 DAC Swap Mux"}, + +	{"IF1 DAC1", NULL, "I2S1_1"}, +	{"IF1 DAC2", NULL, "I2S1_1"}, +	{"IF1 DAC3", NULL, "I2S1_1"}, +	{"IF2_1 DAC", NULL, "I2S2_1"}, +	{"IF2_2 DAC", NULL, "I2S2_2"}, +	{"IF3 DAC", NULL, "I2S3"}, + +	{"IF1 DAC1 L", NULL, "IF1 DAC1"}, +	{"IF1 DAC1 R", NULL, "IF1 DAC1"}, +	{"IF1 DAC2 L", NULL, "IF1 DAC2"}, +	{"IF1 DAC2 R", NULL, "IF1 DAC2"}, +	{"IF1 DAC3 L", NULL, "IF1 DAC3"}, +	{"IF1 DAC3 R", NULL, "IF1 DAC3"}, +	{"IF2_1 DAC L", NULL, "IF2_1 DAC"}, +	{"IF2_1 DAC R", NULL, "IF2_1 DAC"}, +	{"IF2_2 DAC L", NULL, "IF2_2 DAC"}, +	{"IF2_2 DAC R", NULL, "IF2_2 DAC"}, +	{"IF3 DAC L", NULL, "IF3 DAC"}, +	{"IF3 DAC R", NULL, "IF3 DAC"}, + +	{"DAC L1 Mux", "IF1 DAC1", "IF1 DAC1 L"}, +	{"DAC L1 Mux", "IF2_1 DAC", "IF2_1 DAC L"}, +	{"DAC L1 Mux", "IF2_2 DAC", "IF2_2 DAC L"}, +	{"DAC L1 Mux", "IF3 DAC", "IF3 DAC L"}, +	{"DAC L1 Mux", NULL, "DAC Stereo1 Filter"}, + +	{"DAC R1 Mux", "IF1 DAC1", "IF1 DAC1 R"}, +	{"DAC R1 Mux", "IF2_1 DAC", "IF2_1 DAC R"}, +	{"DAC R1 Mux", "IF2_2 DAC", "IF2_2 DAC R"}, +	{"DAC R1 Mux", "IF3 DAC", "IF3 DAC R"}, +	{"DAC R1 Mux", NULL, "DAC Stereo1 Filter"}, + +	{"DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"}, +	{"DAC1 MIXL", "DAC1 Switch", "DAC L1 Mux"}, +	{"DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"}, +	{"DAC1 MIXR", "DAC1 Switch", "DAC R1 Mux"}, + +	{"DAC1 MIX", NULL, "DAC1 MIXL"}, +	{"DAC1 MIX", NULL, "DAC1 MIXR"}, + +	{"DAC L2 Mux", "IF1 DAC2", "IF1 DAC2 L"}, +	{"DAC L2 Mux", "IF2_1 DAC", "IF2_1 DAC L"}, +	{"DAC L2 Mux", "IF2_2 DAC", "IF2_2 DAC L"}, +	{"DAC L2 Mux", "IF3 DAC", "IF3 DAC L"}, +	{"DAC L2 Mux", "Mono ADC MIX", "Mono ADC MIXL"}, +	{"DAC L2 Mux", NULL, "DAC Mono Left Filter"}, + +	{"DAC R2 Mux", "IF1 DAC2", "IF1 DAC2 R"}, +	{"DAC R2 Mux", "IF2_1 DAC", "IF2_1 DAC R"}, +	{"DAC R2 Mux", "IF2_2 DAC", "IF2_2 DAC R"}, +	{"DAC R2 Mux", "IF3 DAC", "IF3 DAC R"}, +	{"DAC R2 Mux", "Mono ADC MIX", "Mono ADC MIXR"}, +	{"DAC R2 Mux", NULL, "DAC Mono Right Filter"}, + +	{"DAC L3 Mux", "IF1 DAC2", "IF1 DAC2 L"}, +	{"DAC L3 Mux", "IF2_1 DAC", "IF2_1 DAC L"}, +	{"DAC L3 Mux", "IF2_2 DAC", "IF2_2 DAC L"}, +	{"DAC L3 Mux", "IF3 DAC", "IF3 DAC L"}, +	{"DAC L3 Mux", "STO2 ADC MIX", "Stereo2 ADC MIXL"}, +	{"DAC L3 Mux", NULL, "DAC Stereo2 Filter"}, + +	{"DAC R3 Mux", "IF1 DAC2", "IF1 DAC2 R"}, +	{"DAC R3 Mux", "IF2_1 DAC", "IF2_1 DAC R"}, +	{"DAC R3 Mux", "IF2_2 DAC", "IF2_2 DAC R"}, +	{"DAC R3 Mux", "IF3 DAC", "IF3 DAC R"}, +	{"DAC R3 Mux", "STO2 ADC MIX", "Stereo2 ADC MIXR"}, +	{"DAC R3 Mux", NULL, "DAC Stereo2 Filter"}, + +	{"Stereo1 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"}, +	{"Stereo1 DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"}, +	{"Stereo1 DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, +	{"Stereo1 DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"}, + +	{"Stereo1 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"}, +	{"Stereo1 DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"}, +	{"Stereo1 DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"}, +	{"Stereo1 DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, + +	{"Stereo2 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"}, +	{"Stereo2 DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, +	{"Stereo2 DAC MIXL", "DAC L3 Switch", "DAC L3 Mux"}, + +	{"Stereo2 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"}, +	{"Stereo2 DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, +	{"Stereo2 DAC MIXR", "DAC R3 Switch", "DAC R3 Mux"}, + +	{"Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"}, +	{"Mono DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"}, +	{"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, +	{"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"}, +	{"Mono DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"}, +	{"Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"}, +	{"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"}, +	{"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, + +	{"DAC MIXL", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"}, +	{"DAC MIXL", "Stereo2 DAC Mixer", "Stereo2 DAC MIXL"}, +	{"DAC MIXL", "Mono DAC Mixer", "Mono DAC MIXL"}, +	{"DAC MIXR", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"}, +	{"DAC MIXR", "Stereo2 DAC Mixer", "Stereo2 DAC MIXR"}, +	{"DAC MIXR", "Mono DAC Mixer", "Mono DAC MIXR"}, + +	{"DAC L1 Source", "DAC1", "DAC1 MIXL"}, +	{"DAC L1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"}, +	{"DAC L1 Source", "DMIC1", "DMIC L1"}, +	{"DAC R1 Source", "DAC1", "DAC1 MIXR"}, +	{"DAC R1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"}, +	{"DAC R1 Source", "DMIC1", "DMIC R1"}, + +	{"DAC L2 Source", "DAC2", "DAC L2 Mux"}, +	{"DAC L2 Source", "Mono DAC Mixer", "Mono DAC MIXL"}, +	{"DAC L2 Source", NULL, "DAC L2 Power"}, +	{"DAC R2 Source", "DAC2", "DAC R2 Mux"}, +	{"DAC R2 Source", "Mono DAC Mixer", "Mono DAC MIXR"}, +	{"DAC R2 Source", NULL, "DAC R2 Power"}, + +	{"DAC L1", NULL, "DAC L1 Source"}, +	{"DAC R1", NULL, "DAC R1 Source"}, +	{"DAC L2", NULL, "DAC L2 Source"}, +	{"DAC R2", NULL, "DAC R2 Source"}, + +	{"DAC L1", NULL, "DAC 1 Clock"}, +	{"DAC R1", NULL, "DAC 1 Clock"}, +	{"DAC L2", NULL, "DAC 2 Clock"}, +	{"DAC R2", NULL, "DAC 2 Clock"}, + +	{"MONOVOL MIX", "DAC L2 Switch", "DAC L2"}, +	{"MONOVOL MIX", "RECMIX2L Switch", "RECMIX2L"}, +	{"MONOVOL MIX", "BST1 Switch", "BST1"}, +	{"MONOVOL MIX", "BST2 Switch", "BST2"}, +	{"MONOVOL MIX", "BST3 Switch", "BST3"}, + +	{"OUT MIXL", "DAC L2 Switch", "DAC L2"}, +	{"OUT MIXL", "INL Switch", "INL VOL"}, +	{"OUT MIXL", "BST1 Switch", "BST1"}, +	{"OUT MIXL", "BST2 Switch", "BST2"}, +	{"OUT MIXL", "BST3 Switch", "BST3"}, +	{"OUT MIXR", "DAC R2 Switch", "DAC R2"}, +	{"OUT MIXR", "INR Switch", "INR VOL"}, +	{"OUT MIXR", "BST2 Switch", "BST2"}, +	{"OUT MIXR", "BST3 Switch", "BST3"}, +	{"OUT MIXR", "BST4 Switch", "BST4"}, + +	{"MONOVOL", "Switch", "MONOVOL MIX"}, +	{"Mono MIX", "DAC L2 Switch", "DAC L2"}, +	{"Mono MIX", "MONOVOL Switch", "MONOVOL"}, +	{"Mono Amp", NULL, "Mono MIX"}, +	{"Mono Amp", NULL, "Vref2"}, +	{"Mono Amp", NULL, "CLKDET SYS"}, +	{"Mono Amp", NULL, "CLKDET MONO"}, +	{"Mono Playback", "Switch", "Mono Amp"}, +	{"MONOOUT", NULL, "Mono Playback"}, + +	{"HP Amp", NULL, "DAC L1"}, +	{"HP Amp", NULL, "DAC R1"}, +	{"HP Amp", NULL, "Charge Pump"}, +	{"HP Amp", NULL, "CLKDET SYS"}, +	{"HP Amp", NULL, "CLKDET HP"}, +	{"HP Amp", NULL, "CBJ Power"}, +	{"HP Amp", NULL, "Vref2"}, +	{"HPO Playback", "Switch", "HP Amp"}, +	{"HPOL", NULL, "HPO Playback"}, +	{"HPOR", NULL, "HPO Playback"}, + +	{"OUTVOL L", "Switch", "OUT MIXL"}, +	{"OUTVOL R", "Switch", "OUT MIXR"}, +	{"LOUT L MIX", "DAC L2 Switch", "DAC L2"}, +	{"LOUT L MIX", "OUTVOL L Switch", "OUTVOL L"}, +	{"LOUT R MIX", "DAC R2 Switch", "DAC R2"}, +	{"LOUT R MIX", "OUTVOL R Switch", "OUTVOL R"}, +	{"LOUT Amp", NULL, "LOUT L MIX"}, +	{"LOUT Amp", NULL, "LOUT R MIX"}, +	{"LOUT Amp", NULL, "Vref1"}, +	{"LOUT Amp", NULL, "Vref2"}, +	{"LOUT Amp", NULL, "CLKDET SYS"}, +	{"LOUT Amp", NULL, "CLKDET LOUT"}, +	{"LOUT L Playback", "Switch", "LOUT Amp"}, +	{"LOUT R Playback", "Switch", "LOUT Amp"}, +	{"LOUTL", NULL, "LOUT L Playback"}, +	{"LOUTR", NULL, "LOUT R Playback"}, + +	{"PDM L Mux", "Mono DAC", "Mono DAC MIXL"}, +	{"PDM L Mux", "Stereo1 DAC", "Stereo1 DAC MIXL"}, +	{"PDM L Mux", "Stereo2 DAC", "Stereo2 DAC MIXL"}, +	{"PDM L Mux", NULL, "PDM Power"}, +	{"PDM R Mux", "Mono DAC", "Mono DAC MIXR"}, +	{"PDM R Mux", "Stereo1 DAC", "Stereo1 DAC MIXR"}, +	{"PDM R Mux", "Stereo2 DAC", "Stereo2 DAC MIXR"}, +	{"PDM R Mux", NULL, "PDM Power"}, +	{"PDM L Playback", "Switch", "PDM L Mux"}, +	{"PDM R Playback", "Switch", "PDM R Mux"}, +	{"PDML", NULL, "PDM L Playback"}, +	{"PDMR", NULL, "PDM R Playback"}, +}; + +static int rt5665_hw_params(struct snd_pcm_substream *substream, +	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); +	unsigned int val_len = 0, val_clk, mask_clk, val_bits = 0x0100; +	int pre_div, frame_size; + +	rt5665->lrck[dai->id] = params_rate(params); +	pre_div = rl6231_get_clk_info(rt5665->sysclk, rt5665->lrck[dai->id]); +	if (pre_div < 0) { +		dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n", +			rt5665->lrck[dai->id], dai->id); +		return -EINVAL; +	} +	frame_size = snd_soc_params_to_frame_size(params); +	if (frame_size < 0) { +		dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size); +		return -EINVAL; +	} + +	dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n", +				rt5665->lrck[dai->id], pre_div, dai->id); + +	switch (params_width(params)) { +	case 16: +		val_bits = 0x0100; +		break; +	case 20: +		val_len |= RT5665_I2S_DL_20; +		val_bits = 0x1300; +		break; +	case 24: +		val_len |= RT5665_I2S_DL_24; +		val_bits = 0x2500; +		break; +	case 8: +		val_len |= RT5665_I2S_DL_8; +		break; +	default: +		return -EINVAL; +	} + +	switch (dai->id) { +	case RT5665_AIF1_1: +	case RT5665_AIF1_2: +		mask_clk = RT5665_I2S_PD1_MASK; +		val_clk = pre_div << RT5665_I2S_PD1_SFT; +		snd_soc_update_bits(codec, RT5665_I2S1_SDP, +			RT5665_I2S_DL_MASK, val_len); +		break; +	case RT5665_AIF2_1: +	case RT5665_AIF2_2: +		mask_clk = RT5665_I2S_PD2_MASK; +		val_clk = pre_div << RT5665_I2S_PD2_SFT; +		snd_soc_update_bits(codec, RT5665_I2S2_SDP, +			RT5665_I2S_DL_MASK, val_len); +		break; +	case RT5665_AIF3: +		mask_clk = RT5665_I2S_PD3_MASK; +		val_clk = pre_div << RT5665_I2S_PD3_SFT; +		snd_soc_update_bits(codec, RT5665_I2S3_SDP, +			RT5665_I2S_DL_MASK, val_len); +		break; +	default: +		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); +		return -EINVAL; +	} + +	snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, mask_clk, val_clk); +	snd_soc_update_bits(codec, RT5665_STO1_DAC_SIL_DET, 0x3700, val_bits); + +	switch (rt5665->lrck[dai->id]) { +	case 192000: +		snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, +			RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK, +			RT5665_DAC_OSR_32 | RT5665_ADC_OSR_32); +		break; +	case 96000: +		snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, +			RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK, +			RT5665_DAC_OSR_64 | RT5665_ADC_OSR_64); +		break; +	default: +		snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, +			RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK, +			RT5665_DAC_OSR_128 | RT5665_ADC_OSR_128); +		break; +	} + +	return 0; +} + +static int rt5665_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); +	unsigned int reg_val = 0; + +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBM_CFM: +		rt5665->master[dai->id] = 1; +		break; +	case SND_SOC_DAIFMT_CBS_CFS: +		reg_val |= RT5665_I2S_MS_S; +		rt5665->master[dai->id] = 0; +		break; +	default: +		return -EINVAL; +	} + +	switch (fmt & SND_SOC_DAIFMT_INV_MASK) { +	case SND_SOC_DAIFMT_NB_NF: +		break; +	case SND_SOC_DAIFMT_IB_NF: +		reg_val |= RT5665_I2S_BP_INV; +		break; +	default: +		return -EINVAL; +	} + +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { +	case SND_SOC_DAIFMT_I2S: +		break; +	case SND_SOC_DAIFMT_LEFT_J: +		reg_val |= RT5665_I2S_DF_LEFT; +		break; +	case SND_SOC_DAIFMT_DSP_A: +		reg_val |= RT5665_I2S_DF_PCM_A; +		break; +	case SND_SOC_DAIFMT_DSP_B: +		reg_val |= RT5665_I2S_DF_PCM_B; +		break; +	default: +		return -EINVAL; +	} + +	switch (dai->id) { +	case RT5665_AIF1_1: +	case RT5665_AIF1_2: +		snd_soc_update_bits(codec, RT5665_I2S1_SDP, +			RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK | +			RT5665_I2S_DF_MASK, reg_val); +		break; +	case RT5665_AIF2_1: +	case RT5665_AIF2_2: +		snd_soc_update_bits(codec, RT5665_I2S2_SDP, +			RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK | +			RT5665_I2S_DF_MASK, reg_val); +		break; +	case RT5665_AIF3: +		snd_soc_update_bits(codec, RT5665_I2S3_SDP, +			RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK | +			RT5665_I2S_DF_MASK, reg_val); +		break; +	default: +		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); +		return -EINVAL; +	} +	return 0; +} + +static int rt5665_set_dai_sysclk(struct snd_soc_dai *dai, +		int clk_id, unsigned int freq, int dir) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); +	unsigned int reg_val = 0; + +	if (freq == rt5665->sysclk && clk_id == rt5665->sysclk_src) +		return 0; + +	switch (clk_id) { +	case RT5665_SCLK_S_MCLK: +		reg_val |= RT5665_SCLK_SRC_MCLK; +		break; +	case RT5665_SCLK_S_PLL1: +		reg_val |= RT5665_SCLK_SRC_PLL1; +		break; +	case RT5665_SCLK_S_RCCLK: +		reg_val |= RT5665_SCLK_SRC_RCCLK; +		break; +	default: +		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); +		return -EINVAL; +	} +	snd_soc_update_bits(codec, RT5665_GLB_CLK, +		RT5665_SCLK_SRC_MASK, reg_val); +	rt5665->sysclk = freq; +	rt5665->sysclk_src = clk_id; + +	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + +	return 0; +} + +static int rt5665_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source, +			unsigned int freq_in, unsigned int freq_out) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); +	struct rl6231_pll_code pll_code; +	int ret; + +	if (Source == rt5665->pll_src && freq_in == rt5665->pll_in && +	    freq_out == rt5665->pll_out) +		return 0; + +	if (!freq_in || !freq_out) { +		dev_dbg(codec->dev, "PLL disabled\n"); + +		rt5665->pll_in = 0; +		rt5665->pll_out = 0; +		snd_soc_update_bits(codec, RT5665_GLB_CLK, +			RT5665_SCLK_SRC_MASK, RT5665_SCLK_SRC_MCLK); +		return 0; +	} + +	switch (Source) { +	case RT5665_PLL1_S_MCLK: +		snd_soc_update_bits(codec, RT5665_GLB_CLK, +			RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_MCLK); +		break; +	case RT5665_PLL1_S_BCLK1: +		snd_soc_update_bits(codec, RT5665_GLB_CLK, +				RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK1); +		break; +	case RT5665_PLL1_S_BCLK2: +		snd_soc_update_bits(codec, RT5665_GLB_CLK, +				RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK2); +		break; +	case RT5665_PLL1_S_BCLK3: +		snd_soc_update_bits(codec, RT5665_GLB_CLK, +				RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK3); +		break; +	default: +		dev_err(codec->dev, "Unknown PLL Source %d\n", Source); +		return -EINVAL; +	} + +	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); +	if (ret < 0) { +		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); +		return ret; +	} + +	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", +		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), +		pll_code.n_code, pll_code.k_code); + +	snd_soc_write(codec, RT5665_PLL_CTRL_1, +		pll_code.n_code << RT5665_PLL_N_SFT | pll_code.k_code); +	snd_soc_write(codec, RT5665_PLL_CTRL_2, +		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5665_PLL_M_SFT | +		pll_code.m_bp << RT5665_PLL_M_BP_SFT); + +	rt5665->pll_in = freq_in; +	rt5665->pll_out = freq_out; +	rt5665->pll_src = Source; + +	return 0; +} + +static int rt5665_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, +			unsigned int rx_mask, int slots, int slot_width) +{ +	struct snd_soc_codec *codec = dai->codec; +	unsigned int val = 0; + +	if (rx_mask || tx_mask) +		val |= RT5665_I2S1_MODE_TDM; + +	switch (slots) { +	case 4: +		val |= RT5665_TDM_IN_CH_4; +		val |= RT5665_TDM_OUT_CH_4; +		break; +	case 6: +		val |= RT5665_TDM_IN_CH_6; +		val |= RT5665_TDM_OUT_CH_6; +		break; +	case 8: +		val |= RT5665_TDM_IN_CH_8; +		val |= RT5665_TDM_OUT_CH_8; +		break; +	case 2: +		break; +	default: +		return -EINVAL; +	} + +	switch (slot_width) { +	case 20: +		val |= RT5665_TDM_IN_LEN_20; +		val |= RT5665_TDM_OUT_LEN_20; +		break; +	case 24: +		val |= RT5665_TDM_IN_LEN_24; +		val |= RT5665_TDM_OUT_LEN_24; +		break; +	case 32: +		val |= RT5665_TDM_IN_LEN_32; +		val |= RT5665_TDM_OUT_LEN_32; +		break; +	case 16: +		break; +	default: +		return -EINVAL; +	} + +	snd_soc_update_bits(codec, RT5665_TDM_CTRL_1, +		RT5665_I2S1_MODE_MASK | RT5665_TDM_IN_CH_MASK | +		RT5665_TDM_OUT_CH_MASK | RT5665_TDM_IN_LEN_MASK | +		RT5665_TDM_OUT_LEN_MASK, val); + +	return 0; +} + +static int rt5665_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + +	dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio); + +	rt5665->bclk[dai->id] = ratio; + +	if (ratio == 64) { +		switch (dai->id) { +		case RT5665_AIF2_1: +		case RT5665_AIF2_2: +			snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, +				RT5665_I2S_BCLK_MS2_MASK, +				RT5665_I2S_BCLK_MS2_64); +			break; +		case RT5665_AIF3: +			snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, +				RT5665_I2S_BCLK_MS3_MASK, +				RT5665_I2S_BCLK_MS3_64); +			break; +		} +	} + +	return 0; +} + +static int rt5665_set_bias_level(struct snd_soc_codec *codec, +			enum snd_soc_bias_level level) +{ +	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + +	switch (level) { +	case SND_SOC_BIAS_PREPARE: +		regmap_update_bits(rt5665->regmap, RT5665_DIG_MISC, +			RT5665_DIG_GATE_CTRL, RT5665_DIG_GATE_CTRL); +		break; + +	case SND_SOC_BIAS_STANDBY: +		regmap_update_bits(rt5665->regmap, RT5665_PWR_DIG_1, +			RT5665_PWR_LDO,	RT5665_PWR_LDO); +		regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_1, +			RT5665_PWR_MB, RT5665_PWR_MB); +		regmap_update_bits(rt5665->regmap, RT5665_DIG_MISC, +			RT5665_DIG_GATE_CTRL, 0); +		break; +	case SND_SOC_BIAS_OFF: +		regmap_update_bits(rt5665->regmap, RT5665_PWR_DIG_1, +			RT5665_PWR_LDO, 0); +		regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_1, +			RT5665_PWR_MB, 0); +		break; + +	default: +		break; +	} + +	return 0; +} + +static int rt5665_probe(struct snd_soc_codec *codec) +{ +	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + +	rt5665->codec = codec; + +	schedule_delayed_work(&rt5665->calibrate_work, msecs_to_jiffies(100)); + +	return 0; +} + +static int rt5665_remove(struct snd_soc_codec *codec) +{ +	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + +	regmap_write(rt5665->regmap, RT5665_RESET, 0); + +	return 0; +} + +#ifdef CONFIG_PM +static int rt5665_suspend(struct snd_soc_codec *codec) +{ +	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + +	regcache_cache_only(rt5665->regmap, true); +	regcache_mark_dirty(rt5665->regmap); +	return 0; +} + +static int rt5665_resume(struct snd_soc_codec *codec) +{ +	struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + +	regcache_cache_only(rt5665->regmap, false); +	regcache_sync(rt5665->regmap); + +	return 0; +} +#else +#define rt5665_suspend NULL +#define rt5665_resume NULL +#endif + +#define RT5665_STEREO_RATES SNDRV_PCM_RATE_8000_192000 +#define RT5665_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ +		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static const struct snd_soc_dai_ops rt5665_aif_dai_ops = { +	.hw_params = rt5665_hw_params, +	.set_fmt = rt5665_set_dai_fmt, +	.set_sysclk = rt5665_set_dai_sysclk, +	.set_tdm_slot = rt5665_set_tdm_slot, +	.set_pll = rt5665_set_dai_pll, +	.set_bclk_ratio = rt5665_set_bclk_ratio, +}; + +static struct snd_soc_dai_driver rt5665_dai[] = { +	{ +		.name = "rt5665-aif1_1", +		.id = RT5665_AIF1_1, +		.playback = { +			.stream_name = "AIF1 Playback", +			.channels_min = 1, +			.channels_max = 8, +			.rates = RT5665_STEREO_RATES, +			.formats = RT5665_FORMATS, +		}, +		.capture = { +			.stream_name = "AIF1_1 Capture", +			.channels_min = 1, +			.channels_max = 8, +			.rates = RT5665_STEREO_RATES, +			.formats = RT5665_FORMATS, +		}, +		.ops = &rt5665_aif_dai_ops, +	}, +	{ +		.name = "rt5665-aif1_2", +		.id = RT5665_AIF1_2, +		.capture = { +			.stream_name = "AIF1_2 Capture", +			.channels_min = 1, +			.channels_max = 8, +			.rates = RT5665_STEREO_RATES, +			.formats = RT5665_FORMATS, +		}, +		.ops = &rt5665_aif_dai_ops, +	}, +	{ +		.name = "rt5665-aif2_1", +		.id = RT5665_AIF2_1, +		.playback = { +			.stream_name = "AIF2_1 Playback", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5665_STEREO_RATES, +			.formats = RT5665_FORMATS, +		}, +		.capture = { +			.stream_name = "AIF2_1 Capture", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5665_STEREO_RATES, +			.formats = RT5665_FORMATS, +		}, +		.ops = &rt5665_aif_dai_ops, +	}, +	{ +		.name = "rt5665-aif2_2", +		.id = RT5665_AIF2_2, +		.playback = { +			.stream_name = "AIF2_2 Playback", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5665_STEREO_RATES, +			.formats = RT5665_FORMATS, +		}, +		.capture = { +			.stream_name = "AIF2_2 Capture", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5665_STEREO_RATES, +			.formats = RT5665_FORMATS, +		}, +		.ops = &rt5665_aif_dai_ops, +	}, +	{ +		.name = "rt5665-aif3", +		.id = RT5665_AIF3, +		.playback = { +			.stream_name = "AIF3 Playback", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5665_STEREO_RATES, +			.formats = RT5665_FORMATS, +		}, +		.capture = { +			.stream_name = "AIF3 Capture", +			.channels_min = 1, +			.channels_max = 2, +			.rates = RT5665_STEREO_RATES, +			.formats = RT5665_FORMATS, +		}, +		.ops = &rt5665_aif_dai_ops, +	}, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5665 = { +	.probe = rt5665_probe, +	.remove = rt5665_remove, +	.suspend = rt5665_suspend, +	.resume = rt5665_resume, +	.set_bias_level = rt5665_set_bias_level, +	.idle_bias_off = true, +	.component_driver = { +		.controls = rt5665_snd_controls, +		.num_controls = ARRAY_SIZE(rt5665_snd_controls), +		.dapm_widgets = rt5665_dapm_widgets, +		.num_dapm_widgets = ARRAY_SIZE(rt5665_dapm_widgets), +		.dapm_routes = rt5665_dapm_routes, +		.num_dapm_routes = ARRAY_SIZE(rt5665_dapm_routes), +	} +}; + + +static const struct regmap_config rt5665_regmap = { +	.reg_bits = 16, +	.val_bits = 16, +	.max_register = 0x0400, +	.volatile_reg = rt5665_volatile_register, +	.readable_reg = rt5665_readable_register, +	.cache_type = REGCACHE_RBTREE, +	.reg_defaults = rt5665_reg, +	.num_reg_defaults = ARRAY_SIZE(rt5665_reg), +	.use_single_rw = true, +}; + +static const struct i2c_device_id rt5665_i2c_id[] = { +	{"rt5665", 0}, +	{} +}; +MODULE_DEVICE_TABLE(i2c, rt5665_i2c_id); + +static int rt5665_parse_dt(struct rt5665_priv *rt5665, struct device *dev) +{ +	rt5665->pdata.in1_diff = of_property_read_bool(dev->of_node, +					"realtek,in1-differential"); +	rt5665->pdata.in2_diff = of_property_read_bool(dev->of_node, +					"realtek,in2-differential"); +	rt5665->pdata.in3_diff = of_property_read_bool(dev->of_node, +					"realtek,in3-differential"); +	rt5665->pdata.in4_diff = of_property_read_bool(dev->of_node, +					"realtek,in4-differential"); + +	of_property_read_u32(dev->of_node, "realtek,dmic1-data-pin", +		&rt5665->pdata.dmic1_data_pin); +	of_property_read_u32(dev->of_node, "realtek,dmic2-data-pin", +		&rt5665->pdata.dmic2_data_pin); +	of_property_read_u32(dev->of_node, "realtek,jd-src", +		&rt5665->pdata.jd_src); + +	rt5665->pdata.ldo1_en = of_get_named_gpio(dev->of_node, +		"realtek,ldo1-en-gpios", 0); + +	return 0; +} + +static void rt5665_calibrate(struct rt5665_priv *rt5665) +{ +	int value, count; + +	mutex_lock(&rt5665->calibrate_mutex); + +	regcache_cache_bypass(rt5665->regmap, true); + +	regmap_write(rt5665->regmap, RT5665_RESET, 0); +	regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602); +	regmap_write(rt5665->regmap, RT5665_HP_CHARGE_PUMP_1, 0x0c26); +	regmap_write(rt5665->regmap, RT5665_MONOMIX_IN_GAIN, 0x021f); +	regmap_write(rt5665->regmap, RT5665_MONO_OUT, 0x480a); +	regmap_write(rt5665->regmap, RT5665_PWR_MIXER, 0x083f); +	regmap_write(rt5665->regmap, RT5665_PWR_DIG_1, 0x0180); +	regmap_write(rt5665->regmap, RT5665_EJD_CTRL_1, 0x4040); +	regmap_write(rt5665->regmap, RT5665_HP_LOGIC_CTRL_2, 0x0000); +	regmap_write(rt5665->regmap, RT5665_DIG_MISC, 0x0001); +	regmap_write(rt5665->regmap, RT5665_MICBIAS_2, 0x0380); +	regmap_write(rt5665->regmap, RT5665_GLB_CLK, 0x8000); +	regmap_write(rt5665->regmap, RT5665_ADDA_CLK_1, 0x1000); +	regmap_write(rt5665->regmap, RT5665_CHOP_DAC, 0x3030); +	regmap_write(rt5665->regmap, RT5665_CALIB_ADC_CTRL, 0x3c05); +	regmap_write(rt5665->regmap, RT5665_PWR_ANLG_1, 0xaa3e); +	usleep_range(15000, 20000); +	regmap_write(rt5665->regmap, RT5665_PWR_ANLG_1, 0xfe7e); +	regmap_write(rt5665->regmap, RT5665_HP_CALIB_CTRL_2, 0x0321); + +	regmap_write(rt5665->regmap, RT5665_HP_CALIB_CTRL_1, 0xfc00); +	count = 0; +	while (true) { +		regmap_read(rt5665->regmap, RT5665_HP_CALIB_STA_1, &value); +		if (value & 0x8000) +			usleep_range(10000, 10005); +		else +			break; + +		if (count > 60) { +			pr_err("HP Calibration Failure\n"); +			regmap_write(rt5665->regmap, RT5665_RESET, 0); +			regcache_cache_bypass(rt5665->regmap, false); +			goto out_unlock; +		} + +		count++; +	} + +	regmap_write(rt5665->regmap, RT5665_MONO_AMP_CALIB_CTRL_1, 0x9e24); +	count = 0; +	while (true) { +		regmap_read(rt5665->regmap, RT5665_MONO_AMP_CALIB_STA1, &value); +		if (value & 0x8000) +			usleep_range(10000, 10005); +		else +			break; + +		if (count > 60) { +			pr_err("MONO Calibration Failure\n"); +			regmap_write(rt5665->regmap, RT5665_RESET, 0); +			regcache_cache_bypass(rt5665->regmap, false); +			goto out_unlock; +		} + +		count++; +	} + +	regmap_write(rt5665->regmap, RT5665_RESET, 0); +	regcache_cache_bypass(rt5665->regmap, false); + +	regcache_mark_dirty(rt5665->regmap); +	regcache_sync(rt5665->regmap); + +	regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602); +	regmap_write(rt5665->regmap, RT5665_ASRC_8, 0x0120); + +out_unlock: +	mutex_unlock(&rt5665->calibrate_mutex); +} + +static void rt5665_calibrate_handler(struct work_struct *work) +{ +	struct rt5665_priv *rt5665 = container_of(work, struct rt5665_priv, +		calibrate_work.work); + +	while (!rt5665->codec->component.card->instantiated) { +		pr_debug("%s\n", __func__); +		usleep_range(10000, 15000); +	} + +	rt5665_calibrate(rt5665); +} + +static int rt5665_i2c_probe(struct i2c_client *i2c, +		    const struct i2c_device_id *id) +{ +	struct rt5665_platform_data *pdata = dev_get_platdata(&i2c->dev); +	struct rt5665_priv *rt5665; +	int i, ret; +	unsigned int val; + +	rt5665 = devm_kzalloc(&i2c->dev, sizeof(struct rt5665_priv), +		GFP_KERNEL); + +	if (rt5665 == NULL) +		return -ENOMEM; + +	i2c_set_clientdata(i2c, rt5665); + +	if (pdata) +		rt5665->pdata = *pdata; +	else +		rt5665_parse_dt(rt5665, &i2c->dev); + +	for (i = 0; i < ARRAY_SIZE(rt5665->supplies); i++) +		rt5665->supplies[i].supply = rt5665_supply_names[i]; + +	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(rt5665->supplies), +				      rt5665->supplies); +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); +		return ret; +	} + +	ret = regulator_bulk_enable(ARRAY_SIZE(rt5665->supplies), +				    rt5665->supplies); +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); +		return ret; +	} + +	if (gpio_is_valid(rt5665->pdata.ldo1_en)) { +		if (devm_gpio_request_one(&i2c->dev, rt5665->pdata.ldo1_en, +					  GPIOF_OUT_INIT_HIGH, "rt5665")) +			dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); +	} + +	/* Sleep for 300 ms miniumum */ +	usleep_range(300000, 350000); + +	rt5665->regmap = devm_regmap_init_i2c(i2c, &rt5665_regmap); +	if (IS_ERR(rt5665->regmap)) { +		ret = PTR_ERR(rt5665->regmap); +		dev_err(&i2c->dev, "Failed to allocate register map: %d\n", +			ret); +		return ret; +	} + +	regmap_read(rt5665->regmap, RT5665_DEVICE_ID, &val); +	if (val != DEVICE_ID) { +		dev_err(&i2c->dev, +			"Device with ID register %x is not rt5665\n", val); +		return -ENODEV; +	} + +	regmap_read(rt5665->regmap, RT5665_RESET, &val); +	switch (val) { +	case 0x0: +		rt5665->id = CODEC_5666; +		break; +	case 0x6: +		rt5665->id = CODEC_5668; +		break; +	case 0x3: +	default: +		rt5665->id = CODEC_5665; +		break; +	} + +	regmap_write(rt5665->regmap, RT5665_RESET, 0); + +	/* line in diff mode*/ +	if (rt5665->pdata.in1_diff) +		regmap_update_bits(rt5665->regmap, RT5665_IN1_IN2, +			RT5665_IN1_DF_MASK, RT5665_IN1_DF_MASK); +	if (rt5665->pdata.in2_diff) +		regmap_update_bits(rt5665->regmap, RT5665_IN1_IN2, +			RT5665_IN2_DF_MASK, RT5665_IN2_DF_MASK); +	if (rt5665->pdata.in3_diff) +		regmap_update_bits(rt5665->regmap, RT5665_IN3_IN4, +			RT5665_IN3_DF_MASK, RT5665_IN3_DF_MASK); +	if (rt5665->pdata.in4_diff) +		regmap_update_bits(rt5665->regmap, RT5665_IN3_IN4, +			RT5665_IN4_DF_MASK, RT5665_IN4_DF_MASK); + +	/* DMIC pin*/ +	if (rt5665->pdata.dmic1_data_pin != RT5665_DMIC1_NULL || +		rt5665->pdata.dmic2_data_pin != RT5665_DMIC2_NULL) { +		regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_2, +			RT5665_GP9_PIN_MASK, RT5665_GP9_PIN_DMIC1_SCL); +		regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1, +				RT5665_GP8_PIN_MASK, RT5665_GP8_PIN_DMIC2_SCL); +		switch (rt5665->pdata.dmic1_data_pin) { +		case RT5665_DMIC1_DATA_IN2N: +			regmap_update_bits(rt5665->regmap, RT5665_DMIC_CTRL_1, +				RT5665_DMIC_1_DP_MASK, RT5665_DMIC_1_DP_IN2N); +			break; + +		case RT5665_DMIC1_DATA_GPIO4: +			regmap_update_bits(rt5665->regmap, RT5665_DMIC_CTRL_1, +				RT5665_DMIC_1_DP_MASK, RT5665_DMIC_1_DP_GPIO4); +			regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1, +				RT5665_GP4_PIN_MASK, RT5665_GP4_PIN_DMIC1_SDA); +			break; + +		default: +			dev_dbg(&i2c->dev, "no DMIC1\n"); +			break; +		} + +		switch (rt5665->pdata.dmic2_data_pin) { +		case RT5665_DMIC2_DATA_IN2P: +			regmap_update_bits(rt5665->regmap, RT5665_DMIC_CTRL_1, +				RT5665_DMIC_2_DP_MASK, RT5665_DMIC_2_DP_IN2P); +			break; + +		case RT5665_DMIC2_DATA_GPIO5: +			regmap_update_bits(rt5665->regmap, +				RT5665_DMIC_CTRL_1, +				RT5665_DMIC_2_DP_MASK, +				RT5665_DMIC_2_DP_GPIO5); +			regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1, +				RT5665_GP5_PIN_MASK, RT5665_GP5_PIN_DMIC2_SDA); +			break; + +		default: +			dev_dbg(&i2c->dev, "no DMIC2\n"); +			break; + +		} +	} + +	regmap_write(rt5665->regmap, RT5665_HP_LOGIC_CTRL_2, 0x0002); +	regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1, +		0xf000 | RT5665_VREF_POW_MASK, 0xd000 | RT5665_VREF_POW_REG); +	/* Work around for pow_pump */ +	regmap_update_bits(rt5665->regmap, RT5665_STO1_DAC_SIL_DET, +		RT5665_DEB_STO_DAC_MASK, RT5665_DEB_80_MS); + +	regmap_update_bits(rt5665->regmap, RT5665_HP_CHARGE_PUMP_1, +		RT5665_PM_HP_MASK, RT5665_PM_HP_HV); + +	/* Set GPIO4,8 as input for combo jack */ +	if (rt5665->id == CODEC_5666) { +		regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_2, +			RT5665_GP4_PF_MASK, RT5665_GP4_PF_IN); +		regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_3, +			RT5665_GP8_PF_MASK, RT5665_GP8_PF_IN); +	} + +	/* Enhance performance*/ +	regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_1, +		RT5665_HP_DRIVER_MASK | RT5665_LDO1_DVO_MASK, +		RT5665_HP_DRIVER_5X | RT5665_LDO1_DVO_09); + +	INIT_DELAYED_WORK(&rt5665->jack_detect_work, +				rt5665_jack_detect_handler); +	INIT_DELAYED_WORK(&rt5665->calibrate_work, +				rt5665_calibrate_handler); +	INIT_DELAYED_WORK(&rt5665->jd_check_work, +				rt5665_jd_check_handler); + +	mutex_init(&rt5665->calibrate_mutex); + +	if (i2c->irq) { +		ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, +			rt5665_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING +			| IRQF_ONESHOT, "rt5665", rt5665); +		if (ret) +			dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); + +	} + +	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5665, +			rt5665_dai, ARRAY_SIZE(rt5665_dai)); +} + +static int rt5665_i2c_remove(struct i2c_client *i2c) +{ +	snd_soc_unregister_codec(&i2c->dev); + +	return 0; +} + +static void rt5665_i2c_shutdown(struct i2c_client *client) +{ +	struct rt5665_priv *rt5665 = i2c_get_clientdata(client); + +	regmap_write(rt5665->regmap, RT5665_RESET, 0); +} + +#ifdef CONFIG_OF +static const struct of_device_id rt5665_of_match[] = { +	{.compatible = "realtek,rt5665"}, +	{.compatible = "realtek,rt5666"}, +	{.compatible = "realtek,rt5668"}, +	{}, +}; +MODULE_DEVICE_TABLE(of, rt5665_of_match); +#endif + +#ifdef CONFIG_ACPI +static struct acpi_device_id rt5665_acpi_match[] = { +	{"10EC5665", 0,}, +	{"10EC5666", 0,}, +	{"10EC5668", 0,}, +	{}, +}; +MODULE_DEVICE_TABLE(acpi, rt5665_acpi_match); +#endif + +struct i2c_driver rt5665_i2c_driver = { +	.driver = { +		.name = "rt5665", +		.of_match_table = of_match_ptr(rt5665_of_match), +		.acpi_match_table = ACPI_PTR(rt5665_acpi_match), +	}, +	.probe = rt5665_i2c_probe, +	.remove = rt5665_i2c_remove, +	.shutdown = rt5665_i2c_shutdown, +	.id_table = rt5665_i2c_id, +}; +module_i2c_driver(rt5665_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5665 driver"); +MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5665.h b/sound/soc/codecs/rt5665.h new file mode 100644 index 000000000000..12f7080a0d3c --- /dev/null +++ b/sound/soc/codecs/rt5665.h @@ -0,0 +1,1990 @@ +/* + * rt5665.h  --  RT5665/RT5658 ALSA SoC audio driver + * + * Copyright 2016 Realtek Microelectronics + * Author: Bard Liao <bardliao@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RT5665_H__ +#define __RT5665_H__ + +#include <sound/rt5665.h> + +#define DEVICE_ID 0x6451 + +/* Info */ +#define RT5665_RESET				0x0000 +#define RT5665_VENDOR_ID			0x00fd +#define RT5665_VENDOR_ID_1			0x00fe +#define RT5665_DEVICE_ID			0x00ff +/*  I/O - Output */ +#define RT5665_LOUT				0x0001 +#define RT5665_HP_CTRL_1			0x0002 +#define RT5665_HP_CTRL_2			0x0003 +#define RT5665_MONO_OUT				0x0004 +#define RT5665_HPL_GAIN				0x0005 +#define RT5665_HPR_GAIN				0x0006 +#define RT5665_MONO_GAIN			0x0007 + +/* I/O - Input */ +#define RT5665_CAL_BST_CTRL			0x000a +#define RT5665_CBJ_BST_CTRL			0x000b +#define RT5665_IN1_IN2				0x000c +#define RT5665_IN3_IN4				0x000d +#define RT5665_INL1_INR1_VOL			0x000f +/* I/O - Speaker */ +#define RT5665_EJD_CTRL_1			0x0010 +#define RT5665_EJD_CTRL_2			0x0011 +#define RT5665_EJD_CTRL_3			0x0012 +#define RT5665_EJD_CTRL_4			0x0013 +#define RT5665_EJD_CTRL_5			0x0014 +#define RT5665_EJD_CTRL_6			0x0015 +#define RT5665_EJD_CTRL_7			0x0016 +/* I/O - ADC/DAC/DMIC */ +#define RT5665_DAC2_CTRL			0x0017 +#define RT5665_DAC2_DIG_VOL			0x0018 +#define RT5665_DAC1_DIG_VOL			0x0019 +#define RT5665_DAC3_DIG_VOL			0x001a +#define RT5665_DAC3_CTRL			0x001b +#define RT5665_STO1_ADC_DIG_VOL			0x001c +#define RT5665_MONO_ADC_DIG_VOL			0x001d +#define RT5665_STO2_ADC_DIG_VOL			0x001e +#define RT5665_STO1_ADC_BOOST			0x001f +#define RT5665_MONO_ADC_BOOST			0x0020 +#define RT5665_STO2_ADC_BOOST			0x0021 +#define RT5665_HP_IMP_GAIN_1			0x0022 +#define RT5665_HP_IMP_GAIN_2			0x0023 +/* Mixer - D-D */ +#define RT5665_STO1_ADC_MIXER			0x0026 +#define RT5665_MONO_ADC_MIXER			0x0027 +#define RT5665_STO2_ADC_MIXER			0x0028 +#define RT5665_AD_DA_MIXER			0x0029 +#define RT5665_STO1_DAC_MIXER			0x002a +#define RT5665_MONO_DAC_MIXER			0x002b +#define RT5665_STO2_DAC_MIXER			0x002c +#define RT5665_A_DAC1_MUX			0x002d +#define RT5665_A_DAC2_MUX			0x002e +#define RT5665_DIG_INF2_DATA			0x002f +#define RT5665_DIG_INF3_DATA			0x0030 +/* Mixer - PDM */ +#define RT5665_PDM_OUT_CTRL			0x0031 +#define RT5665_PDM_DATA_CTRL_1			0x0032 +#define RT5665_PDM_DATA_CTRL_2			0x0033 +#define RT5665_PDM_DATA_CTRL_3			0x0034 +#define RT5665_PDM_DATA_CTRL_4			0x0035 +/* Mixer - ADC */ +#define RT5665_REC1_GAIN			0x003a +#define RT5665_REC1_L1_MIXER			0x003b +#define RT5665_REC1_L2_MIXER			0x003c +#define RT5665_REC1_R1_MIXER			0x003d +#define RT5665_REC1_R2_MIXER			0x003e +#define RT5665_REC2_GAIN			0x003f +#define RT5665_REC2_L1_MIXER			0x0040 +#define RT5665_REC2_L2_MIXER			0x0041 +#define RT5665_REC2_R1_MIXER			0x0042 +#define RT5665_REC2_R2_MIXER			0x0043 +#define RT5665_CAL_REC				0x0044 +/* Mixer - DAC */ +#define RT5665_ALC_BACK_GAIN			0x0049 +#define RT5665_MONOMIX_GAIN			0x004a +#define RT5665_MONOMIX_IN_GAIN			0x004b +#define RT5665_OUT_L_GAIN			0x004d +#define RT5665_OUT_L_MIXER			0x004e +#define RT5665_OUT_R_GAIN			0x004f +#define RT5665_OUT_R_MIXER			0x0050 +#define RT5665_LOUT_MIXER			0x0052 +/* Power */ +#define RT5665_PWR_DIG_1			0x0061 +#define RT5665_PWR_DIG_2			0x0062 +#define RT5665_PWR_ANLG_1			0x0063 +#define RT5665_PWR_ANLG_2			0x0064 +#define RT5665_PWR_ANLG_3			0x0065 +#define RT5665_PWR_MIXER			0x0066 +#define RT5665_PWR_VOL				0x0067 +/* Clock Detect */ +#define RT5665_CLK_DET				0x006b +/* Filter */ +#define RT5665_HPF_CTRL1			0x006d +/* DMIC */ +#define RT5665_DMIC_CTRL_1			0x006e +#define RT5665_DMIC_CTRL_2			0x006f +/* Format - ADC/DAC */ +#define RT5665_I2S1_SDP				0x0070 +#define RT5665_I2S2_SDP				0x0071 +#define RT5665_I2S3_SDP				0x0072 +#define RT5665_ADDA_CLK_1			0x0073 +#define RT5665_ADDA_CLK_2			0x0074 +#define RT5665_I2S1_F_DIV_CTRL_1		0x0075 +#define RT5665_I2S1_F_DIV_CTRL_2		0x0076 +/* Format - TDM Control */ +#define RT5665_TDM_CTRL_1			0x0078 +#define RT5665_TDM_CTRL_2			0x0079 +#define RT5665_TDM_CTRL_3			0x007a +#define RT5665_TDM_CTRL_4			0x007b +#define RT5665_TDM_CTRL_5			0x007c +#define RT5665_TDM_CTRL_6			0x007d +#define RT5665_TDM_CTRL_7			0x007e +#define RT5665_TDM_CTRL_8			0x007f +/* Function - Analog */ +#define RT5665_GLB_CLK				0x0080 +#define RT5665_PLL_CTRL_1			0x0081 +#define RT5665_PLL_CTRL_2			0x0082 +#define RT5665_ASRC_1				0x0083 +#define RT5665_ASRC_2				0x0084 +#define RT5665_ASRC_3				0x0085 +#define RT5665_ASRC_4				0x0086 +#define RT5665_ASRC_5				0x0087 +#define RT5665_ASRC_6				0x0088 +#define RT5665_ASRC_7				0x0089 +#define RT5665_ASRC_8				0x008a +#define RT5665_ASRC_9				0x008b +#define RT5665_ASRC_10				0x008c +#define RT5665_DEPOP_1				0x008e +#define RT5665_DEPOP_2				0x008f +#define RT5665_HP_CHARGE_PUMP_1			0x0091 +#define RT5665_HP_CHARGE_PUMP_2			0x0092 +#define RT5665_MICBIAS_1			0x0093 +#define RT5665_MICBIAS_2			0x0094 +#define RT5665_ASRC_12				0x0098 +#define RT5665_ASRC_13				0x0099 +#define RT5665_ASRC_14				0x009a +#define RT5665_RC_CLK_CTRL			0x009f +#define RT5665_I2S_M_CLK_CTRL_1			0x00a0 +#define RT5665_I2S2_F_DIV_CTRL_1		0x00a1 +#define RT5665_I2S2_F_DIV_CTRL_2		0x00a2 +#define RT5665_I2S3_F_DIV_CTRL_1		0x00a3 +#define RT5665_I2S3_F_DIV_CTRL_2		0x00a4 +/* Function - Digital */ +#define RT5665_EQ_CTRL_1			0x00ae +#define RT5665_EQ_CTRL_2			0x00af +#define RT5665_IRQ_CTRL_1			0x00b6 +#define RT5665_IRQ_CTRL_2			0x00b7 +#define RT5665_IRQ_CTRL_3			0x00b8 +#define RT5665_IRQ_CTRL_4			0x00b9 +#define RT5665_IRQ_CTRL_5			0x00ba +#define RT5665_IRQ_CTRL_6			0x00bb +#define RT5665_INT_ST_1				0x00be +#define RT5665_GPIO_CTRL_1			0x00c0 +#define RT5665_GPIO_CTRL_2			0x00c1 +#define RT5665_GPIO_CTRL_3			0x00c2 +#define RT5665_GPIO_CTRL_4			0x00c3 +#define RT5665_GPIO_STA				0x00c4 +#define RT5665_HP_AMP_DET_CTRL_1		0x00d0 +#define RT5665_HP_AMP_DET_CTRL_2		0x00d1 +#define RT5665_MID_HP_AMP_DET			0x00d3 +#define RT5665_LOW_HP_AMP_DET			0x00d4 +#define RT5665_SV_ZCD_1				0x00d9 +#define RT5665_SV_ZCD_2				0x00da +#define RT5665_IL_CMD_1				0x00db +#define RT5665_IL_CMD_2				0x00dc +#define RT5665_IL_CMD_3				0x00dd +#define RT5665_IL_CMD_4				0x00de +#define RT5665_4BTN_IL_CMD_1			0x00df +#define RT5665_4BTN_IL_CMD_2			0x00e0 +#define RT5665_4BTN_IL_CMD_3			0x00e1 +#define RT5665_PSV_IL_CMD_1			0x00e2 + +#define RT5665_ADC_STO1_HP_CTRL_1		0x00ea +#define RT5665_ADC_STO1_HP_CTRL_2		0x00eb +#define RT5665_ADC_MONO_HP_CTRL_1		0x00ec +#define RT5665_ADC_MONO_HP_CTRL_2		0x00ed +#define RT5665_ADC_STO2_HP_CTRL_1		0x00ee +#define RT5665_ADC_STO2_HP_CTRL_2		0x00ef +#define RT5665_AJD1_CTRL			0x00f0 +#define RT5665_JD1_THD				0x00f1 +#define RT5665_JD2_THD				0x00f2 +#define RT5665_JD_CTRL_1			0x00f6 +#define RT5665_JD_CTRL_2			0x00f7 +#define RT5665_JD_CTRL_3			0x00f8 +/* General Control */ +#define RT5665_DIG_MISC				0x00fa +#define RT5665_DUMMY_2				0x00fb +#define RT5665_DUMMY_3				0x00fc + +#define RT5665_DAC_ADC_DIG_VOL1			0x0100 +#define RT5665_DAC_ADC_DIG_VOL2			0x0101 +#define RT5665_BIAS_CUR_CTRL_1			0x010a +#define RT5665_BIAS_CUR_CTRL_2			0x010b +#define RT5665_BIAS_CUR_CTRL_3			0x010c +#define RT5665_BIAS_CUR_CTRL_4			0x010d +#define RT5665_BIAS_CUR_CTRL_5			0x010e +#define RT5665_BIAS_CUR_CTRL_6			0x010f +#define RT5665_BIAS_CUR_CTRL_7			0x0110 +#define RT5665_BIAS_CUR_CTRL_8			0x0111 +#define RT5665_BIAS_CUR_CTRL_9			0x0112 +#define RT5665_BIAS_CUR_CTRL_10			0x0113 +#define RT5665_VREF_REC_OP_FB_CAP_CTRL		0x0117 +#define RT5665_CHARGE_PUMP_1			0x0125 +#define RT5665_DIG_IN_CTRL_1			0x0132 +#define RT5665_DIG_IN_CTRL_2			0x0133 +#define RT5665_PAD_DRIVING_CTRL			0x0137 +#define RT5665_SOFT_RAMP_DEPOP			0x0138 +#define RT5665_PLL				0x0139 +#define RT5665_CHOP_DAC				0x013a +#define RT5665_CHOP_ADC				0x013b +#define RT5665_CALIB_ADC_CTRL			0x013c +#define RT5665_VOL_TEST				0x013f +#define RT5665_TEST_MODE_CTRL_1			0x0145 +#define RT5665_TEST_MODE_CTRL_2			0x0146 +#define RT5665_TEST_MODE_CTRL_3			0x0147 +#define RT5665_TEST_MODE_CTRL_4			0x0148 +#define RT5665_BASSBACK_CTRL			0x0150 +#define RT5665_STO_NG2_CTRL_1			0x0160 +#define RT5665_STO_NG2_CTRL_2			0x0161 +#define RT5665_STO_NG2_CTRL_3			0x0162 +#define RT5665_STO_NG2_CTRL_4			0x0163 +#define RT5665_STO_NG2_CTRL_5			0x0164 +#define RT5665_STO_NG2_CTRL_6			0x0165 +#define RT5665_STO_NG2_CTRL_7			0x0166 +#define RT5665_STO_NG2_CTRL_8			0x0167 +#define RT5665_MONO_NG2_CTRL_1			0x0170 +#define RT5665_MONO_NG2_CTRL_2			0x0171 +#define RT5665_MONO_NG2_CTRL_3			0x0172 +#define RT5665_MONO_NG2_CTRL_4			0x0173 +#define RT5665_MONO_NG2_CTRL_5			0x0174 +#define RT5665_MONO_NG2_CTRL_6			0x0175 +#define RT5665_STO1_DAC_SIL_DET			0x0190 +#define RT5665_MONOL_DAC_SIL_DET		0x0191 +#define RT5665_MONOR_DAC_SIL_DET		0x0192 +#define RT5665_STO2_DAC_SIL_DET			0x0193 +#define RT5665_SIL_PSV_CTRL1			0x0194 +#define RT5665_SIL_PSV_CTRL2			0x0195 +#define RT5665_SIL_PSV_CTRL3			0x0196 +#define RT5665_SIL_PSV_CTRL4			0x0197 +#define RT5665_SIL_PSV_CTRL5			0x0198 +#define RT5665_SIL_PSV_CTRL6			0x0199 +#define RT5665_MONO_AMP_CALIB_CTRL_1		0x01a0 +#define RT5665_MONO_AMP_CALIB_CTRL_2		0x01a1 +#define RT5665_MONO_AMP_CALIB_CTRL_3		0x01a2 +#define RT5665_MONO_AMP_CALIB_CTRL_4		0x01a3 +#define RT5665_MONO_AMP_CALIB_CTRL_5		0x01a4 +#define RT5665_MONO_AMP_CALIB_CTRL_6		0x01a5 +#define RT5665_MONO_AMP_CALIB_CTRL_7		0x01a6 +#define RT5665_MONO_AMP_CALIB_STA1		0x01a7 +#define RT5665_MONO_AMP_CALIB_STA2		0x01a8 +#define RT5665_MONO_AMP_CALIB_STA3		0x01a9 +#define RT5665_MONO_AMP_CALIB_STA4		0x01aa +#define RT5665_MONO_AMP_CALIB_STA6		0x01ab +#define RT5665_HP_IMP_SENS_CTRL_01		0x01b5 +#define RT5665_HP_IMP_SENS_CTRL_02		0x01b6 +#define RT5665_HP_IMP_SENS_CTRL_03		0x01b7 +#define RT5665_HP_IMP_SENS_CTRL_04		0x01b8 +#define RT5665_HP_IMP_SENS_CTRL_05		0x01b9 +#define RT5665_HP_IMP_SENS_CTRL_06		0x01ba +#define RT5665_HP_IMP_SENS_CTRL_07		0x01bb +#define RT5665_HP_IMP_SENS_CTRL_08		0x01bc +#define RT5665_HP_IMP_SENS_CTRL_09		0x01bd +#define RT5665_HP_IMP_SENS_CTRL_10		0x01be +#define RT5665_HP_IMP_SENS_CTRL_11		0x01bf +#define RT5665_HP_IMP_SENS_CTRL_12		0x01c0 +#define RT5665_HP_IMP_SENS_CTRL_13		0x01c1 +#define RT5665_HP_IMP_SENS_CTRL_14		0x01c2 +#define RT5665_HP_IMP_SENS_CTRL_15		0x01c3 +#define RT5665_HP_IMP_SENS_CTRL_16		0x01c4 +#define RT5665_HP_IMP_SENS_CTRL_17		0x01c5 +#define RT5665_HP_IMP_SENS_CTRL_18		0x01c6 +#define RT5665_HP_IMP_SENS_CTRL_19		0x01c7 +#define RT5665_HP_IMP_SENS_CTRL_20		0x01c8 +#define RT5665_HP_IMP_SENS_CTRL_21		0x01c9 +#define RT5665_HP_IMP_SENS_CTRL_22		0x01ca +#define RT5665_HP_IMP_SENS_CTRL_23		0x01cb +#define RT5665_HP_IMP_SENS_CTRL_24		0x01cc +#define RT5665_HP_IMP_SENS_CTRL_25		0x01cd +#define RT5665_HP_IMP_SENS_CTRL_26		0x01ce +#define RT5665_HP_IMP_SENS_CTRL_27		0x01cf +#define RT5665_HP_IMP_SENS_CTRL_28		0x01d0 +#define RT5665_HP_IMP_SENS_CTRL_29		0x01d1 +#define RT5665_HP_IMP_SENS_CTRL_30		0x01d2 +#define RT5665_HP_IMP_SENS_CTRL_31		0x01d3 +#define RT5665_HP_IMP_SENS_CTRL_32		0x01d4 +#define RT5665_HP_IMP_SENS_CTRL_33		0x01d5 +#define RT5665_HP_IMP_SENS_CTRL_34		0x01d6 +#define RT5665_HP_LOGIC_CTRL_1			0x01da +#define RT5665_HP_LOGIC_CTRL_2			0x01db +#define RT5665_HP_LOGIC_CTRL_3			0x01dc +#define RT5665_HP_CALIB_CTRL_1			0x01de +#define RT5665_HP_CALIB_CTRL_2			0x01df +#define RT5665_HP_CALIB_CTRL_3			0x01e0 +#define RT5665_HP_CALIB_CTRL_4			0x01e1 +#define RT5665_HP_CALIB_CTRL_5			0x01e2 +#define RT5665_HP_CALIB_CTRL_6			0x01e3 +#define RT5665_HP_CALIB_CTRL_7			0x01e4 +#define RT5665_HP_CALIB_CTRL_9			0x01e6 +#define RT5665_HP_CALIB_CTRL_10			0x01e7 +#define RT5665_HP_CALIB_CTRL_11			0x01e8 +#define RT5665_HP_CALIB_STA_1			0x01ea +#define RT5665_HP_CALIB_STA_2			0x01eb +#define RT5665_HP_CALIB_STA_3			0x01ec +#define RT5665_HP_CALIB_STA_4			0x01ed +#define RT5665_HP_CALIB_STA_5			0x01ee +#define RT5665_HP_CALIB_STA_6			0x01ef +#define RT5665_HP_CALIB_STA_7			0x01f0 +#define RT5665_HP_CALIB_STA_8			0x01f1 +#define RT5665_HP_CALIB_STA_9			0x01f2 +#define RT5665_HP_CALIB_STA_10			0x01f3 +#define RT5665_HP_CALIB_STA_11			0x01f4 +#define RT5665_PGM_TAB_CTRL1			0x0200 +#define RT5665_PGM_TAB_CTRL2			0x0201 +#define RT5665_PGM_TAB_CTRL3			0x0202 +#define RT5665_PGM_TAB_CTRL4			0x0203 +#define RT5665_PGM_TAB_CTRL5			0x0204 +#define RT5665_PGM_TAB_CTRL6			0x0205 +#define RT5665_PGM_TAB_CTRL7			0x0206 +#define RT5665_PGM_TAB_CTRL8			0x0207 +#define RT5665_PGM_TAB_CTRL9			0x0208 +#define RT5665_SAR_IL_CMD_1			0x0210 +#define RT5665_SAR_IL_CMD_2			0x0211 +#define RT5665_SAR_IL_CMD_3			0x0212 +#define RT5665_SAR_IL_CMD_4			0x0213 +#define RT5665_SAR_IL_CMD_5			0x0214 +#define RT5665_SAR_IL_CMD_6			0x0215 +#define RT5665_SAR_IL_CMD_7			0x0216 +#define RT5665_SAR_IL_CMD_8			0x0217 +#define RT5665_SAR_IL_CMD_9			0x0218 +#define RT5665_SAR_IL_CMD_10			0x0219 +#define RT5665_SAR_IL_CMD_11			0x021a +#define RT5665_SAR_IL_CMD_12			0x021b +#define RT5665_DRC1_CTRL_0			0x02ff +#define RT5665_DRC1_CTRL_1			0x0300 +#define RT5665_DRC1_CTRL_2			0x0301 +#define RT5665_DRC1_CTRL_3			0x0302 +#define RT5665_DRC1_CTRL_4			0x0303 +#define RT5665_DRC1_CTRL_5			0x0304 +#define RT5665_DRC1_CTRL_6			0x0305 +#define RT5665_DRC1_HARD_LMT_CTRL_1		0x0306 +#define RT5665_DRC1_HARD_LMT_CTRL_2		0x0307 +#define RT5665_DRC1_PRIV_1			0x0310 +#define RT5665_DRC1_PRIV_2			0x0311 +#define RT5665_DRC1_PRIV_3			0x0312 +#define RT5665_DRC1_PRIV_4			0x0313 +#define RT5665_DRC1_PRIV_5			0x0314 +#define RT5665_DRC1_PRIV_6			0x0315 +#define RT5665_DRC1_PRIV_7			0x0316 +#define RT5665_DRC1_PRIV_8			0x0317 +#define RT5665_ALC_PGA_CTRL_1			0x0330 +#define RT5665_ALC_PGA_CTRL_2			0x0331 +#define RT5665_ALC_PGA_CTRL_3			0x0332 +#define RT5665_ALC_PGA_CTRL_4			0x0333 +#define RT5665_ALC_PGA_CTRL_5			0x0334 +#define RT5665_ALC_PGA_CTRL_6			0x0335 +#define RT5665_ALC_PGA_CTRL_7			0x0336 +#define RT5665_ALC_PGA_CTRL_8			0x0337 +#define RT5665_ALC_PGA_STA_1			0x0338 +#define RT5665_ALC_PGA_STA_2			0x0339 +#define RT5665_ALC_PGA_STA_3			0x033a +#define RT5665_EQ_AUTO_RCV_CTRL1		0x03c0 +#define RT5665_EQ_AUTO_RCV_CTRL2		0x03c1 +#define RT5665_EQ_AUTO_RCV_CTRL3		0x03c2 +#define RT5665_EQ_AUTO_RCV_CTRL4		0x03c3 +#define RT5665_EQ_AUTO_RCV_CTRL5		0x03c4 +#define RT5665_EQ_AUTO_RCV_CTRL6		0x03c5 +#define RT5665_EQ_AUTO_RCV_CTRL7		0x03c6 +#define RT5665_EQ_AUTO_RCV_CTRL8		0x03c7 +#define RT5665_EQ_AUTO_RCV_CTRL9		0x03c8 +#define RT5665_EQ_AUTO_RCV_CTRL10		0x03c9 +#define RT5665_EQ_AUTO_RCV_CTRL11		0x03ca +#define RT5665_EQ_AUTO_RCV_CTRL12		0x03cb +#define RT5665_EQ_AUTO_RCV_CTRL13		0x03cc +#define RT5665_ADC_L_EQ_LPF1_A1			0x03d0 +#define RT5665_R_EQ_LPF1_A1			0x03d1 +#define RT5665_L_EQ_LPF1_H0			0x03d2 +#define RT5665_R_EQ_LPF1_H0			0x03d3 +#define RT5665_L_EQ_BPF1_A1			0x03d4 +#define RT5665_R_EQ_BPF1_A1			0x03d5 +#define RT5665_L_EQ_BPF1_A2			0x03d6 +#define RT5665_R_EQ_BPF1_A2			0x03d7 +#define RT5665_L_EQ_BPF1_H0			0x03d8 +#define RT5665_R_EQ_BPF1_H0			0x03d9 +#define RT5665_L_EQ_BPF2_A1			0x03da +#define RT5665_R_EQ_BPF2_A1			0x03db +#define RT5665_L_EQ_BPF2_A2			0x03dc +#define RT5665_R_EQ_BPF2_A2			0x03dd +#define RT5665_L_EQ_BPF2_H0			0x03de +#define RT5665_R_EQ_BPF2_H0			0x03df +#define RT5665_L_EQ_BPF3_A1			0x03e0 +#define RT5665_R_EQ_BPF3_A1			0x03e1 +#define RT5665_L_EQ_BPF3_A2			0x03e2 +#define RT5665_R_EQ_BPF3_A2			0x03e3 +#define RT5665_L_EQ_BPF3_H0			0x03e4 +#define RT5665_R_EQ_BPF3_H0			0x03e5 +#define RT5665_L_EQ_BPF4_A1			0x03e6 +#define RT5665_R_EQ_BPF4_A1			0x03e7 +#define RT5665_L_EQ_BPF4_A2			0x03e8 +#define RT5665_R_EQ_BPF4_A2			0x03e9 +#define RT5665_L_EQ_BPF4_H0			0x03ea +#define RT5665_R_EQ_BPF4_H0			0x03eb +#define RT5665_L_EQ_HPF1_A1			0x03ec +#define RT5665_R_EQ_HPF1_A1			0x03ed +#define RT5665_L_EQ_HPF1_H0			0x03ee +#define RT5665_R_EQ_HPF1_H0			0x03ef +#define RT5665_L_EQ_PRE_VOL			0x03f0 +#define RT5665_R_EQ_PRE_VOL			0x03f1 +#define RT5665_L_EQ_POST_VOL			0x03f2 +#define RT5665_R_EQ_POST_VOL			0x03f3 +#define RT5665_SCAN_MODE_CTRL			0x07f0 +#define RT5665_I2C_MODE				0x07fa + + + +/* global definition */ +#define RT5665_L_MUTE				(0x1 << 15) +#define RT5665_L_MUTE_SFT			15 +#define RT5665_VOL_L_MUTE			(0x1 << 14) +#define RT5665_VOL_L_SFT			14 +#define RT5665_R_MUTE				(0x1 << 7) +#define RT5665_R_MUTE_SFT			7 +#define RT5665_VOL_R_MUTE			(0x1 << 6) +#define RT5665_VOL_R_SFT			6 +#define RT5665_L_VOL_MASK			(0x3f << 8) +#define RT5665_L_VOL_SFT			8 +#define RT5665_R_VOL_MASK			(0x3f) +#define RT5665_R_VOL_SFT			0 + +/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/ +#define RT5665_G_HP				(0xf << 8) +#define RT5665_G_HP_SFT				8 +#define RT5665_G_STO_DA_DMIX			(0xf) +#define RT5665_G_STO_DA_SFT			0 + +/* CBJ Control (0x000b) */ +#define RT5665_BST_CBJ_MASK			(0xf << 8) +#define RT5665_BST_CBJ_SFT			8 + +/* IN1/IN2 Control (0x000c) */ +#define RT5665_IN1_DF_MASK			(0x1 << 15) +#define RT5665_IN1_DF				15 +#define RT5665_BST1_MASK			(0x7f << 8) +#define RT5665_BST1_SFT				8 +#define RT5665_IN2_DF_MASK			(0x1 << 7) +#define RT5665_IN2_DF				7 +#define RT5665_BST2_MASK			(0x7f) +#define RT5665_BST2_SFT				0 + +/* IN3/IN4 Control (0x000d) */ +#define RT5665_IN3_DF_MASK			(0x1 << 15) +#define RT5665_IN3_DF				15 +#define RT5665_BST3_MASK			(0x7f << 8) +#define RT5665_BST3_SFT				8 +#define RT5665_IN4_DF_MASK			(0x1 << 7) +#define RT5665_IN4_DF				7 +#define RT5665_BST4_MASK			(0x7f) +#define RT5665_BST4_SFT				0 + +/* INL and INR Volume Control (0x000f) */ +#define RT5665_INL_VOL_MASK			(0x1f << 8) +#define RT5665_INL_VOL_SFT			8 +#define RT5665_INR_VOL_MASK			(0x1f) +#define RT5665_INR_VOL_SFT			0 + +/* Embeeded Jack and Type Detection Control 1 (0x0010) */ +#define RT5665_EMB_JD_EN			(0x1 << 15) +#define RT5665_EMB_JD_EN_SFT			15 +#define RT5665_JD_MODE				(0x1 << 13) +#define RT5665_JD_MODE_SFT			13 +#define RT5665_POLA_EXT_JD_MASK			(0x1 << 11) +#define RT5665_POLA_EXT_JD_LOW			(0x1 << 11) +#define RT5665_POLA_EXT_JD_HIGH			(0x0 << 11) +#define RT5665_EXT_JD_DIG			(0x1 << 9) +#define RT5665_POL_FAST_OFF_MASK		(0x1 << 8) +#define RT5665_POL_FAST_OFF_HIGH		(0x1 << 8) +#define RT5665_POL_FAST_OFF_LOW			(0x0 << 8) +#define RT5665_VREF_POW_MASK			(0x1 << 6) +#define RT5665_VREF_POW_FSM			(0x0 << 6) +#define RT5665_VREF_POW_REG			(0x1 << 6) +#define RT5665_MB1_PATH_MASK			(0x1 << 5) +#define RT5665_CTRL_MB1_REG			(0x1 << 5) +#define RT5665_CTRL_MB1_FSM			(0x0 << 5) +#define RT5665_MB2_PATH_MASK			(0x1 << 4) +#define RT5665_CTRL_MB2_REG			(0x1 << 4) +#define RT5665_CTRL_MB2_FSM			(0x0 << 4) +#define RT5665_TRIG_JD_MASK			(0x1 << 3) +#define RT5665_TRIG_JD_HIGH			(0x1 << 3) +#define RT5665_TRIG_JD_LOW			(0x0 << 3) + +/* Embeeded Jack and Type Detection Control 2 (0x0011) */ +#define RT5665_EXT_JD_SRC			(0x7 << 4) +#define RT5665_EXT_JD_SRC_SFT			4 +#define RT5665_EXT_JD_SRC_GPIO_JD1		(0x0 << 4) +#define RT5665_EXT_JD_SRC_GPIO_JD2		(0x1 << 4) +#define RT5665_EXT_JD_SRC_JD1_1			(0x2 << 4) +#define RT5665_EXT_JD_SRC_JD1_2			(0x3 << 4) +#define RT5665_EXT_JD_SRC_JD2			(0x4 << 4) +#define RT5665_EXT_JD_SRC_JD3			(0x5 << 4) +#define RT5665_EXT_JD_SRC_MANUAL		(0x6 << 4) + +/* Combo Jack and Type Detection Control 4 (0x0013) */ +#define RT5665_SEL_SHT_MID_TON_MASK		(0x3 << 12) +#define RT5665_SEL_SHT_MID_TON_2		(0x0 << 12) +#define RT5665_SEL_SHT_MID_TON_3		(0x1 << 12) +#define RT5665_CBJ_JD_TEST_MASK			(0x1 << 6) +#define RT5665_CBJ_JD_TEST_NORM			(0x0 << 6) +#define RT5665_CBJ_JD_TEST_MODE			(0x1 << 6) + +/* Slience Detection Control (0x0015) */ +#define RT5665_SIL_DET_MASK			(0x1 << 15) +#define RT5665_SIL_DET_DIS			(0x0 << 15) +#define RT5665_SIL_DET_EN			(0x1 << 15) + +/* DAC2 Control (0x0017) */ +#define RT5665_M_DAC2_L_VOL			(0x1 << 13) +#define RT5665_M_DAC2_L_VOL_SFT			13 +#define RT5665_M_DAC2_R_VOL			(0x1 << 12) +#define RT5665_M_DAC2_R_VOL_SFT			12 +#define RT5665_DAC_L2_SEL_MASK			(0x7 << 4) +#define RT5665_DAC_L2_SEL_SFT			4 +#define RT5665_DAC_R2_SEL_MASK			(0x7 << 0) +#define RT5665_DAC_R2_SEL_SFT			0 + +/* Sidetone Control (0x0018) */ +#define RT5665_ST_SEL_MASK			(0x7 << 9) +#define RT5665_ST_SEL_SFT			9 +#define RT5665_ST_EN				(0x1 << 6) +#define RT5665_ST_EN_SFT			6 + +/* DAC1 Digital Volume (0x0019) */ +#define RT5665_DAC_L1_VOL_MASK			(0xff << 8) +#define RT5665_DAC_L1_VOL_SFT			8 +#define RT5665_DAC_R1_VOL_MASK			(0xff) +#define RT5665_DAC_R1_VOL_SFT			0 + +/* DAC2 Digital Volume (0x001a) */ +#define RT5665_DAC_L2_VOL_MASK			(0xff << 8) +#define RT5665_DAC_L2_VOL_SFT			8 +#define RT5665_DAC_R2_VOL_MASK			(0xff) +#define RT5665_DAC_R2_VOL_SFT			0 + +/* DAC3 Control (0x001b) */ +#define RT5665_M_DAC3_L_VOL			(0x1 << 13) +#define RT5665_M_DAC3_L_VOL_SFT			13 +#define RT5665_M_DAC3_R_VOL			(0x1 << 12) +#define RT5665_M_DAC3_R_VOL_SFT			12 +#define RT5665_DAC_L3_SEL_MASK			(0x7 << 4) +#define RT5665_DAC_L3_SEL_SFT			4 +#define RT5665_DAC_R3_SEL_MASK			(0x7 << 0) +#define RT5665_DAC_R3_SEL_SFT			0 + +/* ADC Digital Volume Control (0x001c) */ +#define RT5665_ADC_L_VOL_MASK			(0x7f << 8) +#define RT5665_ADC_L_VOL_SFT			8 +#define RT5665_ADC_R_VOL_MASK			(0x7f) +#define RT5665_ADC_R_VOL_SFT			0 + +/* Mono ADC Digital Volume Control (0x001d) */ +#define RT5665_MONO_ADC_L_VOL_MASK		(0x7f << 8) +#define RT5665_MONO_ADC_L_VOL_SFT		8 +#define RT5665_MONO_ADC_R_VOL_MASK		(0x7f) +#define RT5665_MONO_ADC_R_VOL_SFT		0 + +/* Stereo1 ADC Boost Gain Control (0x001f) */ +#define RT5665_STO1_ADC_L_BST_MASK		(0x3 << 14) +#define RT5665_STO1_ADC_L_BST_SFT		14 +#define RT5665_STO1_ADC_R_BST_MASK		(0x3 << 12) +#define RT5665_STO1_ADC_R_BST_SFT		12 + +/* Mono ADC Boost Gain Control (0x0020) */ +#define RT5665_MONO_ADC_L_BST_MASK		(0x3 << 14) +#define RT5665_MONO_ADC_L_BST_SFT		14 +#define RT5665_MONO_ADC_R_BST_MASK		(0x3 << 12) +#define RT5665_MONO_ADC_R_BST_SFT		12 + +/* Stereo1 ADC Boost Gain Control (0x001f) */ +#define RT5665_STO2_ADC_L_BST_MASK		(0x3 << 14) +#define RT5665_STO2_ADC_L_BST_SFT		14 +#define RT5665_STO2_ADC_R_BST_MASK		(0x3 << 12) +#define RT5665_STO2_ADC_R_BST_SFT		12 + +/* Stereo1 ADC Mixer Control (0x0026) */ +#define RT5665_M_STO1_ADC_L1			(0x1 << 15) +#define RT5665_M_STO1_ADC_L1_SFT		15 +#define RT5665_M_STO1_ADC_L2			(0x1 << 14) +#define RT5665_M_STO1_ADC_L2_SFT		14 +#define RT5665_STO1_ADC1L_SRC_MASK		(0x1 << 13) +#define RT5665_STO1_ADC1L_SRC_SFT		13 +#define RT5665_STO1_ADC1_SRC_ADC		(0x1 << 13) +#define RT5665_STO1_ADC1_SRC_DACMIX		(0x0 << 13) +#define RT5665_STO1_ADC2L_SRC_MASK		(0x1 << 12) +#define RT5665_STO1_ADC2L_SRC_SFT		12 +#define RT5665_STO1_ADCL_SRC_MASK		(0x3 << 10) +#define RT5665_STO1_ADCL_SRC_SFT		10 +#define RT5665_STO1_DD_L_SRC_MASK		(0x1 << 9) +#define RT5665_STO1_DD_L_SRC_SFT		9 +#define RT5665_STO1_DMIC_SRC_MASK		(0x1 << 8) +#define RT5665_STO1_DMIC_SRC_SFT		8 +#define RT5665_STO1_DMIC_SRC_DMIC2		(0x1 << 8) +#define RT5665_STO1_DMIC_SRC_DMIC1		(0x0 << 8) +#define RT5665_M_STO1_ADC_R1			(0x1 << 7) +#define RT5665_M_STO1_ADC_R1_SFT		7 +#define RT5665_M_STO1_ADC_R2			(0x1 << 6) +#define RT5665_M_STO1_ADC_R2_SFT		6 +#define RT5665_STO1_ADC1R_SRC_MASK		(0x1 << 5) +#define RT5665_STO1_ADC1R_SRC_SFT		5 +#define RT5665_STO1_ADC2R_SRC_MASK		(0x1 << 4) +#define RT5665_STO1_ADC2R_SRC_SFT		4 +#define RT5665_STO1_ADCR_SRC_MASK		(0x3 << 2) +#define RT5665_STO1_ADCR_SRC_SFT		2 +#define RT5665_STO1_DD_R_SRC_MASK		(0x3) +#define RT5665_STO1_DD_R_SRC_SFT		0 + + +/* Mono1 ADC Mixer control (0x0027) */ +#define RT5665_M_MONO_ADC_L1			(0x1 << 15) +#define RT5665_M_MONO_ADC_L1_SFT		15 +#define RT5665_M_MONO_ADC_L2			(0x1 << 14) +#define RT5665_M_MONO_ADC_L2_SFT		14 +#define RT5665_MONO_ADC_L1_SRC_MASK		(0x1 << 13) +#define RT5665_MONO_ADC_L1_SRC_SFT		13 +#define RT5665_MONO_ADC_L2_SRC_MASK		(0x1 << 12) +#define RT5665_MONO_ADC_L2_SRC_SFT		12 +#define RT5665_MONO_ADC_L_SRC_MASK		(0x3 << 10) +#define RT5665_MONO_ADC_L_SRC_SFT		10 +#define RT5665_MONO_DD_L_SRC_MASK		(0x1 << 9) +#define RT5665_MONO_DD_L_SRC_SFT		9 +#define RT5665_MONO_DMIC_L_SRC_MASK		(0x1 << 8) +#define RT5665_MONO_DMIC_L_SRC_SFT		8 +#define RT5665_M_MONO_ADC_R1			(0x1 << 7) +#define RT5665_M_MONO_ADC_R1_SFT		7 +#define RT5665_M_MONO_ADC_R2			(0x1 << 6) +#define RT5665_M_MONO_ADC_R2_SFT		6 +#define RT5665_MONO_ADC_R1_SRC_MASK		(0x1 << 5) +#define RT5665_MONO_ADC_R1_SRC_SFT		5 +#define RT5665_MONO_ADC_R2_SRC_MASK		(0x1 << 4) +#define RT5665_MONO_ADC_R2_SRC_SFT		4 +#define RT5665_MONO_ADC_R_SRC_MASK		(0x3 << 2) +#define RT5665_MONO_ADC_R_SRC_SFT		2 +#define RT5665_MONO_DD_R_SRC_MASK		(0x1 << 1) +#define RT5665_MONO_DD_R_SRC_SFT		1 +#define RT5665_MONO_DMIC_R_SRC_MASK		0x1 +#define RT5665_MONO_DMIC_R_SRC_SFT		0 + +/* Stereo2 ADC Mixer Control (0x0028) */ +#define RT5665_M_STO2_ADC_L1			(0x1 << 15) +#define RT5665_M_STO2_ADC_L1_UN			(0x0 << 15) +#define RT5665_M_STO2_ADC_L1_SFT		15 +#define RT5665_M_STO2_ADC_L2			(0x1 << 14) +#define RT5665_M_STO2_ADC_L2_SFT		14 +#define RT5665_STO2_ADC1L_SRC_MASK		(0x1 << 13) +#define RT5665_STO2_ADC1L_SRC_SFT		13 +#define RT5665_STO2_ADC1_SRC_ADC		(0x1 << 13) +#define RT5665_STO2_ADC1_SRC_DACMIX		(0x0 << 13) +#define RT5665_STO2_ADC2L_SRC_MASK		(0x1 << 12) +#define RT5665_STO2_ADC2L_SRC_SFT		12 +#define RT5665_STO2_ADCL_SRC_MASK		(0x3 << 10) +#define RT5665_STO2_ADCL_SRC_SFT		10 +#define RT5665_STO2_DD_L_SRC_MASK		(0x1 << 9) +#define RT5665_STO2_DD_L_SRC_SFT		9 +#define RT5665_STO2_DMIC_SRC_MASK		(0x1 << 8) +#define RT5665_STO2_DMIC_SRC_SFT		8 +#define RT5665_STO2_DMIC_SRC_DMIC2		(0x1 << 8) +#define RT5665_STO2_DMIC_SRC_DMIC1		(0x0 << 8) +#define RT5665_M_STO2_ADC_R1			(0x1 << 7) +#define RT5665_M_STO2_ADC_R1_UN			(0x0 << 7) +#define RT5665_M_STO2_ADC_R1_SFT		7 +#define RT5665_M_STO2_ADC_R2			(0x1 << 6) +#define RT5665_M_STO2_ADC_R2_SFT		6 +#define RT5665_STO2_ADC1R_SRC_MASK		(0x1 << 5) +#define RT5665_STO2_ADC1R_SRC_SFT		5 +#define RT5665_STO2_ADC2R_SRC_MASK		(0x1 << 4) +#define RT5665_STO2_ADC2R_SRC_SFT		4 +#define RT5665_STO2_ADCR_SRC_MASK		(0x3 << 2) +#define RT5665_STO2_ADCR_SRC_SFT		2 +#define RT5665_STO2_DD_R_SRC_MASK		(0x1 << 1) +#define RT5665_STO2_DD_R_SRC_SFT		1 + +/* ADC Mixer to DAC Mixer Control (0x0029) */ +#define RT5665_M_ADCMIX_L			(0x1 << 15) +#define RT5665_M_ADCMIX_L_SFT			15 +#define RT5665_M_DAC1_L				(0x1 << 14) +#define RT5665_M_DAC1_L_SFT			14 +#define RT5665_DAC1_R_SEL_MASK			(0x3 << 10) +#define RT5665_DAC1_R_SEL_SFT			10 +#define RT5665_DAC1_L_SEL_MASK			(0x3 << 8) +#define RT5665_DAC1_L_SEL_SFT			8 +#define RT5665_M_ADCMIX_R			(0x1 << 7) +#define RT5665_M_ADCMIX_R_SFT			7 +#define RT5665_M_DAC1_R				(0x1 << 6) +#define RT5665_M_DAC1_R_SFT			6 + +/* Stereo1 DAC Mixer Control (0x002a) */ +#define RT5665_M_DAC_L1_STO_L			(0x1 << 15) +#define RT5665_M_DAC_L1_STO_L_SFT		15 +#define RT5665_G_DAC_L1_STO_L_MASK		(0x1 << 14) +#define RT5665_G_DAC_L1_STO_L_SFT		14 +#define RT5665_M_DAC_R1_STO_L			(0x1 << 13) +#define RT5665_M_DAC_R1_STO_L_SFT		13 +#define RT5665_G_DAC_R1_STO_L_MASK		(0x1 << 12) +#define RT5665_G_DAC_R1_STO_L_SFT		12 +#define RT5665_M_DAC_L2_STO_L			(0x1 << 11) +#define RT5665_M_DAC_L2_STO_L_SFT		11 +#define RT5665_G_DAC_L2_STO_L_MASK		(0x1 << 10) +#define RT5665_G_DAC_L2_STO_L_SFT		10 +#define RT5665_M_DAC_R2_STO_L			(0x1 << 9) +#define RT5665_M_DAC_R2_STO_L_SFT		9 +#define RT5665_G_DAC_R2_STO_L_MASK		(0x1 << 8) +#define RT5665_G_DAC_R2_STO_L_SFT		8 +#define RT5665_M_DAC_L1_STO_R			(0x1 << 7) +#define RT5665_M_DAC_L1_STO_R_SFT		7 +#define RT5665_G_DAC_L1_STO_R_MASK		(0x1 << 6) +#define RT5665_G_DAC_L1_STO_R_SFT		6 +#define RT5665_M_DAC_R1_STO_R			(0x1 << 5) +#define RT5665_M_DAC_R1_STO_R_SFT		5 +#define RT5665_G_DAC_R1_STO_R_MASK		(0x1 << 4) +#define RT5665_G_DAC_R1_STO_R_SFT		4 +#define RT5665_M_DAC_L2_STO_R			(0x1 << 3) +#define RT5665_M_DAC_L2_STO_R_SFT		3 +#define RT5665_G_DAC_L2_STO_R_MASK		(0x1 << 2) +#define RT5665_G_DAC_L2_STO_R_SFT		2 +#define RT5665_M_DAC_R2_STO_R			(0x1 << 1) +#define RT5665_M_DAC_R2_STO_R_SFT		1 +#define RT5665_G_DAC_R2_STO_R_MASK		(0x1) +#define RT5665_G_DAC_R2_STO_R_SFT		0 + +/* Mono DAC Mixer Control (0x002b) */ +#define RT5665_M_DAC_L1_MONO_L			(0x1 << 15) +#define RT5665_M_DAC_L1_MONO_L_SFT		15 +#define RT5665_G_DAC_L1_MONO_L_MASK		(0x1 << 14) +#define RT5665_G_DAC_L1_MONO_L_SFT		14 +#define RT5665_M_DAC_R1_MONO_L			(0x1 << 13) +#define RT5665_M_DAC_R1_MONO_L_SFT		13 +#define RT5665_G_DAC_R1_MONO_L_MASK		(0x1 << 12) +#define RT5665_G_DAC_R1_MONO_L_SFT		12 +#define RT5665_M_DAC_L2_MONO_L			(0x1 << 11) +#define RT5665_M_DAC_L2_MONO_L_SFT		11 +#define RT5665_G_DAC_L2_MONO_L_MASK		(0x1 << 10) +#define RT5665_G_DAC_L2_MONO_L_SFT		10 +#define RT5665_M_DAC_R2_MONO_L			(0x1 << 9) +#define RT5665_M_DAC_R2_MONO_L_SFT		9 +#define RT5665_G_DAC_R2_MONO_L_MASK		(0x1 << 8) +#define RT5665_G_DAC_R2_MONO_L_SFT		8 +#define RT5665_M_DAC_L1_MONO_R			(0x1 << 7) +#define RT5665_M_DAC_L1_MONO_R_SFT		7 +#define RT5665_G_DAC_L1_MONO_R_MASK		(0x1 << 6) +#define RT5665_G_DAC_L1_MONO_R_SFT		6 +#define RT5665_M_DAC_R1_MONO_R			(0x1 << 5) +#define RT5665_M_DAC_R1_MONO_R_SFT		5 +#define RT5665_G_DAC_R1_MONO_R_MASK		(0x1 << 4) +#define RT5665_G_DAC_R1_MONO_R_SFT		4 +#define RT5665_M_DAC_L2_MONO_R			(0x1 << 3) +#define RT5665_M_DAC_L2_MONO_R_SFT		3 +#define RT5665_G_DAC_L2_MONO_R_MASK		(0x1 << 2) +#define RT5665_G_DAC_L2_MONO_R_SFT		2 +#define RT5665_M_DAC_R2_MONO_R			(0x1 << 1) +#define RT5665_M_DAC_R2_MONO_R_SFT		1 +#define RT5665_G_DAC_R2_MONO_R_MASK		(0x1) +#define RT5665_G_DAC_R2_MONO_R_SFT		0 + +/* Stereo2 DAC Mixer Control (0x002c) */ +#define RT5665_M_DAC_L1_STO2_L			(0x1 << 15) +#define RT5665_M_DAC_L1_STO2_L_SFT		15 +#define RT5665_G_DAC_L1_STO2_L_MASK		(0x1 << 14) +#define RT5665_G_DAC_L1_STO2_L_SFT		14 +#define RT5665_M_DAC_L2_STO2_L			(0x1 << 13) +#define RT5665_M_DAC_L2_STO2_L_SFT		13 +#define RT5665_G_DAC_L2_STO2_L_MASK		(0x1 << 12) +#define RT5665_G_DAC_L2_STO2_L_SFT		12 +#define RT5665_M_DAC_L3_STO2_L			(0x1 << 11) +#define RT5665_M_DAC_L3_STO2_L_SFT		11 +#define RT5665_G_DAC_L3_STO2_L_MASK		(0x1 << 10) +#define RT5665_G_DAC_L3_STO2_L_SFT		10 +#define RT5665_M_ST_DAC_L1			(0x1 << 9) +#define RT5665_M_ST_DAC_L1_SFT			9 +#define RT5665_M_ST_DAC_R1			(0x1 << 8) +#define RT5665_M_ST_DAC_R1_SFT			8 +#define RT5665_M_DAC_R1_STO2_R			(0x1 << 7) +#define RT5665_M_DAC_R1_STO2_R_SFT		7 +#define RT5665_G_DAC_R1_STO2_R_MASK		(0x1 << 6) +#define RT5665_G_DAC_R1_STO2_R_SFT		6 +#define RT5665_M_DAC_R2_STO2_R			(0x1 << 5) +#define RT5665_M_DAC_R2_STO2_R_SFT		5 +#define RT5665_G_DAC_R2_STO2_R_MASK		(0x1 << 4) +#define RT5665_G_DAC_R2_STO2_R_SFT		4 +#define RT5665_M_DAC_R3_STO2_R			(0x1 << 3) +#define RT5665_M_DAC_R3_STO2_R_SFT		3 +#define RT5665_G_DAC_R3_STO2_R_MASK		(0x1 << 2) +#define RT5665_G_DAC_R3_STO2_R_SFT		2 + +/* Analog DAC1 Input Source Control (0x002d) */ +#define RT5665_DAC_MIX_L_MASK			(0x3 << 12) +#define RT5665_DAC_MIX_L_SFT			12 +#define RT5665_DAC_MIX_R_MASK			(0x3 << 8) +#define RT5665_DAC_MIX_R_SFT			8 +#define RT5665_DAC_L1_SRC_MASK			(0x3 << 4) +#define RT5665_A_DACL1_SFT			4 +#define RT5665_DAC_R1_SRC_MASK			(0x3) +#define RT5665_A_DACR1_SFT			0 + +/* Analog DAC Input Source Control (0x002e) */ +#define RT5665_A_DACL2_SEL			(0x1 << 4) +#define RT5665_A_DACL2_SFT			4 +#define RT5665_A_DACR2_SEL			(0x1 << 0) +#define RT5665_A_DACR2_SFT			0 + +/* Digital Interface Data Control (0x002f) */ +#define RT5665_IF2_1_ADC_IN_MASK		(0x7 << 12) +#define RT5665_IF2_1_ADC_IN_SFT			12 +#define RT5665_IF2_1_DAC_SEL_MASK		(0x3 << 10) +#define RT5665_IF2_1_DAC_SEL_SFT		10 +#define RT5665_IF2_1_ADC_SEL_MASK		(0x3 << 8) +#define RT5665_IF2_1_ADC_SEL_SFT		8 +#define RT5665_IF2_2_ADC_IN_MASK		(0x7 << 4) +#define RT5665_IF2_2_ADC_IN_SFT			4 +#define RT5665_IF2_2_DAC_SEL_MASK		(0x3 << 2) +#define RT5665_IF2_2_DAC_SEL_SFT		2 +#define RT5665_IF2_2_ADC_SEL_MASK		(0x3 << 0) +#define RT5665_IF2_2_ADC_SEL_SFT		0 + +/* Digital Interface Data Control (0x0030) */ +#define RT5665_IF3_ADC_IN_MASK			(0x7 << 4) +#define RT5665_IF3_ADC_IN_SFT			4 +#define RT5665_IF3_DAC_SEL_MASK			(0x3 << 2) +#define RT5665_IF3_DAC_SEL_SFT			2 +#define RT5665_IF3_ADC_SEL_MASK			(0x3 << 0) +#define RT5665_IF3_ADC_SEL_SFT			0 + +/* PDM Output Control (0x0031) */ +#define RT5665_M_PDM1_L				(0x1 << 14) +#define RT5665_M_PDM1_L_SFT			14 +#define RT5665_M_PDM1_R				(0x1 << 12) +#define RT5665_M_PDM1_R_SFT			12 +#define RT5665_PDM1_L_MASK			(0x3 << 10) +#define RT5665_PDM1_L_SFT			10 +#define RT5665_PDM1_R_MASK			(0x3 << 8) +#define RT5665_PDM1_R_SFT			8 +#define RT5665_PDM1_BUSY			(0x1 << 6) +#define RT5665_PDM_PATTERN			(0x1 << 5) +#define RT5665_PDM_GAIN				(0x1 << 4) +#define RT5665_LRCK_PDM_PI2C			(0x1 << 3) +#define RT5665_PDM_DIV_MASK			(0x3) + +/*S/PDIF Output Control (0x0036) */ +#define RT5665_SPDIF_SEL_MASK			(0x3 << 0) +#define RT5665_SPDIF_SEL_SFT			0 + +/* REC Left Mixer Control 2 (0x003c) */ +#define RT5665_M_CBJ_RM1_L			(0x1 << 7) +#define RT5665_M_CBJ_RM1_L_SFT			7 +#define RT5665_M_BST1_RM1_L			(0x1 << 5) +#define RT5665_M_BST1_RM1_L_SFT			5 +#define RT5665_M_BST2_RM1_L			(0x1 << 4) +#define RT5665_M_BST2_RM1_L_SFT			4 +#define RT5665_M_BST3_RM1_L			(0x1 << 3) +#define RT5665_M_BST3_RM1_L_SFT			3 +#define RT5665_M_BST4_RM1_L			(0x1 << 2) +#define RT5665_M_BST4_RM1_L_SFT			2 +#define RT5665_M_INL_RM1_L			(0x1 << 1) +#define RT5665_M_INL_RM1_L_SFT			1 +#define RT5665_M_INR_RM1_L			(0x1) +#define RT5665_M_INR_RM1_L_SFT			0 + +/* REC Right Mixer Control 2 (0x003e) */ +#define RT5665_M_AEC_REF_RM1_R			(0x1 << 7) +#define RT5665_M_AEC_REF_RM1_R_SFT		7 +#define RT5665_M_BST1_RM1_R			(0x1 << 5) +#define RT5665_M_BST1_RM1_R_SFT			5 +#define RT5665_M_BST2_RM1_R			(0x1 << 4) +#define RT5665_M_BST2_RM1_R_SFT			4 +#define RT5665_M_BST3_RM1_R			(0x1 << 3) +#define RT5665_M_BST3_RM1_R_SFT			3 +#define RT5665_M_BST4_RM1_R			(0x1 << 2) +#define RT5665_M_BST4_RM1_R_SFT			2 +#define RT5665_M_INR_RM1_R			(0x1 << 1) +#define RT5665_M_INR_RM1_R_SFT			1 +#define RT5665_M_MONOVOL_RM1_R			(0x1) +#define RT5665_M_MONOVOL_RM1_R_SFT		0 + +/* REC Mixer 2 Left Control 2 (0x0041) */ +#define RT5665_M_CBJ_RM2_L			(0x1 << 7) +#define RT5665_M_CBJ_RM2_L_SFT			7 +#define RT5665_M_BST1_RM2_L			(0x1 << 5) +#define RT5665_M_BST1_RM2_L_SFT			5 +#define RT5665_M_BST2_RM2_L			(0x1 << 4) +#define RT5665_M_BST2_RM2_L_SFT			4 +#define RT5665_M_BST3_RM2_L			(0x1 << 3) +#define RT5665_M_BST3_RM2_L_SFT			3 +#define RT5665_M_BST4_RM2_L			(0x1 << 2) +#define RT5665_M_BST4_RM2_L_SFT			2 +#define RT5665_M_INL_RM2_L			(0x1 << 1) +#define RT5665_M_INL_RM2_L_SFT			1 +#define RT5665_M_INR_RM2_L			(0x1) +#define RT5665_M_INR_RM2_L_SFT			0 + +/* REC Mixer 2 Right Control 2 (0x0043) */ +#define RT5665_M_MONOVOL_RM2_R			(0x1 << 7) +#define RT5665_M_MONOVOL_RM2_R_SFT		7 +#define RT5665_M_BST1_RM2_R			(0x1 << 5) +#define RT5665_M_BST1_RM2_R_SFT			5 +#define RT5665_M_BST2_RM2_R			(0x1 << 4) +#define RT5665_M_BST2_RM2_R_SFT			4 +#define RT5665_M_BST3_RM2_R			(0x1 << 3) +#define RT5665_M_BST3_RM2_R_SFT			3 +#define RT5665_M_BST4_RM2_R			(0x1 << 2) +#define RT5665_M_BST4_RM2_R_SFT			2 +#define RT5665_M_INL_RM2_R			(0x1 << 1) +#define RT5665_M_INL_RM2_R_SFT			1 +#define RT5665_M_INR_RM2_R			(0x1) +#define RT5665_M_INR_RM2_R_SFT			0 + +/* SPK Left Mixer Control (0x0046) */ +#define RT5665_M_BST3_SM_L			(0x1 << 4) +#define RT5665_M_BST3_SM_L_SFT			4 +#define RT5665_M_IN_R_SM_L			(0x1 << 3) +#define RT5665_M_IN_R_SM_L_SFT			3 +#define RT5665_M_IN_L_SM_L			(0x1 << 2) +#define RT5665_M_IN_L_SM_L_SFT			2 +#define RT5665_M_BST1_SM_L			(0x1 << 1) +#define RT5665_M_BST1_SM_L_SFT			1 +#define RT5665_M_DAC_L2_SM_L			(0x1) +#define RT5665_M_DAC_L2_SM_L_SFT		0 + +/* SPK Right Mixer Control (0x0047) */ +#define RT5665_M_BST3_SM_R			(0x1 << 4) +#define RT5665_M_BST3_SM_R_SFT			4 +#define RT5665_M_IN_R_SM_R			(0x1 << 3) +#define RT5665_M_IN_R_SM_R_SFT			3 +#define RT5665_M_IN_L_SM_R			(0x1 << 2) +#define RT5665_M_IN_L_SM_R_SFT			2 +#define RT5665_M_BST4_SM_R			(0x1 << 1) +#define RT5665_M_BST4_SM_R_SFT			1 +#define RT5665_M_DAC_R2_SM_R			(0x1) +#define RT5665_M_DAC_R2_SM_R_SFT		0 + +/* SPO Amp Input and Gain Control (0x0048) */ +#define RT5665_M_DAC_L2_SPKOMIX			(0x1 << 13) +#define RT5665_M_DAC_L2_SPKOMIX_SFT		13 +#define RT5665_M_SPKVOLL_SPKOMIX		(0x1 << 12) +#define RT5665_M_SPKVOLL_SPKOMIX_SFT		12 +#define RT5665_M_DAC_R2_SPKOMIX			(0x1 << 9) +#define RT5665_M_DAC_R2_SPKOMIX_SFT		9 +#define RT5665_M_SPKVOLR_SPKOMIX		(0x1 << 8) +#define RT5665_M_SPKVOLR_SPKOMIX_SFT		8 + +/* MONOMIX Input and Gain Control (0x004b) */ +#define RT5665_G_MONOVOL_MA			(0x1 << 10) +#define RT5665_G_MONOVOL_MA_SFT			10 +#define RT5665_M_MONOVOL_MA			(0x1 << 9) +#define RT5665_M_MONOVOL_MA_SFT			9 +#define RT5665_M_DAC_L2_MA			(0x1 << 8) +#define RT5665_M_DAC_L2_MA_SFT			8 +#define RT5665_M_BST3_MM			(0x1 << 4) +#define RT5665_M_BST3_MM_SFT			4 +#define RT5665_M_BST2_MM			(0x1 << 3) +#define RT5665_M_BST2_MM_SFT			3 +#define RT5665_M_BST1_MM			(0x1 << 2) +#define RT5665_M_BST1_MM_SFT			2 +#define RT5665_M_RECMIC2L_MM			(0x1 << 1) +#define RT5665_M_RECMIC2L_MM_SFT		1 +#define RT5665_M_DAC_L2_MM			(0x1) +#define RT5665_M_DAC_L2_MM_SFT			0 + +/* Output Left Mixer Control 1 (0x004d) */ +#define RT5665_G_BST3_OM_L_MASK			(0x7 << 12) +#define RT5665_G_BST3_OM_L_SFT			12 +#define RT5665_G_BST2_OM_L_MASK			(0x7 << 9) +#define RT5665_G_BST2_OM_L_SFT			9 +#define RT5665_G_BST1_OM_L_MASK			(0x7 << 6) +#define RT5665_G_BST1_OM_L_SFT			6 +#define RT5665_G_IN_L_OM_L_MASK			(0x7 << 3) +#define RT5665_G_IN_L_OM_L_SFT			3 +#define RT5665_G_DAC_L2_OM_L_MASK		(0x7 << 0) +#define RT5665_G_DAC_L2_OM_L_SFT		0 + +/* Output Left Mixer Input Control (0x004e) */ +#define RT5665_M_BST3_OM_L			(0x1 << 4) +#define RT5665_M_BST3_OM_L_SFT			4 +#define RT5665_M_BST2_OM_L			(0x1 << 3) +#define RT5665_M_BST2_OM_L_SFT			3 +#define RT5665_M_BST1_OM_L			(0x1 << 2) +#define RT5665_M_BST1_OM_L_SFT			2 +#define RT5665_M_IN_L_OM_L			(0x1 << 1) +#define RT5665_M_IN_L_OM_L_SFT			1 +#define RT5665_M_DAC_L2_OM_L			(0x1) +#define RT5665_M_DAC_L2_OM_L_SFT		0 + +/* Output Right Mixer Input Control (0x0050) */ +#define RT5665_M_BST4_OM_R			(0x1 << 4) +#define RT5665_M_BST4_OM_R_SFT			4 +#define RT5665_M_BST3_OM_R			(0x1 << 3) +#define RT5665_M_BST3_OM_R_SFT			3 +#define RT5665_M_BST2_OM_R			(0x1 << 2) +#define RT5665_M_BST2_OM_R_SFT			2 +#define RT5665_M_IN_R_OM_R			(0x1 << 1) +#define RT5665_M_IN_R_OM_R_SFT			1 +#define RT5665_M_DAC_R2_OM_R			(0x1) +#define RT5665_M_DAC_R2_OM_R_SFT		0 + +/* LOUT Mixer Control (0x0052) */ +#define RT5665_M_DAC_L2_LM			(0x1 << 15) +#define RT5665_M_DAC_L2_LM_SFT			15 +#define RT5665_M_DAC_R2_LM			(0x1 << 14) +#define RT5665_M_DAC_R2_LM_SFT			14 +#define RT5665_M_OV_L_LM			(0x1 << 13) +#define RT5665_M_OV_L_LM_SFT			13 +#define RT5665_M_OV_R_LM			(0x1 << 12) +#define RT5665_M_OV_R_LM_SFT			12 +#define RT5665_LOUT_BST_SFT			11 +#define RT5665_LOUT_DF				(0x1 << 11) +#define RT5665_LOUT_DF_SFT			11 + +/* Power Management for Digital 1 (0x0061) */ +#define RT5665_PWR_I2S1_1			(0x1 << 15) +#define RT5665_PWR_I2S1_1_BIT			15 +#define RT5665_PWR_I2S1_2			(0x1 << 14) +#define RT5665_PWR_I2S1_2_BIT			14 +#define RT5665_PWR_I2S2_1			(0x1 << 13) +#define RT5665_PWR_I2S2_1_BIT			13 +#define RT5665_PWR_I2S2_2			(0x1 << 12) +#define RT5665_PWR_I2S2_2_BIT			12 +#define RT5665_PWR_DAC_L1			(0x1 << 11) +#define RT5665_PWR_DAC_L1_BIT			11 +#define RT5665_PWR_DAC_R1			(0x1 << 10) +#define RT5665_PWR_DAC_R1_BIT			10 +#define RT5665_PWR_I2S3				(0x1 << 9) +#define RT5665_PWR_I2S3_BIT			9 +#define RT5665_PWR_LDO				(0x1 << 8) +#define RT5665_PWR_LDO_BIT			8 +#define RT5665_PWR_DAC_L2			(0x1 << 7) +#define RT5665_PWR_DAC_L2_BIT			7 +#define RT5665_PWR_DAC_R2			(0x1 << 6) +#define RT5665_PWR_DAC_R2_BIT			6 +#define RT5665_PWR_ADC_L1			(0x1 << 4) +#define RT5665_PWR_ADC_L1_BIT			4 +#define RT5665_PWR_ADC_R1			(0x1 << 3) +#define RT5665_PWR_ADC_R1_BIT			3 +#define RT5665_PWR_ADC_L2			(0x1 << 2) +#define RT5665_PWR_ADC_L2_BIT			2 +#define RT5665_PWR_ADC_R2			(0x1 << 1) +#define RT5665_PWR_ADC_R2_BIT			1 + +/* Power Management for Digital 2 (0x0062) */ +#define RT5665_PWR_ADC_S1F			(0x1 << 15) +#define RT5665_PWR_ADC_S1F_BIT			15 +#define RT5665_PWR_ADC_S2F			(0x1 << 14) +#define RT5665_PWR_ADC_S2F_BIT			14 +#define RT5665_PWR_ADC_MF_L			(0x1 << 13) +#define RT5665_PWR_ADC_MF_L_BIT			13 +#define RT5665_PWR_ADC_MF_R			(0x1 << 12) +#define RT5665_PWR_ADC_MF_R_BIT			12 +#define RT5665_PWR_DAC_S2F			(0x1 << 11) +#define RT5665_PWR_DAC_S2F_BIT			11 +#define RT5665_PWR_DAC_S1F			(0x1 << 10) +#define RT5665_PWR_DAC_S1F_BIT			10 +#define RT5665_PWR_DAC_MF_L			(0x1 << 9) +#define RT5665_PWR_DAC_MF_L_BIT			9 +#define RT5665_PWR_DAC_MF_R			(0x1 << 8) +#define RT5665_PWR_DAC_MF_R_BIT			8 +#define RT5665_PWR_PDM1				(0x1 << 7) +#define RT5665_PWR_PDM1_BIT			7 + +/* Power Management for Analog 1 (0x0063) */ +#define RT5665_PWR_VREF1			(0x1 << 15) +#define RT5665_PWR_VREF1_BIT			15 +#define RT5665_PWR_FV1				(0x1 << 14) +#define RT5665_PWR_FV1_BIT			14 +#define RT5665_PWR_VREF2			(0x1 << 13) +#define RT5665_PWR_VREF2_BIT			13 +#define RT5665_PWR_FV2				(0x1 << 12) +#define RT5665_PWR_FV2_BIT			12 +#define RT5665_PWR_VREF3			(0x1 << 11) +#define RT5665_PWR_VREF3_BIT			11 +#define RT5665_PWR_FV3				(0x1 << 10) +#define RT5665_PWR_FV3_BIT			10 +#define RT5665_PWR_MB				(0x1 << 9) +#define RT5665_PWR_MB_BIT			9 +#define RT5665_PWR_LM				(0x1 << 8) +#define RT5665_PWR_LM_BIT			8 +#define RT5665_PWR_BG				(0x1 << 7) +#define RT5665_PWR_BG_BIT			7 +#define RT5665_PWR_MA				(0x1 << 6) +#define RT5665_PWR_MA_BIT			6 +#define RT5665_PWR_HA_L				(0x1 << 5) +#define RT5665_PWR_HA_L_BIT			5 +#define RT5665_PWR_HA_R				(0x1 << 4) +#define RT5665_PWR_HA_R_BIT			4 +#define RT5665_HP_DRIVER_MASK			(0x3 << 2) +#define RT5665_HP_DRIVER_1X			(0x0 << 2) +#define RT5665_HP_DRIVER_3X			(0x1 << 2) +#define RT5665_HP_DRIVER_5X			(0x2 << 2) +#define RT5665_LDO1_DVO_MASK			(0x3) +#define RT5665_LDO1_DVO_09			(0x0) +#define RT5665_LDO1_DVO_10			(0x1) +#define RT5665_LDO1_DVO_12			(0x2) +#define RT5665_LDO1_DVO_14			(0x3) + +/* Power Management for Analog 2 (0x0064) */ +#define RT5665_PWR_BST1				(0x1 << 15) +#define RT5665_PWR_BST1_BIT			15 +#define RT5665_PWR_BST2				(0x1 << 14) +#define RT5665_PWR_BST2_BIT			14 +#define RT5665_PWR_BST3				(0x1 << 13) +#define RT5665_PWR_BST3_BIT			13 +#define RT5665_PWR_BST4				(0x1 << 12) +#define RT5665_PWR_BST4_BIT			12 +#define RT5665_PWR_MB1				(0x1 << 11) +#define RT5665_PWR_MB1_PWR_DOWN			(0x0 << 11) +#define RT5665_PWR_MB1_BIT			11 +#define RT5665_PWR_MB2				(0x1 << 10) +#define RT5665_PWR_MB2_PWR_DOWN			(0x0 << 10) +#define RT5665_PWR_MB2_BIT			10 +#define RT5665_PWR_MB3				(0x1 << 9) +#define RT5665_PWR_MB3_BIT			9 +#define RT5665_PWR_BST1_P			(0x1 << 7) +#define RT5665_PWR_BST1_P_BIT			7 +#define RT5665_PWR_BST2_P			(0x1 << 6) +#define RT5665_PWR_BST2_P_BIT			6 +#define RT5665_PWR_BST3_P			(0x1 << 5) +#define RT5665_PWR_BST3_P_BIT			5 +#define RT5665_PWR_BST4_P			(0x1 << 4) +#define RT5665_PWR_BST4_P_BIT			4 +#define RT5665_PWR_JD1				(0x1 << 3) +#define RT5665_PWR_JD1_BIT			3 +#define RT5665_PWR_JD2				(0x1 << 2) +#define RT5665_PWR_JD2_BIT			2 +#define RT5665_PWR_RM1_L			(0x1 << 1) +#define RT5665_PWR_RM1_L_BIT			1 +#define RT5665_PWR_RM1_R			(0x1) +#define RT5665_PWR_RM1_R_BIT			0 + +/* Power Management for Analog 3 (0x0065) */ +#define RT5665_PWR_CBJ				(0x1 << 9) +#define RT5665_PWR_CBJ_BIT			9 +#define RT5665_PWR_BST_L			(0x1 << 8) +#define RT5665_PWR_BST_L_BIT			8 +#define RT5665_PWR_BST_R			(0x1 << 7) +#define RT5665_PWR_BST_R_BIT			7 +#define RT5665_PWR_PLL				(0x1 << 6) +#define RT5665_PWR_PLL_BIT			6 +#define RT5665_PWR_LDO2				(0x1 << 2) +#define RT5665_PWR_LDO2_BIT			2 +#define RT5665_PWR_SVD				(0x1 << 1) +#define RT5665_PWR_SVD_BIT			1 + +/* Power Management for Mixer (0x0066) */ +#define RT5665_PWR_RM2_L			(0x1 << 15) +#define RT5665_PWR_RM2_L_BIT			15 +#define RT5665_PWR_RM2_R			(0x1 << 14) +#define RT5665_PWR_RM2_R_BIT			14 +#define RT5665_PWR_OM_L				(0x1 << 13) +#define RT5665_PWR_OM_L_BIT			13 +#define RT5665_PWR_OM_R				(0x1 << 12) +#define RT5665_PWR_OM_R_BIT			12 +#define RT5665_PWR_MM				(0x1 << 11) +#define RT5665_PWR_MM_BIT			11 +#define RT5665_PWR_AEC_REF			(0x1 << 6) +#define RT5665_PWR_AEC_REF_BIT			6 +#define RT5665_PWR_STO1_DAC_L			(0x1 << 5) +#define RT5665_PWR_STO1_DAC_L_BIT		5 +#define RT5665_PWR_STO1_DAC_R			(0x1 << 4) +#define RT5665_PWR_STO1_DAC_R_BIT		4 +#define RT5665_PWR_MONO_DAC_L			(0x1 << 3) +#define RT5665_PWR_MONO_DAC_L_BIT		3 +#define RT5665_PWR_MONO_DAC_R			(0x1 << 2) +#define RT5665_PWR_MONO_DAC_R_BIT		2 +#define RT5665_PWR_STO2_DAC_L			(0x1 << 1) +#define RT5665_PWR_STO2_DAC_L_BIT		1 +#define RT5665_PWR_STO2_DAC_R			(0x1) +#define RT5665_PWR_STO2_DAC_R_BIT		0 + +/* Power Management for Volume (0x0067) */ +#define RT5665_PWR_OV_L				(0x1 << 13) +#define RT5665_PWR_OV_L_BIT			13 +#define RT5665_PWR_OV_R				(0x1 << 12) +#define RT5665_PWR_OV_R_BIT			12 +#define RT5665_PWR_IN_L				(0x1 << 9) +#define RT5665_PWR_IN_L_BIT			9 +#define RT5665_PWR_IN_R				(0x1 << 8) +#define RT5665_PWR_IN_R_BIT			8 +#define RT5665_PWR_MV				(0x1 << 7) +#define RT5665_PWR_MV_BIT			7 +#define RT5665_PWR_MIC_DET			(0x1 << 5) +#define RT5665_PWR_MIC_DET_BIT			5 + +/* (0x006b) */ +#define RT5665_SYS_CLK_DET			15 +#define RT5665_HP_CLK_DET			14 +#define RT5665_MONO_CLK_DET			13 +#define RT5665_LOUT_CLK_DET			12 +#define RT5665_POW_CLK_DET			0 + +/* Digital Microphone Control 1 (0x006e) */ +#define RT5665_DMIC_1_EN_MASK			(0x1 << 15) +#define RT5665_DMIC_1_EN_SFT			15 +#define RT5665_DMIC_1_DIS			(0x0 << 15) +#define RT5665_DMIC_1_EN			(0x1 << 15) +#define RT5665_DMIC_2_EN_MASK			(0x1 << 14) +#define RT5665_DMIC_2_EN_SFT			14 +#define RT5665_DMIC_2_DIS			(0x0 << 14) +#define RT5665_DMIC_2_EN			(0x1 << 14) +#define RT5665_DMIC_2_DP_MASK			(0x1 << 9) +#define RT5665_DMIC_2_DP_SFT			9 +#define RT5665_DMIC_2_DP_GPIO5			(0x0 << 9) +#define RT5665_DMIC_2_DP_IN2P			(0x1 << 9) +#define RT5665_DMIC_CLK_MASK			(0x7 << 5) +#define RT5665_DMIC_CLK_SFT			5 +#define RT5665_DMIC_1_DP_MASK			(0x1 << 1) +#define RT5665_DMIC_1_DP_SFT			1 +#define RT5665_DMIC_1_DP_GPIO4			(0x0 << 1) +#define RT5665_DMIC_1_DP_IN2N			(0x1 << 1) + + +/* Digital Microphone Control 1 (0x006f) */ +#define RT5665_DMIC_2L_LH_MASK			(0x1 << 3) +#define RT5665_DMIC_2L_LH_SFT			3 +#define RT5665_DMIC_2L_LH_RISING		(0x0 << 3) +#define RT5665_DMIC_2L_LH_FALLING		(0x1 << 3) +#define RT5665_DMIC_2R_LH_MASK			(0x1 << 2) +#define RT5665_DMIC_2R_LH_SFT			2 +#define RT5665_DMIC_2R_LH_RISING		(0x0 << 2) +#define RT5665_DMIC_2R_LH_FALLING		(0x1 << 2) +#define RT5665_DMIC_1L_LH_MASK			(0x1 << 1) +#define RT5665_DMIC_1L_LH_SFT			1 +#define RT5665_DMIC_1L_LH_RISING		(0x0 << 1) +#define RT5665_DMIC_1L_LH_FALLING		(0x1 << 1) +#define RT5665_DMIC_1R_LH_MASK			(0x1 << 0) +#define RT5665_DMIC_1R_LH_SFT			0 +#define RT5665_DMIC_1R_LH_RISING		(0x0) +#define RT5665_DMIC_1R_LH_FALLING		(0x1) + +/* I2S1/2/3 Audio Serial Data Port Control (0x0070 0x0071 0x0072) */ +#define RT5665_I2S_MS_MASK			(0x1 << 15) +#define RT5665_I2S_MS_SFT			15 +#define RT5665_I2S_MS_M				(0x0 << 15) +#define RT5665_I2S_MS_S				(0x1 << 15) +#define RT5665_I2S_PIN_CFG_MASK			(0x1 << 14) +#define RT5665_I2S_PIN_CFG_SFT			14 +#define RT5665_I2S_CLK_SEL_MASK			(0x1 << 11) +#define RT5665_I2S_CLK_SEL_SFT			11 +#define RT5665_I2S_BP_MASK			(0x1 << 8) +#define RT5665_I2S_BP_SFT			8 +#define RT5665_I2S_BP_NOR			(0x0 << 8) +#define RT5665_I2S_BP_INV			(0x1 << 8) +#define RT5665_I2S_DL_MASK			(0x3 << 4) +#define RT5665_I2S_DL_SFT			4 +#define RT5665_I2S_DL_16			(0x0 << 4) +#define RT5665_I2S_DL_20			(0x1 << 4) +#define RT5665_I2S_DL_24			(0x2 << 4) +#define RT5665_I2S_DL_8				(0x3 << 4) +#define RT5665_I2S_DF_MASK			(0x7) +#define RT5665_I2S_DF_SFT			0 +#define RT5665_I2S_DF_I2S			(0x0) +#define RT5665_I2S_DF_LEFT			(0x1) +#define RT5665_I2S_DF_PCM_A			(0x2) +#define RT5665_I2S_DF_PCM_B			(0x3) +#define RT5665_I2S_DF_PCM_A_N			(0x6) +#define RT5665_I2S_DF_PCM_B_N			(0x7) + +/* ADC/DAC Clock Control 1 (0x0073) */ +#define RT5665_I2S_PD1_MASK			(0x7 << 12) +#define RT5665_I2S_PD1_SFT			12 +#define RT5665_I2S_PD1_1			(0x0 << 12) +#define RT5665_I2S_PD1_2			(0x1 << 12) +#define RT5665_I2S_PD1_3			(0x2 << 12) +#define RT5665_I2S_PD1_4			(0x3 << 12) +#define RT5665_I2S_PD1_6			(0x4 << 12) +#define RT5665_I2S_PD1_8			(0x5 << 12) +#define RT5665_I2S_PD1_12			(0x6 << 12) +#define RT5665_I2S_PD1_16			(0x7 << 12) +#define RT5665_I2S_M_PD2_MASK			(0x7 << 8) +#define RT5665_I2S_M_PD2_SFT			8 +#define RT5665_I2S_M_PD2_1			(0x0 << 8) +#define RT5665_I2S_M_PD2_2			(0x1 << 8) +#define RT5665_I2S_M_PD2_3			(0x2 << 8) +#define RT5665_I2S_M_PD2_4			(0x3 << 8) +#define RT5665_I2S_M_PD2_6			(0x4 << 8) +#define RT5665_I2S_M_PD2_8			(0x5 << 8) +#define RT5665_I2S_M_PD2_12			(0x6 << 8) +#define RT5665_I2S_M_PD2_16			(0x7 << 8) +#define RT5665_I2S_CLK_SRC_MASK			(0x3 << 4) +#define RT5665_I2S_CLK_SRC_SFT			4 +#define RT5665_I2S_CLK_SRC_MCLK			(0x0 << 4) +#define RT5665_I2S_CLK_SRC_PLL1			(0x1 << 4) +#define RT5665_I2S_CLK_SRC_RCCLK		(0x2 << 4) +#define RT5665_DAC_OSR_MASK			(0x3 << 2) +#define RT5665_DAC_OSR_SFT			2 +#define RT5665_DAC_OSR_128			(0x0 << 2) +#define RT5665_DAC_OSR_64			(0x1 << 2) +#define RT5665_DAC_OSR_32			(0x2 << 2) +#define RT5665_ADC_OSR_MASK			(0x3) +#define RT5665_ADC_OSR_SFT			0 +#define RT5665_ADC_OSR_128			(0x0) +#define RT5665_ADC_OSR_64			(0x1) +#define RT5665_ADC_OSR_32			(0x2) + +/* ADC/DAC Clock Control 2 (0x0074) */ +#define RT5665_I2S_BCLK_MS2_MASK		(0x1 << 15) +#define RT5665_I2S_BCLK_MS2_SFT			15 +#define RT5665_I2S_BCLK_MS2_32			(0x0 << 15) +#define RT5665_I2S_BCLK_MS2_64			(0x1 << 15) +#define RT5665_I2S_PD2_MASK			(0x7 << 12) +#define RT5665_I2S_PD2_SFT			12 +#define RT5665_I2S_PD2_1			(0x0 << 12) +#define RT5665_I2S_PD2_2			(0x1 << 12) +#define RT5665_I2S_PD2_3			(0x2 << 12) +#define RT5665_I2S_PD2_4			(0x3 << 12) +#define RT5665_I2S_PD2_6			(0x4 << 12) +#define RT5665_I2S_PD2_8			(0x5 << 12) +#define RT5665_I2S_PD2_12			(0x6 << 12) +#define RT5665_I2S_PD2_16			(0x7 << 12) +#define RT5665_I2S_BCLK_MS3_MASK		(0x1 << 11) +#define RT5665_I2S_BCLK_MS3_SFT			11 +#define RT5665_I2S_BCLK_MS3_32			(0x0 << 11) +#define RT5665_I2S_BCLK_MS3_64			(0x1 << 11) +#define RT5665_I2S_PD3_MASK			(0x7 << 8) +#define RT5665_I2S_PD3_SFT			8 +#define RT5665_I2S_PD3_1			(0x0 << 8) +#define RT5665_I2S_PD3_2			(0x1 << 8) +#define RT5665_I2S_PD3_3			(0x2 << 8) +#define RT5665_I2S_PD3_4			(0x3 << 8) +#define RT5665_I2S_PD3_6			(0x4 << 8) +#define RT5665_I2S_PD3_8			(0x5 << 8) +#define RT5665_I2S_PD3_12			(0x6 << 8) +#define RT5665_I2S_PD3_16			(0x7 << 8) +#define RT5665_I2S_PD4_MASK			(0x7 << 4) +#define RT5665_I2S_PD4_SFT			4 +#define RT5665_I2S_PD4_1			(0x0 << 4) +#define RT5665_I2S_PD4_2			(0x1 << 4) +#define RT5665_I2S_PD4_3			(0x2 << 4) +#define RT5665_I2S_PD4_4			(0x3 << 4) +#define RT5665_I2S_PD4_6			(0x4 << 4) +#define RT5665_I2S_PD4_8			(0x5 << 4) +#define RT5665_I2S_PD4_12			(0x6 << 4) +#define RT5665_I2S_PD4_16			(0x7 << 4) + +/* TDM control 1 (0x0078) */ +#define RT5665_I2S1_MODE_MASK			(0x1 << 15) +#define RT5665_I2S1_MODE_I2S			(0x0 << 15) +#define RT5665_I2S1_MODE_TDM			(0x1 << 15) +#define RT5665_TDM_IN_CH_MASK			(0x3 << 10) +#define RT5665_TDM_IN_CH_2			(0x0 << 10) +#define RT5665_TDM_IN_CH_4			(0x1 << 10) +#define RT5665_TDM_IN_CH_6			(0x2 << 10) +#define RT5665_TDM_IN_CH_8			(0x3 << 10) +#define RT5665_TDM_OUT_CH_MASK			(0x3 << 8) +#define RT5665_TDM_OUT_CH_2			(0x0 << 8) +#define RT5665_TDM_OUT_CH_4			(0x1 << 8) +#define RT5665_TDM_OUT_CH_6			(0x2 << 8) +#define RT5665_TDM_OUT_CH_8			(0x3 << 8) +#define RT5665_TDM_IN_LEN_MASK			(0x3 << 6) +#define RT5665_TDM_IN_LEN_16			(0x0 << 6) +#define RT5665_TDM_IN_LEN_20			(0x1 << 6) +#define RT5665_TDM_IN_LEN_24			(0x2 << 6) +#define RT5665_TDM_IN_LEN_32			(0x3 << 6) +#define RT5665_TDM_OUT_LEN_MASK			(0x3 << 4) +#define RT5665_TDM_OUT_LEN_16			(0x0 << 4) +#define RT5665_TDM_OUT_LEN_20			(0x1 << 4) +#define RT5665_TDM_OUT_LEN_24			(0x2 << 4) +#define RT5665_TDM_OUT_LEN_32			(0x3 << 4) + + +/* TDM control 2 (0x0079) */ +#define RT5665_I2S1_1_DS_ADC_SLOT01_SFT		14 +#define RT5665_I2S1_1_DS_ADC_SLOT23_SFT		12 +#define RT5665_I2S1_1_DS_ADC_SLOT45_SFT		10 +#define RT5665_I2S1_1_DS_ADC_SLOT67_SFT		8 +#define RT5665_I2S1_2_DS_ADC_SLOT01_SFT		6 +#define RT5665_I2S1_2_DS_ADC_SLOT23_SFT		4 +#define RT5665_I2S1_2_DS_ADC_SLOT45_SFT		2 +#define RT5665_I2S1_2_DS_ADC_SLOT67_SFT		0 + +/* TDM control 3/4 (0x007a) (0x007b) */ +#define RT5665_IF1_ADC1_SEL_SFT			10 +#define RT5665_IF1_ADC2_SEL_SFT			9 +#define RT5665_IF1_ADC3_SEL_SFT			8 +#define RT5665_IF1_ADC4_SEL_SFT			7 +#define RT5665_TDM_ADC_SEL_SFT			0 +#define RT5665_TDM_ADC_CTRL_MASK		(0x1f << 0) +#define RT5665_TDM_ADC_DATA_06			(0x6 << 0) + +/* Global Clock Control (0x0080) */ +#define RT5665_SCLK_SRC_MASK			(0x3 << 14) +#define RT5665_SCLK_SRC_SFT			14 +#define RT5665_SCLK_SRC_MCLK			(0x0 << 14) +#define RT5665_SCLK_SRC_PLL1			(0x1 << 14) +#define RT5665_SCLK_SRC_RCCLK			(0x2 << 14) +#define RT5665_PLL1_SRC_MASK			(0x7 << 8) +#define RT5665_PLL1_SRC_SFT			8 +#define RT5665_PLL1_SRC_MCLK			(0x0 << 8) +#define RT5665_PLL1_SRC_BCLK1			(0x1 << 8) +#define RT5665_PLL1_SRC_BCLK2			(0x2 << 8) +#define RT5665_PLL1_SRC_BCLK3			(0x3 << 8) +#define RT5665_PLL1_PD_MASK			(0x7 << 4) +#define RT5665_PLL1_PD_SFT			4 + + +#define RT5665_PLL_INP_MAX			40000000 +#define RT5665_PLL_INP_MIN			256000 +/* PLL M/N/K Code Control 1 (0x0081) */ +#define RT5665_PLL_N_MAX			0x001ff +#define RT5665_PLL_N_MASK			(RT5665_PLL_N_MAX << 7) +#define RT5665_PLL_N_SFT			7 +#define RT5665_PLL_K_MAX			0x001f +#define RT5665_PLL_K_MASK			(RT5665_PLL_K_MAX) +#define RT5665_PLL_K_SFT			0 + +/* PLL M/N/K Code Control 2 (0x0082) */ +#define RT5665_PLL_M_MAX			0x00f +#define RT5665_PLL_M_MASK			(RT5665_PLL_M_MAX << 12) +#define RT5665_PLL_M_SFT			12 +#define RT5665_PLL_M_BP				(0x1 << 11) +#define RT5665_PLL_M_BP_SFT			11 +#define RT5665_PLL_K_BP				(0x1 << 10) +#define RT5665_PLL_K_BP_SFT			10 + +/* PLL tracking mode 1 (0x0083) */ +#define RT5665_I2S3_ASRC_MASK			(0x1 << 15) +#define RT5665_I2S3_ASRC_SFT			15 +#define RT5665_I2S2_ASRC_MASK			(0x1 << 14) +#define RT5665_I2S2_ASRC_SFT			14 +#define RT5665_I2S1_ASRC_MASK			(0x1 << 13) +#define RT5665_I2S1_ASRC_SFT			13 +#define RT5665_DAC_STO1_ASRC_MASK		(0x1 << 12) +#define RT5665_DAC_STO1_ASRC_SFT		12 +#define RT5665_DAC_STO2_ASRC_MASK		(0x1 << 11) +#define RT5665_DAC_STO2_ASRC_SFT		11 +#define RT5665_DAC_MONO_L_ASRC_MASK		(0x1 << 10) +#define RT5665_DAC_MONO_L_ASRC_SFT		10 +#define RT5665_DAC_MONO_R_ASRC_MASK		(0x1 << 9) +#define RT5665_DAC_MONO_R_ASRC_SFT		9 +#define RT5665_DMIC_STO1_ASRC_MASK		(0x1 << 8) +#define RT5665_DMIC_STO1_ASRC_SFT		8 +#define RT5665_DMIC_STO2_ASRC_MASK		(0x1 << 7) +#define RT5665_DMIC_STO2_ASRC_SFT		7 +#define RT5665_DMIC_MONO_L_ASRC_MASK		(0x1 << 6) +#define RT5665_DMIC_MONO_L_ASRC_SFT		6 +#define RT5665_DMIC_MONO_R_ASRC_MASK		(0x1 << 5) +#define RT5665_DMIC_MONO_R_ASRC_SFT		5 +#define RT5665_ADC_STO1_ASRC_MASK		(0x1 << 4) +#define RT5665_ADC_STO1_ASRC_SFT		4 +#define RT5665_ADC_STO2_ASRC_MASK		(0x1 << 3) +#define RT5665_ADC_STO2_ASRC_SFT		3 +#define RT5665_ADC_MONO_L_ASRC_MASK		(0x1 << 2) +#define RT5665_ADC_MONO_L_ASRC_SFT		2 +#define RT5665_ADC_MONO_R_ASRC_MASK		(0x1 << 1) +#define RT5665_ADC_MONO_R_ASRC_SFT		1 + +/* PLL tracking mode 2 (0x0084)*/ +#define RT5665_DA_STO1_CLK_SEL_MASK		(0x7 << 12) +#define RT5665_DA_STO1_CLK_SEL_SFT		12 +#define RT5665_DA_STO2_CLK_SEL_MASK		(0x7 << 8) +#define RT5665_DA_STO2_CLK_SEL_SFT		8 +#define RT5665_DA_MONOL_CLK_SEL_MASK		(0x7 << 4) +#define RT5665_DA_MONOL_CLK_SEL_SFT		4 +#define RT5665_DA_MONOR_CLK_SEL_MASK		(0x7) +#define RT5665_DA_MONOR_CLK_SEL_SFT		0 + +/* PLL tracking mode 3 (0x0085)*/ +#define RT5665_AD_STO1_CLK_SEL_MASK		(0x7 << 12) +#define RT5665_AD_STO1_CLK_SEL_SFT		12 +#define RT5665_AD_STO2_CLK_SEL_MASK		(0x7 << 8) +#define RT5665_AD_STO2_CLK_SEL_SFT		8 +#define RT5665_AD_MONOL_CLK_SEL_MASK		(0x7 << 4) +#define RT5665_AD_MONOL_CLK_SEL_SFT		4 +#define RT5665_AD_MONOR_CLK_SEL_MASK		(0x7) +#define RT5665_AD_MONOR_CLK_SEL_SFT		0 + +/* ASRC Control 4 (0x0086) */ +#define RT5665_I2S1_RATE_MASK			(0xf << 12) +#define RT5665_I2S1_RATE_SFT			12 +#define RT5665_I2S2_RATE_MASK			(0xf << 8) +#define RT5665_I2S2_RATE_SFT			8 +#define RT5665_I2S3_RATE_MASK			(0xf << 4) +#define RT5665_I2S3_RATE_SFT			4 + +/* Depop Mode Control 1 (0x008e) */ +#define RT5665_PUMP_EN				(0x1 << 3) + +/* Depop Mode Control 2 (0x8f) */ +#define RT5665_DEPOP_MASK			(0x1 << 13) +#define RT5665_DEPOP_SFT			13 +#define RT5665_DEPOP_AUTO			(0x0 << 13) +#define RT5665_DEPOP_MAN			(0x1 << 13) +#define RT5665_RAMP_MASK			(0x1 << 12) +#define RT5665_RAMP_SFT				12 +#define RT5665_RAMP_DIS				(0x0 << 12) +#define RT5665_RAMP_EN				(0x1 << 12) +#define RT5665_BPS_MASK				(0x1 << 11) +#define RT5665_BPS_SFT				11 +#define RT5665_BPS_DIS				(0x0 << 11) +#define RT5665_BPS_EN				(0x1 << 11) +#define RT5665_FAST_UPDN_MASK			(0x1 << 10) +#define RT5665_FAST_UPDN_SFT			10 +#define RT5665_FAST_UPDN_DIS			(0x0 << 10) +#define RT5665_FAST_UPDN_EN			(0x1 << 10) +#define RT5665_MRES_MASK			(0x3 << 8) +#define RT5665_MRES_SFT				8 +#define RT5665_MRES_15MO			(0x0 << 8) +#define RT5665_MRES_25MO			(0x1 << 8) +#define RT5665_MRES_35MO			(0x2 << 8) +#define RT5665_MRES_45MO			(0x3 << 8) +#define RT5665_VLO_MASK				(0x1 << 7) +#define RT5665_VLO_SFT				7 +#define RT5665_VLO_3V				(0x0 << 7) +#define RT5665_VLO_32V				(0x1 << 7) +#define RT5665_DIG_DP_MASK			(0x1 << 6) +#define RT5665_DIG_DP_SFT			6 +#define RT5665_DIG_DP_DIS			(0x0 << 6) +#define RT5665_DIG_DP_EN			(0x1 << 6) +#define RT5665_DP_TH_MASK			(0x3 << 4) +#define RT5665_DP_TH_SFT			4 + +/* Depop Mode Control 3 (0x90) */ +#define RT5665_CP_SYS_MASK			(0x7 << 12) +#define RT5665_CP_SYS_SFT			12 +#define RT5665_CP_FQ1_MASK			(0x7 << 8) +#define RT5665_CP_FQ1_SFT			8 +#define RT5665_CP_FQ2_MASK			(0x7 << 4) +#define RT5665_CP_FQ2_SFT			4 +#define RT5665_CP_FQ3_MASK			(0x7) +#define RT5665_CP_FQ3_SFT			0 +#define RT5665_CP_FQ_1_5_KHZ			0 +#define RT5665_CP_FQ_3_KHZ			1 +#define RT5665_CP_FQ_6_KHZ			2 +#define RT5665_CP_FQ_12_KHZ			3 +#define RT5665_CP_FQ_24_KHZ			4 +#define RT5665_CP_FQ_48_KHZ			5 +#define RT5665_CP_FQ_96_KHZ			6 +#define RT5665_CP_FQ_192_KHZ			7 + +/* HPOUT charge pump 1 (0x0091) */ +#define RT5665_OSW_L_MASK			(0x1 << 11) +#define RT5665_OSW_L_SFT			11 +#define RT5665_OSW_L_DIS			(0x0 << 11) +#define RT5665_OSW_L_EN				(0x1 << 11) +#define RT5665_OSW_R_MASK			(0x1 << 10) +#define RT5665_OSW_R_SFT			10 +#define RT5665_OSW_R_DIS			(0x0 << 10) +#define RT5665_OSW_R_EN				(0x1 << 10) +#define RT5665_PM_HP_MASK			(0x3 << 8) +#define RT5665_PM_HP_SFT			8 +#define RT5665_PM_HP_LV				(0x0 << 8) +#define RT5665_PM_HP_MV				(0x1 << 8) +#define RT5665_PM_HP_HV				(0x2 << 8) +#define RT5665_IB_HP_MASK			(0x3 << 6) +#define RT5665_IB_HP_SFT			6 +#define RT5665_IB_HP_125IL			(0x0 << 6) +#define RT5665_IB_HP_25IL			(0x1 << 6) +#define RT5665_IB_HP_5IL			(0x2 << 6) +#define RT5665_IB_HP_1IL			(0x3 << 6) + +/* PV detection and SPK gain control (0x92) */ +#define RT5665_PVDD_DET_MASK			(0x1 << 15) +#define RT5665_PVDD_DET_SFT			15 +#define RT5665_PVDD_DET_DIS			(0x0 << 15) +#define RT5665_PVDD_DET_EN			(0x1 << 15) +#define RT5665_SPK_AG_MASK			(0x1 << 14) +#define RT5665_SPK_AG_SFT			14 +#define RT5665_SPK_AG_DIS			(0x0 << 14) +#define RT5665_SPK_AG_EN			(0x1 << 14) + +/* Micbias Control1 (0x93) */ +#define RT5665_MIC1_BS_MASK			(0x1 << 15) +#define RT5665_MIC1_BS_SFT			15 +#define RT5665_MIC1_BS_9AV			(0x0 << 15) +#define RT5665_MIC1_BS_75AV			(0x1 << 15) +#define RT5665_MIC2_BS_MASK			(0x1 << 14) +#define RT5665_MIC2_BS_SFT			14 +#define RT5665_MIC2_BS_9AV			(0x0 << 14) +#define RT5665_MIC2_BS_75AV			(0x1 << 14) +#define RT5665_MIC1_CLK_MASK			(0x1 << 13) +#define RT5665_MIC1_CLK_SFT			13 +#define RT5665_MIC1_CLK_DIS			(0x0 << 13) +#define RT5665_MIC1_CLK_EN			(0x1 << 13) +#define RT5665_MIC2_CLK_MASK			(0x1 << 12) +#define RT5665_MIC2_CLK_SFT			12 +#define RT5665_MIC2_CLK_DIS			(0x0 << 12) +#define RT5665_MIC2_CLK_EN			(0x1 << 12) +#define RT5665_MIC1_OVCD_MASK			(0x1 << 11) +#define RT5665_MIC1_OVCD_SFT			11 +#define RT5665_MIC1_OVCD_DIS			(0x0 << 11) +#define RT5665_MIC1_OVCD_EN			(0x1 << 11) +#define RT5665_MIC1_OVTH_MASK			(0x3 << 9) +#define RT5665_MIC1_OVTH_SFT			9 +#define RT5665_MIC1_OVTH_600UA			(0x0 << 9) +#define RT5665_MIC1_OVTH_1500UA			(0x1 << 9) +#define RT5665_MIC1_OVTH_2000UA			(0x2 << 9) +#define RT5665_MIC2_OVCD_MASK			(0x1 << 8) +#define RT5665_MIC2_OVCD_SFT			8 +#define RT5665_MIC2_OVCD_DIS			(0x0 << 8) +#define RT5665_MIC2_OVCD_EN			(0x1 << 8) +#define RT5665_MIC2_OVTH_MASK			(0x3 << 6) +#define RT5665_MIC2_OVTH_SFT			6 +#define RT5665_MIC2_OVTH_600UA			(0x0 << 6) +#define RT5665_MIC2_OVTH_1500UA			(0x1 << 6) +#define RT5665_MIC2_OVTH_2000UA			(0x2 << 6) +#define RT5665_PWR_MB_MASK			(0x1 << 5) +#define RT5665_PWR_MB_SFT			5 +#define RT5665_PWR_MB_PD			(0x0 << 5) +#define RT5665_PWR_MB_PU			(0x1 << 5) + +/* Micbias Control2 (0x94) */ +#define RT5665_PWR_CLK25M_MASK			(0x1 << 9) +#define RT5665_PWR_CLK25M_SFT			9 +#define RT5665_PWR_CLK25M_PD			(0x0 << 9) +#define RT5665_PWR_CLK25M_PU			(0x1 << 9) +#define RT5665_PWR_CLK1M_MASK			(0x1 << 8) +#define RT5665_PWR_CLK1M_SFT			8 +#define RT5665_PWR_CLK1M_PD			(0x0 << 8) +#define RT5665_PWR_CLK1M_PU			(0x1 << 8) + + +/* EQ Control 1 (0x00b0) */ +#define RT5665_EQ_SRC_DAC			(0x0 << 15) +#define RT5665_EQ_SRC_ADC			(0x1 << 15) +#define RT5665_EQ_UPD				(0x1 << 14) +#define RT5665_EQ_UPD_BIT			14 +#define RT5665_EQ_CD_MASK			(0x1 << 13) +#define RT5665_EQ_CD_SFT			13 +#define RT5665_EQ_CD_DIS			(0x0 << 13) +#define RT5665_EQ_CD_EN				(0x1 << 13) +#define RT5665_EQ_DITH_MASK			(0x3 << 8) +#define RT5665_EQ_DITH_SFT			8 +#define RT5665_EQ_DITH_NOR			(0x0 << 8) +#define RT5665_EQ_DITH_LSB			(0x1 << 8) +#define RT5665_EQ_DITH_LSB_1			(0x2 << 8) +#define RT5665_EQ_DITH_LSB_2			(0x3 << 8) + +/* IRQ Control 1 (0x00b7) */ +#define RT5665_JD1_1_EN_MASK			(0x1 << 15) +#define RT5665_JD1_1_EN_SFT			15 +#define RT5665_JD1_1_DIS			(0x0 << 15) +#define RT5665_JD1_1_EN				(0x1 << 15) +#define RT5665_JD1_2_EN_MASK			(0x1 << 12) +#define RT5665_JD1_2_EN_SFT			12 +#define RT5665_JD1_2_DIS			(0x0 << 12) +#define RT5665_JD1_2_EN				(0x1 << 12) + +/* IRQ Control 2 (0x00b8) */ +#define RT5665_IL_IRQ_MASK			(0x1 << 6) +#define RT5665_IL_IRQ_DIS			(0x0 << 6) +#define RT5665_IL_IRQ_EN			(0x1 << 6) + +/* IRQ Control 5 (0x00ba) */ +#define RT5665_IRQ_JD_EN			(0x1 << 3) +#define RT5665_IRQ_JD_EN_SFT			3 + +/* GPIO Control 1 (0x00c0) */ +#define RT5665_GP1_PIN_MASK			(0x1 << 15) +#define RT5665_GP1_PIN_SFT			15 +#define RT5665_GP1_PIN_GPIO1			(0x0 << 15) +#define RT5665_GP1_PIN_IRQ			(0x1 << 15) +#define RT5665_GP2_PIN_MASK			(0x3 << 13) +#define RT5665_GP2_PIN_SFT			13 +#define RT5665_GP2_PIN_GPIO2			(0x0 << 13) +#define RT5665_GP2_PIN_BCLK2			(0x1 << 13) +#define RT5665_GP2_PIN_PDM_SCL			(0x2 << 13) +#define RT5665_GP3_PIN_MASK			(0x3 << 11) +#define RT5665_GP3_PIN_SFT			11 +#define RT5665_GP3_PIN_GPIO3			(0x0 << 11) +#define RT5665_GP3_PIN_LRCK2			(0x1 << 11) +#define RT5665_GP3_PIN_PDM_SDA			(0x2 << 11) +#define RT5665_GP4_PIN_MASK			(0x3 << 9) +#define RT5665_GP4_PIN_SFT			9 +#define RT5665_GP4_PIN_GPIO4			(0x0 << 9) +#define RT5665_GP4_PIN_DACDAT2_1		(0x1 << 9) +#define RT5665_GP4_PIN_DMIC1_SDA		(0x2 << 9) +#define RT5665_GP5_PIN_MASK			(0x3 << 7) +#define RT5665_GP5_PIN_SFT			7 +#define RT5665_GP5_PIN_GPIO5			(0x0 << 7) +#define RT5665_GP5_PIN_ADCDAT2_1		(0x1 << 7) +#define RT5665_GP5_PIN_DMIC2_SDA		(0x2 << 7) +#define RT5665_GP6_PIN_MASK			(0x3 << 5) +#define RT5665_GP6_PIN_SFT			5 +#define RT5665_GP6_PIN_GPIO6			(0x0 << 5) +#define RT5665_GP6_PIN_BCLK3			(0x0 << 5) +#define RT5665_GP6_PIN_PDM_SCL			(0x1 << 5) +#define RT5665_GP7_PIN_MASK			(0x3 << 3) +#define RT5665_GP7_PIN_SFT			3 +#define RT5665_GP7_PIN_GPIO7			(0x0 << 3) +#define RT5665_GP7_PIN_LRCK3			(0x1 << 3) +#define RT5665_GP7_PIN_PDM_SDA			(0x2 << 3) +#define RT5665_GP8_PIN_MASK			(0x3 << 1) +#define RT5665_GP8_PIN_SFT			1 +#define RT5665_GP8_PIN_GPIO8			(0x0 << 1) +#define RT5665_GP8_PIN_DACDAT3			(0x1 << 1) +#define RT5665_GP8_PIN_DMIC2_SCL		(0x2 << 1) +#define RT5665_GP8_PIN_DACDAT2_2		(0x3 << 1) + + +/* GPIO Control 2 (0x00c1)*/ +#define RT5665_GP9_PIN_MASK			(0x3 << 14) +#define RT5665_GP9_PIN_SFT			14 +#define RT5665_GP9_PIN_GPIO9			(0x0 << 14) +#define RT5665_GP9_PIN_ADCDAT3			(0x1 << 14) +#define RT5665_GP9_PIN_DMIC1_SCL		(0x2 << 14) +#define RT5665_GP9_PIN_ADCDAT2_2		(0x3 << 14) +#define RT5665_GP10_PIN_MASK			(0x3 << 12) +#define RT5665_GP10_PIN_SFT			12 +#define RT5665_GP10_PIN_GPIO10			(0x0 << 12) +#define RT5665_GP10_PIN_ADCDAT1_2		(0x1 << 12) +#define RT5665_GP10_PIN_LPD			(0x2 << 12) +#define RT5665_GP1_PF_MASK			(0x1 << 11) +#define RT5665_GP1_PF_IN			(0x0 << 11) +#define RT5665_GP1_PF_OUT			(0x1 << 11) +#define RT5665_GP1_OUT_MASK			(0x1 << 10) +#define RT5665_GP1_OUT_H			(0x0 << 10) +#define RT5665_GP1_OUT_L			(0x1 << 10) +#define RT5665_GP2_PF_MASK			(0x1 << 9) +#define RT5665_GP2_PF_IN			(0x0 << 9) +#define RT5665_GP2_PF_OUT			(0x1 << 9) +#define RT5665_GP2_OUT_MASK			(0x1 << 8) +#define RT5665_GP2_OUT_H			(0x0 << 8) +#define RT5665_GP2_OUT_L			(0x1 << 8) +#define RT5665_GP3_PF_MASK			(0x1 << 7) +#define RT5665_GP3_PF_IN			(0x0 << 7) +#define RT5665_GP3_PF_OUT			(0x1 << 7) +#define RT5665_GP3_OUT_MASK			(0x1 << 6) +#define RT5665_GP3_OUT_H			(0x0 << 6) +#define RT5665_GP3_OUT_L			(0x1 << 6) +#define RT5665_GP4_PF_MASK			(0x1 << 5) +#define RT5665_GP4_PF_IN			(0x0 << 5) +#define RT5665_GP4_PF_OUT			(0x1 << 5) +#define RT5665_GP4_OUT_MASK			(0x1 << 4) +#define RT5665_GP4_OUT_H			(0x0 << 4) +#define RT5665_GP4_OUT_L			(0x1 << 4) +#define RT5665_GP5_PF_MASK			(0x1 << 3) +#define RT5665_GP5_PF_IN			(0x0 << 3) +#define RT5665_GP5_PF_OUT			(0x1 << 3) +#define RT5665_GP5_OUT_MASK			(0x1 << 2) +#define RT5665_GP5_OUT_H			(0x0 << 2) +#define RT5665_GP5_OUT_L			(0x1 << 2) +#define RT5665_GP6_PF_MASK			(0x1 << 1) +#define RT5665_GP6_PF_IN			(0x0 << 1) +#define RT5665_GP6_PF_OUT			(0x1 << 1) +#define RT5665_GP6_OUT_MASK			(0x1) +#define RT5665_GP6_OUT_H			(0x0) +#define RT5665_GP6_OUT_L			(0x1) + + +/* GPIO Control 3 (0x00c2) */ +#define RT5665_GP7_PF_MASK			(0x1 << 15) +#define RT5665_GP7_PF_IN			(0x0 << 15) +#define RT5665_GP7_PF_OUT			(0x1 << 15) +#define RT5665_GP7_OUT_MASK			(0x1 << 14) +#define RT5665_GP7_OUT_H			(0x0 << 14) +#define RT5665_GP7_OUT_L			(0x1 << 14) +#define RT5665_GP8_PF_MASK			(0x1 << 13) +#define RT5665_GP8_PF_IN			(0x0 << 13) +#define RT5665_GP8_PF_OUT			(0x1 << 13) +#define RT5665_GP8_OUT_MASK			(0x1 << 12) +#define RT5665_GP8_OUT_H			(0x0 << 12) +#define RT5665_GP8_OUT_L			(0x1 << 12) +#define RT5665_GP9_PF_MASK			(0x1 << 11) +#define RT5665_GP9_PF_IN			(0x0 << 11) +#define RT5665_GP9_PF_OUT			(0x1 << 11) +#define RT5665_GP9_OUT_MASK			(0x1 << 10) +#define RT5665_GP9_OUT_H			(0x0 << 10) +#define RT5665_GP9_OUT_L			(0x1 << 10) +#define RT5665_GP10_PF_MASK			(0x1 << 9) +#define RT5665_GP10_PF_IN			(0x0 << 9) +#define RT5665_GP10_PF_OUT			(0x1 << 9) +#define RT5665_GP10_OUT_MASK			(0x1 << 8) +#define RT5665_GP10_OUT_H			(0x0 << 8) +#define RT5665_GP10_OUT_L			(0x1 << 8) +#define RT5665_GP11_PF_MASK			(0x1 << 7) +#define RT5665_GP11_PF_IN			(0x0 << 7) +#define RT5665_GP11_PF_OUT			(0x1 << 7) +#define RT5665_GP11_OUT_MASK			(0x1 << 6) +#define RT5665_GP11_OUT_H			(0x0 << 6) +#define RT5665_GP11_OUT_L			(0x1 << 6) + +/* Soft volume and zero cross control 1 (0x00d9) */ +#define RT5665_SV_MASK				(0x1 << 15) +#define RT5665_SV_SFT				15 +#define RT5665_SV_DIS				(0x0 << 15) +#define RT5665_SV_EN				(0x1 << 15) +#define RT5665_OUT_SV_MASK			(0x1 << 13) +#define RT5665_OUT_SV_SFT			13 +#define RT5665_OUT_SV_DIS			(0x0 << 13) +#define RT5665_OUT_SV_EN			(0x1 << 13) +#define RT5665_HP_SV_MASK			(0x1 << 12) +#define RT5665_HP_SV_SFT			12 +#define RT5665_HP_SV_DIS			(0x0 << 12) +#define RT5665_HP_SV_EN				(0x1 << 12) +#define RT5665_ZCD_DIG_MASK			(0x1 << 11) +#define RT5665_ZCD_DIG_SFT			11 +#define RT5665_ZCD_DIG_DIS			(0x0 << 11) +#define RT5665_ZCD_DIG_EN			(0x1 << 11) +#define RT5665_ZCD_MASK				(0x1 << 10) +#define RT5665_ZCD_SFT				10 +#define RT5665_ZCD_PD				(0x0 << 10) +#define RT5665_ZCD_PU				(0x1 << 10) +#define RT5665_SV_DLY_MASK			(0xf) +#define RT5665_SV_DLY_SFT			0 + +/* Soft volume and zero cross control 2 (0x00da) */ +#define RT5665_ZCD_HP_MASK			(0x1 << 15) +#define RT5665_ZCD_HP_SFT			15 +#define RT5665_ZCD_HP_DIS			(0x0 << 15) +#define RT5665_ZCD_HP_EN			(0x1 << 15) + +/* 4 Button Inline Command Control 2 (0x00e0) */ +#define RT5665_4BTN_IL_MASK			(0x1 << 15) +#define RT5665_4BTN_IL_EN			(0x1 << 15) +#define RT5665_4BTN_IL_DIS			(0x0 << 15) +#define RT5665_4BTN_IL_RST_MASK			(0x1 << 14) +#define RT5665_4BTN_IL_NOR			(0x1 << 14) +#define RT5665_4BTN_IL_RST			(0x0 << 14) + +/* Analog JD Control 1 (0x00f0) */ +#define RT5665_JD1_MODE_MASK			(0x3 << 0) +#define RT5665_JD1_MODE_0			(0x0 << 0) +#define RT5665_JD1_MODE_1			(0x1 << 0) +#define RT5665_JD1_MODE_2			(0x2 << 0) + +/* Jack Detect Control 3 (0x00f8) */ +#define RT5665_JD_TRI_HPO_SEL_MASK		(0x7) +#define RT5665_JD_TRI_HPO_SEL_SFT		(0) +#define RT5665_JD_HPO_GPIO_JD1			(0x0) +#define RT5665_JD_HPO_JD1_1			(0x1) +#define RT5665_JD_HPO_JD1_2			(0x2) +#define RT5665_JD_HPO_JD2			(0x3) +#define RT5665_JD_HPO_GPIO_JD2			(0x4) +#define RT5665_JD_HPO_JD3			(0x5) +#define RT5665_JD_HPO_JD_D			(0x6) + +/* Digital Misc Control (0x00fa) */ +#define RT5665_AM_MASK				(0x1 << 7) +#define RT5665_AM_EN				(0x1 << 7) +#define RT5665_AM_DIS				(0x1 << 7) +#define RT5665_DIG_GATE_CTRL			0x1 +#define RT5665_DIG_GATE_CTRL_SFT		(0) + +/* Chopper and Clock control for ADC (0x011c)*/ +#define RT5665_M_RF_DIG_MASK			(0x1 << 12) +#define RT5665_M_RF_DIG_SFT			12 +#define RT5665_M_RI_DIG				(0x1 << 11) + +/* Chopper and Clock control for DAC (0x013a)*/ +#define RT5665_CKXEN_DAC1_MASK			(0x1 << 13) +#define RT5665_CKXEN_DAC1_SFT			13 +#define RT5665_CKGEN_DAC1_MASK			(0x1 << 12) +#define RT5665_CKGEN_DAC1_SFT			12 +#define RT5665_CKXEN_DAC2_MASK			(0x1 << 5) +#define RT5665_CKXEN_DAC2_SFT			5 +#define RT5665_CKGEN_DAC2_MASK			(0x1 << 4) +#define RT5665_CKGEN_DAC2_SFT			4 + +/* Chopper and Clock control for ADC (0x013b)*/ +#define RT5665_CKXEN_ADC1_MASK			(0x1 << 13) +#define RT5665_CKXEN_ADC1_SFT			13 +#define RT5665_CKGEN_ADC1_MASK			(0x1 << 12) +#define RT5665_CKGEN_ADC1_SFT			12 +#define RT5665_CKXEN_ADC2_MASK			(0x1 << 5) +#define RT5665_CKXEN_ADC2_SFT			5 +#define RT5665_CKGEN_ADC2_MASK			(0x1 << 4) +#define RT5665_CKGEN_ADC2_SFT			4 + +/* Volume test (0x013f)*/ +#define RT5665_SEL_CLK_VOL_MASK			(0x1 << 15) +#define RT5665_SEL_CLK_VOL_EN			(0x1 << 15) +#define RT5665_SEL_CLK_VOL_DIS			(0x0 << 15) + +/* Test Mode Control 1 (0x0145) */ +#define RT5665_AD2DA_LB_MASK			(0x1 << 9) +#define RT5665_AD2DA_LB_SFT			9 + +/* Stereo Noise Gate Control 1 (0x0160) */ +#define RT5665_NG2_EN_MASK			(0x1 << 15) +#define RT5665_NG2_EN				(0x1 << 15) +#define RT5665_NG2_DIS				(0x0 << 15) + +/* Stereo1 DAC Silence Detection Control (0x0190) */ +#define RT5665_DEB_STO_DAC_MASK			(0x7 << 4) +#define RT5665_DEB_80_MS			(0x0 << 4) + +/* SAR ADC Inline Command Control 1 (0x0210) */ +#define RT5665_SAR_BUTT_DET_MASK		(0x1 << 15) +#define RT5665_SAR_BUTT_DET_EN			(0x1 << 15) +#define RT5665_SAR_BUTT_DET_DIS			(0x0 << 15) +#define RT5665_SAR_BUTDET_MODE_MASK		(0x1 << 14) +#define RT5665_SAR_BUTDET_POW_SAV		(0x1 << 14) +#define RT5665_SAR_BUTDET_POW_NORM		(0x0 << 14) +#define RT5665_SAR_BUTDET_RST_MASK		(0x1 << 13) +#define RT5665_SAR_BUTDET_RST_NORMAL		(0x1 << 13) +#define RT5665_SAR_BUTDET_RST			(0x0 << 13) +#define RT5665_SAR_POW_MASK			(0x1 << 12) +#define RT5665_SAR_POW_EN			(0x1 << 12) +#define RT5665_SAR_POW_DIS			(0x0 << 12) +#define RT5665_SAR_RST_MASK			(0x1 << 11) +#define RT5665_SAR_RST_NORMAL			(0x1 << 11) +#define RT5665_SAR_RST				(0x0 << 11) +#define RT5665_SAR_BYPASS_MASK			(0x1 << 10) +#define RT5665_SAR_BYPASS_EN			(0x1 << 10) +#define RT5665_SAR_BYPASS_DIS			(0x0 << 10) +#define RT5665_SAR_SEL_MB1_MASK			(0x1 << 9) +#define RT5665_SAR_SEL_MB1_SEL			(0x1 << 9) +#define RT5665_SAR_SEL_MB1_NOSEL		(0x0 << 9) +#define RT5665_SAR_SEL_MB2_MASK			(0x1 << 8) +#define RT5665_SAR_SEL_MB2_SEL			(0x1 << 8) +#define RT5665_SAR_SEL_MB2_NOSEL		(0x0 << 8) +#define RT5665_SAR_SEL_MODE_MASK		(0x1 << 7) +#define RT5665_SAR_SEL_MODE_CMP			(0x1 << 7) +#define RT5665_SAR_SEL_MODE_ADC			(0x0 << 7) +#define RT5665_SAR_SEL_MB1_MB2_MASK		(0x1 << 5) +#define RT5665_SAR_SEL_MB1_MB2_AUTO		(0x1 << 5) +#define RT5665_SAR_SEL_MB1_MB2_MANU		(0x0 << 5) +#define RT5665_SAR_SEL_SIGNAL_MASK		(0x1 << 4) +#define RT5665_SAR_SEL_SIGNAL_AUTO		(0x1 << 4) +#define RT5665_SAR_SEL_SIGNAL_MANU		(0x0 << 4) + +/* System Clock Source */ +enum { +	RT5665_SCLK_S_MCLK, +	RT5665_SCLK_S_PLL1, +	RT5665_SCLK_S_RCCLK, +}; + +/* PLL1 Source */ +enum { +	RT5665_PLL1_S_MCLK, +	RT5665_PLL1_S_BCLK1, +	RT5665_PLL1_S_BCLK2, +	RT5665_PLL1_S_BCLK3, +	RT5665_PLL1_S_BCLK4, +}; + +enum { +	RT5665_AIF1_1, +	RT5665_AIF1_2, +	RT5665_AIF2_1, +	RT5665_AIF2_2, +	RT5665_AIF3, +	RT5665_AIFS +}; + +enum { +	CODEC_5665, +	CODEC_5666, +	CODEC_5668, +}; + +/* filter mask */ +enum { +	RT5665_DA_STEREO1_FILTER = 0x1, +	RT5665_DA_STEREO2_FILTER = (0x1 << 1), +	RT5665_DA_MONO_L_FILTER = (0x1 << 2), +	RT5665_DA_MONO_R_FILTER = (0x1 << 3), +	RT5665_AD_STEREO1_FILTER = (0x1 << 4), +	RT5665_AD_STEREO2_FILTER = (0x1 << 5), +	RT5665_AD_MONO_L_FILTER = (0x1 << 6), +	RT5665_AD_MONO_R_FILTER = (0x1 << 7), +}; + +enum { +	RT5665_CLK_SEL_SYS, +	RT5665_CLK_SEL_I2S1_ASRC, +	RT5665_CLK_SEL_I2S2_ASRC, +	RT5665_CLK_SEL_I2S3_ASRC, +	RT5665_CLK_SEL_SYS2, +	RT5665_CLK_SEL_SYS3, +	RT5665_CLK_SEL_SYS4, +}; + +int rt5665_sel_asrc_clk_src(struct snd_soc_codec *codec, +		unsigned int filter_mask, unsigned int clk_src); +int rt5665_set_jack_detect(struct snd_soc_codec *codec, +	struct snd_soc_jack *hs_jack); + +#endif /* __RT5665_H__ */ diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 49caf1393aeb..97bafac3bc15 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2618,7 +2618,7 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,  				RT5670_OSW_L_DIS | RT5670_OSW_R_DIS);  			snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x1);  			snd_soc_update_bits(codec, RT5670_PWR_ANLG1, -				RT5670_LDO_SEL_MASK, 0x3); +				RT5670_LDO_SEL_MASK, 0x5);  		}  		break;  	case SND_SOC_BIAS_STANDBY: @@ -2626,7 +2626,7 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,  				RT5670_PWR_VREF1 | RT5670_PWR_VREF2 |  				RT5670_PWR_FV1 | RT5670_PWR_FV2, 0);  		snd_soc_update_bits(codec, RT5670_PWR_ANLG1, -				RT5670_LDO_SEL_MASK, 0x1); +				RT5670_LDO_SEL_MASK, 0x3);  		break;  	case SND_SOC_BIAS_OFF:  		if (rt5670->pdata.jd_mode) @@ -2813,6 +2813,7 @@ MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id);  #ifdef CONFIG_ACPI  static const struct acpi_device_id rt5670_acpi_match[] = {  	{ "10EC5670", 0}, +	{ "10EC5672", 0},  	{ },  };  MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); @@ -2826,6 +2827,13 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = {  			DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"),  		},  	}, +	{ +		.ident = "Dell Wyse 3040", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), +			DMI_MATCH(DMI_PRODUCT_NAME, "Wyse 3040"), +		}, +	},  	{}  }; @@ -2889,6 +2897,9 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,  	if (ret != 0)  		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); +	regmap_update_bits(rt5670->regmap, RT5670_DIG_MISC, +				 RT5670_MCLK_DET, RT5670_MCLK_DET); +  	if (rt5670->pdata.in2_diff)  		regmap_update_bits(rt5670->regmap, RT5670_IN2,  					RT5670_IN_DF2, RT5670_IN_DF2); @@ -2903,7 +2914,6 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,  				   RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ);  		regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL2,  				   RT5670_GP1_PF_MASK, RT5670_GP1_PF_OUT); -		regmap_update_bits(rt5670->regmap, RT5670_DIG_MISC, 0x8, 0x8);  	}  	if (rt5670->pdata.jd_mode) { diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index 3f1b0f1df809..5ba485cae4e6 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -1914,6 +1914,7 @@ enum {  #define RT5670_IF1_ADC1_IN2_SFT			11  #define RT5670_IF1_ADC2_IN1_SEL			(0x1 << 10)  #define RT5670_IF1_ADC2_IN1_SFT			10 +#define RT5670_MCLK_DET				(0x1 << 3)  /* General Control2 (0xfb) */  #define RT5670_RXDC_SRC_MASK			(0x1 << 7) diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index 91879ea95415..ebd0f7c5ad3b 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -20,7 +20,6 @@  #include <linux/slab.h>  #include <linux/gpio.h>  #include <linux/sched.h> -#include <linux/kthread.h>  #include <linux/uaccess.h>  #include <linux/miscdevice.h>  #include <linux/regulator/consumer.h> diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 27f30d352867..9de7fe8af255 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -18,6 +18,7 @@  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/device.h> +#include <linux/regmap.h>  #include <sound/core.h>  #include <sound/pcm.h>  #include <sound/ac97_codec.h> @@ -26,31 +27,56 @@  #include <sound/soc.h>  #include <sound/tlv.h> -#include "stac9766.h" -  #define STAC9766_VENDOR_ID 0x83847666  #define STAC9766_VENDOR_ID_MASK 0xffffffff -/* - * STAC9766 register cache - */ -static const u16 stac9766_reg[] = { -	0x6A90, 0x8000, 0x8000, 0x8000, /* 6 */ -	0x0000, 0x0000, 0x8008, 0x8008, /* e */ -	0x8808, 0x8808, 0x8808, 0x8808, /* 16 */ -	0x8808, 0x0000, 0x8000, 0x0000, /* 1e */ -	0x0000, 0x0000, 0x0000, 0x000f, /* 26 */ -	0x0a05, 0x0400, 0xbb80, 0x0000, /* 2e */ -	0x0000, 0xbb80, 0x0000, 0x0000, /* 36 */ -	0x0000, 0x2000, 0x0000, 0x0100, /* 3e */ -	0x0000, 0x0000, 0x0080, 0x0000, /* 46 */ -	0x0000, 0x0000, 0x0003, 0xffff, /* 4e */ -	0x0000, 0x0000, 0x0000, 0x0000, /* 56 */ -	0x4000, 0x0000, 0x0000, 0x0000, /* 5e */ -	0x1201, 0xFFFF, 0xFFFF, 0x0000, /* 66 */ -	0x0000, 0x0000, 0x0000, 0x0000, /* 6e */ -	0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ -	0x0000, 0x0000, 0x0000, 0x0000, /* 7e */ +#define AC97_STAC_DA_CONTROL 0x6A +#define AC97_STAC_ANALOG_SPECIAL 0x6E +#define AC97_STAC_STEREO_MIC 0x78 + +static const struct reg_default stac9766_reg_defaults[] = { +	{ 0x02, 0x8000 }, +	{ 0x04, 0x8000 }, +	{ 0x06, 0x8000 }, +	{ 0x0a, 0x0000 }, +	{ 0x0c, 0x8008 }, +	{ 0x0e, 0x8008 }, +	{ 0x10, 0x8808 }, +	{ 0x12, 0x8808 }, +	{ 0x14, 0x8808 }, +	{ 0x16, 0x8808 }, +	{ 0x18, 0x8808 }, +	{ 0x1a, 0x0000 }, +	{ 0x1c, 0x8000 }, +	{ 0x20, 0x0000 }, +	{ 0x22, 0x0000 }, +	{ 0x28, 0x0a05 }, +	{ 0x2c, 0xbb80 }, +	{ 0x32, 0xbb80 }, +	{ 0x3a, 0x2000 }, +	{ 0x3e, 0x0100 }, +	{ 0x4c, 0x0300 }, +	{ 0x4e, 0xffff }, +	{ 0x50, 0x0000 }, +	{ 0x52, 0x0000 }, +	{ 0x54, 0x0000 }, +	{ 0x6a, 0x0000 }, +	{ 0x6e, 0x1000 }, +	{ 0x72, 0x0000 }, +	{ 0x78, 0x0000 }, +}; + +static const struct regmap_config stac9766_regmap_config = { +	.reg_bits = 16, +	.reg_stride = 2, +	.val_bits = 16, +	.max_register = 0x78, +	.cache_type = REGCACHE_RBTREE, + +	.volatile_reg = regmap_ac97_default_volatile, + +	.reg_defaults = stac9766_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(stac9766_reg_defaults),  };  static const char *stac9766_record_mux[] = {"Mic", "CD", "Video", "AUX", @@ -139,71 +165,22 @@ static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = {  	SOC_ENUM("Pop Bypass Mux", stac9766_popbypass_enum),  }; -static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, -			       unsigned int val) -{ -	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); -	u16 *cache = codec->reg_cache; - -	if (reg > AC97_STAC_PAGE0) { -		stac9766_ac97_write(codec, AC97_INT_PAGING, 0); -		soc_ac97_ops->write(ac97, reg, val); -		stac9766_ac97_write(codec, AC97_INT_PAGING, 1); -		return 0; -	} -	if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) -		return -EIO; - -	soc_ac97_ops->write(ac97, reg, val); -	cache[reg / 2] = val; -	return 0; -} - -static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, -				       unsigned int reg) -{ -	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); -	u16 val = 0, *cache = codec->reg_cache; - -	if (reg > AC97_STAC_PAGE0) { -		stac9766_ac97_write(codec, AC97_INT_PAGING, 0); -		val = soc_ac97_ops->read(ac97, reg - AC97_STAC_PAGE0); -		stac9766_ac97_write(codec, AC97_INT_PAGING, 1); -		return val; -	} -	if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) -		return -EIO; - -	if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || -		reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 || -		reg == AC97_VENDOR_ID2) { - -		val = soc_ac97_ops->read(ac97, reg); -		return val; -	} -	return cache[reg / 2]; -} -  static int ac97_analog_prepare(struct snd_pcm_substream *substream,  			       struct snd_soc_dai *dai)  {  	struct snd_soc_codec *codec = dai->codec;  	struct snd_pcm_runtime *runtime = substream->runtime; -	unsigned short reg, vra; - -	vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS); +	unsigned short reg; -	vra |= 0x1; /* enable variable rate audio */ -	vra &= ~0x4; /* disable SPDIF output */ - -	stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra); +	/* enable variable rate audio, disable SPDIF output */ +	snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x5, 0x1);  	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)  		reg = AC97_PCM_FRONT_DAC_RATE;  	else  		reg = AC97_PCM_LR_ADC_RATE; -	return stac9766_ac97_write(codec, reg, runtime->rate); +	return snd_soc_write(codec, reg, runtime->rate);  }  static int ac97_digital_prepare(struct snd_pcm_substream *substream, @@ -211,18 +188,16 @@ static int ac97_digital_prepare(struct snd_pcm_substream *substream,  {  	struct snd_soc_codec *codec = dai->codec;  	struct snd_pcm_runtime *runtime = substream->runtime; -	unsigned short reg, vra; - -	stac9766_ac97_write(codec, AC97_SPDIF, 0x2002); +	unsigned short reg; -	vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS); -	vra |= 0x5; /* Enable VRA and SPDIF out */ +	snd_soc_write(codec, AC97_SPDIF, 0x2002); -	stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra); +	/* Enable VRA and SPDIF out */ +	snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x5, 0x5);  	reg = AC97_PCM_FRONT_DAC_RATE; -	return stac9766_ac97_write(codec, reg, runtime->rate); +	return snd_soc_write(codec, reg, runtime->rate);  }  static int stac9766_set_bias_level(struct snd_soc_codec *codec, @@ -232,11 +207,11 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec,  	case SND_SOC_BIAS_ON: /* full On */  	case SND_SOC_BIAS_PREPARE: /* partial On */  	case SND_SOC_BIAS_STANDBY: /* Off, with power */ -		stac9766_ac97_write(codec, AC97_POWERDOWN, 0x0000); +		snd_soc_write(codec, AC97_POWERDOWN, 0x0000);  		break;  	case SND_SOC_BIAS_OFF: /* Off, without power */  		/* disable everything including AC link */ -		stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff); +		snd_soc_write(codec, AC97_POWERDOWN, 0xffff);  		break;  	}  	return 0; @@ -300,21 +275,34 @@ static struct snd_soc_dai_driver stac9766_dai[] = {  static int stac9766_codec_probe(struct snd_soc_codec *codec)  {  	struct snd_ac97 *ac97; +	struct regmap *regmap; +	int ret;  	ac97 = snd_soc_new_ac97_codec(codec, STAC9766_VENDOR_ID,  			STAC9766_VENDOR_ID_MASK);  	if (IS_ERR(ac97))  		return PTR_ERR(ac97); +	regmap = regmap_init_ac97(ac97, &stac9766_regmap_config); +	if (IS_ERR(regmap)) { +		ret = PTR_ERR(regmap); +		goto err_free_ac97; +	} + +	snd_soc_codec_init_regmap(codec, regmap);  	snd_soc_codec_set_drvdata(codec, ac97);  	return 0; +err_free_ac97: +	snd_soc_free_ac97_codec(ac97); +	return ret;  }  static int stac9766_codec_remove(struct snd_soc_codec *codec)  {  	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); +	snd_soc_codec_exit_regmap(codec);  	snd_soc_free_ac97_codec(ac97);  	return 0;  } @@ -324,17 +312,11 @@ static struct snd_soc_codec_driver soc_codec_dev_stac9766 = {  		.controls		= stac9766_snd_ac97_controls,  		.num_controls		= ARRAY_SIZE(stac9766_snd_ac97_controls),  	}, -	.write = stac9766_ac97_write, -	.read = stac9766_ac97_read,  	.set_bias_level = stac9766_set_bias_level,  	.suspend_bias_off = true,  	.probe = stac9766_codec_probe,  	.remove = stac9766_codec_remove,  	.resume = stac9766_codec_resume, -	.reg_cache_size = ARRAY_SIZE(stac9766_reg), -	.reg_word_size = sizeof(u16), -	.reg_cache_step = 2, -	.reg_cache_default = stac9766_reg,  };  static int stac9766_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/stac9766.h b/sound/soc/codecs/stac9766.h deleted file mode 100644 index c726f907e2c0..000000000000 --- a/sound/soc/codecs/stac9766.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * stac9766.h  --  STAC9766 Soc Audio driver - */ - -#ifndef _STAC9766_H -#define _STAC9766_H - -#define AC97_STAC_PAGE0 0x1000 -#define AC97_STAC_DA_CONTROL (AC97_STAC_PAGE0 | 0x6A) -#define AC97_STAC_ANALOG_SPECIAL (AC97_STAC_PAGE0 | 0x6E) -#define AC97_STAC_STEREO_MIC 0x78 - -/* STAC9766 DAI ID's */ -#define STAC9766_DAI_AC97_ANALOG		0 -#define STAC9766_DAI_AC97_DIGITAL		1 - -#endif diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index d6e00c77edcd..62c618765224 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -14,28 +14,8 @@  #include <sound/soc.h>  #include <sound/soc-dapm.h> -/* chipID supported */ -#define CHIPID_STIH416 0 -#define CHIPID_STIH407 1 -  /* DAC definitions */ -/* stih416 DAC registers */ -/* sysconf 2517: Audio-DAC-Control */ -#define STIH416_AUDIO_DAC_CTRL 0x00000814 -/* sysconf 2519: Audio-Gue-Control */ -#define STIH416_AUDIO_GLUE_CTRL 0x0000081C - -#define STIH416_DAC_NOT_STANDBY	0x3 -#define STIH416_DAC_SOFTMUTE	0x4 -#define STIH416_DAC_ANA_NOT_PWR	0x5 -#define STIH416_DAC_NOT_PNDBG	0x6 - -#define STIH416_DAC_NOT_STANDBY_MASK	BIT(STIH416_DAC_NOT_STANDBY) -#define STIH416_DAC_SOFTMUTE_MASK	BIT(STIH416_DAC_SOFTMUTE) -#define STIH416_DAC_ANA_NOT_PWR_MASK	BIT(STIH416_DAC_ANA_NOT_PWR) -#define STIH416_DAC_NOT_PNDBG_MASK	BIT(STIH416_DAC_NOT_PNDBG) -  /* stih407 DAC registers */  /* sysconf 5041: Audio-Gue-Control */  #define STIH407_AUDIO_GLUE_CTRL 0x000000A4 @@ -63,14 +43,9 @@ enum {  	STI_SAS_DAI_ANALOG_OUT,  }; -static const struct reg_default stih416_sas_reg_defaults[] = { -	{ STIH407_AUDIO_GLUE_CTRL, 0x00000040 }, -	{ STIH407_AUDIO_DAC_CTRL, 0x000000000 }, -}; -  static const struct reg_default stih407_sas_reg_defaults[] = { -	{ STIH416_AUDIO_DAC_CTRL, 0x000000000 }, -	{ STIH416_AUDIO_GLUE_CTRL, 0x00000040 }, +	{ STIH407_AUDIO_DAC_CTRL, 0x000000000 }, +	{ STIH407_AUDIO_GLUE_CTRL, 0x00000040 },  };  struct sti_dac_audio { @@ -89,7 +64,6 @@ struct sti_spdif_audio {  /* device data structure */  struct sti_sas_dev_data { -	const int chipid; /* IC version */  	const struct regmap_config *regmap;  	const struct snd_soc_dai_ops *dac_ops;  /* DAC function callbacks */  	const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */ @@ -150,51 +124,27 @@ static int  sti_sas_init_sas_registers(struct snd_soc_codec *codec,  		ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,  					  SPDIF_BIPHASE_IDLE_MASK, 0);  	if (ret < 0) { -		dev_err(codec->dev, "Failed to update SPDIF registers"); +		dev_err(codec->dev, "Failed to update SPDIF registers\n");  		return ret;  	}  	/* Init DAC configuration */ -	switch (data->dev_data->chipid) { -	case CHIPID_STIH407: -		/* init configuration */ -		ret =  snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, -					   STIH407_DAC_STANDBY_MASK, -					   STIH407_DAC_STANDBY_MASK); - -		if (!ret) -			ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, -						  STIH407_DAC_STANDBY_ANA_MASK, -						  STIH407_DAC_STANDBY_ANA_MASK); -		if (!ret) -			ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, -						  STIH407_DAC_SOFTMUTE_MASK, -						  STIH407_DAC_SOFTMUTE_MASK); -		break; -	case CHIPID_STIH416: -		ret =  snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, -					   STIH416_DAC_NOT_STANDBY_MASK, 0); -		if (!ret) -			ret =  snd_soc_update_bits(codec, -						   STIH416_AUDIO_DAC_CTRL, -						   STIH416_DAC_ANA_NOT_PWR, 0); -		if (!ret) -			ret =  snd_soc_update_bits(codec, -						   STIH416_AUDIO_DAC_CTRL, -						   STIH416_DAC_NOT_PNDBG_MASK, -						   0); -		if (!ret) -			ret =  snd_soc_update_bits(codec, -						   STIH416_AUDIO_DAC_CTRL, -						   STIH416_DAC_SOFTMUTE_MASK, -						   STIH416_DAC_SOFTMUTE_MASK); -		break; -	default: -		return -EINVAL; -	} +	/* init configuration */ +	ret =  snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, +				   STIH407_DAC_STANDBY_MASK, +				   STIH407_DAC_STANDBY_MASK); + +	if (!ret) +		ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, +					  STIH407_DAC_STANDBY_ANA_MASK, +					  STIH407_DAC_STANDBY_ANA_MASK); +	if (!ret) +		ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, +					  STIH407_DAC_SOFTMUTE_MASK, +					  STIH407_DAC_SOFTMUTE_MASK);  	if (ret < 0) { -		dev_err(codec->dev, "Failed to update DAC registers"); +		dev_err(codec->dev, "Failed to update DAC registers\n");  		return ret;  	} @@ -217,37 +167,6 @@ static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)  	return 0;  } -static int stih416_dac_probe(struct snd_soc_dai *dai) -{ -	struct snd_soc_codec *codec = dai->codec; -	struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); -	struct sti_dac_audio *dac = &drvdata->dac; - -	/* Get reset control */ -	dac->rst = devm_reset_control_get(codec->dev, "dac_rst"); -	if (IS_ERR(dac->rst)) { -		dev_err(dai->codec->dev, -			"%s: ERROR: DAC reset control not defined !\n", -			__func__); -		dac->rst = NULL; -		return -EFAULT; -	} -	/* Put the DAC into reset */ -	reset_control_assert(dac->rst); - -	return 0; -} - -static const struct snd_soc_dapm_widget stih416_sas_dapm_widgets[] = { -	SND_SOC_DAPM_PGA("DAC bandgap", STIH416_AUDIO_DAC_CTRL, -			 STIH416_DAC_NOT_PNDBG_MASK, 0, NULL, 0), -	SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH416_AUDIO_DAC_CTRL, -			     STIH416_DAC_ANA_NOT_PWR, 0, NULL, 0), -	SND_SOC_DAPM_DAC("DAC standby",  "dac_p", STIH416_AUDIO_DAC_CTRL, -			 STIH416_DAC_NOT_STANDBY, 0), -	SND_SOC_DAPM_OUTPUT("DAC Output"), -}; -  static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = {  	SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL,  			     STIH407_DAC_STANDBY_ANA, 1, NULL, 0), @@ -256,30 +175,11 @@ static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = {  	SND_SOC_DAPM_OUTPUT("DAC Output"),  }; -static const struct snd_soc_dapm_route stih416_sas_route[] = { -	{"DAC Output", NULL, "DAC bandgap"}, -	{"DAC Output", NULL, "DAC standby ana"}, -	{"DAC standby ana", NULL, "DAC standby"}, -}; -  static const struct snd_soc_dapm_route stih407_sas_route[] = {  	{"DAC Output", NULL, "DAC standby ana"},  	{"DAC standby ana", NULL, "DAC standby"},  }; -static int stih416_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) -{ -	struct snd_soc_codec *codec = dai->codec; - -	if (mute) { -		return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, -					    STIH416_DAC_SOFTMUTE_MASK, -					    STIH416_DAC_SOFTMUTE_MASK); -	} else { -		return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, -					    STIH416_DAC_SOFTMUTE_MASK, 0); -	} -}  static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)  { @@ -392,13 +292,13 @@ static int sti_sas_prepare(struct snd_pcm_substream *substream,  	switch (dai->id) {  	case STI_SAS_DAI_SPDIF_OUT:  		if ((drvdata->spdif.mclk / runtime->rate) != 128) { -			dev_err(codec->dev, "unexpected mclk-fs ratio"); +			dev_err(codec->dev, "unexpected mclk-fs ratio\n");  			return -EINVAL;  		}  		break;  	case STI_SAS_DAI_ANALOG_OUT:  		if ((drvdata->dac.mclk / runtime->rate) != 256) { -			dev_err(codec->dev, "unexpected mclk-fs ratio"); +			dev_err(codec->dev, "unexpected mclk-fs ratio\n");  			return -EINVAL;  		}  		break; @@ -407,13 +307,6 @@ static int sti_sas_prepare(struct snd_pcm_substream *substream,  	return 0;  } -static const struct snd_soc_dai_ops stih416_dac_ops = { -	.set_fmt = sti_sas_dac_set_fmt, -	.mute_stream = stih416_sas_dac_mute, -	.prepare = sti_sas_prepare, -	.set_sysclk = sti_sas_set_sysclk, -}; -  static const struct snd_soc_dai_ops stih407_dac_ops = {  	.set_fmt = sti_sas_dac_set_fmt,  	.mute_stream = stih407_sas_dac_mute, @@ -434,31 +327,7 @@ static const struct regmap_config stih407_sas_regmap = {  	.reg_write = sti_sas_write_reg,  }; -static const struct regmap_config stih416_sas_regmap = { -	.reg_bits = 32, -	.val_bits = 32, - -	.max_register = STIH416_AUDIO_DAC_CTRL, -	.reg_defaults = stih416_sas_reg_defaults, -	.num_reg_defaults = ARRAY_SIZE(stih416_sas_reg_defaults), -	.volatile_reg = sti_sas_volatile_register, -	.cache_type = REGCACHE_RBTREE, -	.reg_read = sti_sas_read_reg, -	.reg_write = sti_sas_write_reg, -}; - -static const struct sti_sas_dev_data stih416_data = { -	.chipid = CHIPID_STIH416, -	.regmap = &stih416_sas_regmap, -	.dac_ops = &stih416_dac_ops, -	.dapm_widgets = stih416_sas_dapm_widgets, -	.num_dapm_widgets = ARRAY_SIZE(stih416_sas_dapm_widgets), -	.dapm_routes =	stih416_sas_route, -	.num_dapm_routes = ARRAY_SIZE(stih416_sas_route), -}; -  static const struct sti_sas_dev_data stih407_data = { -	.chipid = CHIPID_STIH407,  	.regmap = &stih407_sas_regmap,  	.dac_ops = &stih407_dac_ops,  	.dapm_widgets = stih407_sas_dapm_widgets, @@ -533,10 +402,6 @@ static struct snd_soc_codec_driver sti_sas_driver = {  static const struct of_device_id sti_sas_dev_match[] = {  	{ -		.compatible = "st,stih416-sas-codec", -		.data = &stih416_data, -	}, -	{  		.compatible = "st,stih407-sas-codec",  		.data = &stih407_data,  	}, @@ -558,7 +423,7 @@ static int sti_sas_driver_probe(struct platform_device *pdev)  	/* Populate data structure depending on compatibility */  	of_id = of_match_node(sti_sas_dev_match, pnode);  	if (!of_id->data) { -		dev_err(&pdev->dev, "data associated to device is missing"); +		dev_err(&pdev->dev, "data associated to device is missing\n");  		return -EINVAL;  	} @@ -584,10 +449,6 @@ static int sti_sas_driver_probe(struct platform_device *pdev)  	}  	drvdata->spdif.regmap = drvdata->dac.regmap; -	/* Set DAC dai probe */ -	if (drvdata->dev_data->chipid == CHIPID_STIH416) -		sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].probe = stih416_dac_probe; -  	sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops;  	/* Set dapms*/ diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index be1a64bfd320..f8a90ba8cd71 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1253,6 +1253,8 @@ static const struct of_device_id tlv320aic31xx_of_match[] = {  	{ .compatible = "ti,tlv320aic3110" },  	{ .compatible = "ti,tlv320aic3120" },  	{ .compatible = "ti,tlv320aic3111" }, +	{ .compatible = "ti,tlv320dac3100" }, +	{ .compatible = "ti,tlv320dac3101" },  	{},  };  MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match); @@ -1379,6 +1381,7 @@ static const struct i2c_device_id aic31xx_i2c_id[] = {  	{ "tlv320aic3120", AIC3120 },  	{ "tlv320aic3111", AIC3111 },  	{ "tlv320dac3100", DAC3100 }, +	{ "tlv320dac3101", DAC3101 },  	{ }  };  MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 5acd5b69fb83..730fb2058869 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -32,6 +32,7 @@ enum aic31xx_type {  	AIC3120 = AIC31XX_MINIDSP_BIT,  	AIC3111 = (AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT),  	DAC3100 = DAC31XX_BIT, +	DAC3101 = DAC31XX_BIT | AIC31XX_STEREO_CLASS_D_BIT,  };  struct aic31xx_pdata { diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 5a8d96ec058c..8877b74b0510 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -157,7 +157,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,  	unsigned int mask = (1 << fls(max)) - 1;  	unsigned int invert = mc->invert;  	unsigned short val; -	struct snd_soc_dapm_update update; +	struct snd_soc_dapm_update update = { 0 };  	int connect, change;  	val = (ucontrol->value.integer.value[0] & mask); diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 533e3bb444e4..2918fdb95e58 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -698,25 +698,10 @@ static int uda1380_probe(struct snd_soc_codec *codec)  	codec->hw_write = (hw_write_t)i2c_master_send;  	codec->control_data = uda1380->control_data; -	if (!pdata) -		return -EINVAL; - -	if (gpio_is_valid(pdata->gpio_reset)) { -		ret = gpio_request_one(pdata->gpio_reset, GPIOF_OUT_INIT_LOW, -				       "uda1380 reset"); -		if (ret) -			goto err_out; -	} - -	if (gpio_is_valid(pdata->gpio_power)) { -		ret = gpio_request_one(pdata->gpio_power, GPIOF_OUT_INIT_LOW, -				   "uda1380 power"); -		if (ret) -			goto err_free_gpio; -	} else { +	if (!gpio_is_valid(pdata->gpio_power)) {  		ret = uda1380_reset(codec);  		if (ret) -			goto err_free_gpio; +			return ret;  	}  	INIT_WORK(&uda1380->work, uda1380_flush_work); @@ -733,28 +718,10 @@ static int uda1380_probe(struct snd_soc_codec *codec)  	}  	return 0; - -err_free_gpio: -	if (gpio_is_valid(pdata->gpio_reset)) -		gpio_free(pdata->gpio_reset); -err_out: -	return ret; -} - -/* power down chip */ -static int uda1380_remove(struct snd_soc_codec *codec) -{ -	struct uda1380_platform_data *pdata =codec->dev->platform_data; - -	gpio_free(pdata->gpio_reset); -	gpio_free(pdata->gpio_power); - -	return 0;  }  static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {  	.probe =	uda1380_probe, -	.remove =	uda1380_remove,  	.read =		uda1380_read_reg_cache,  	.write =	uda1380_write,  	.set_bias_level = uda1380_set_bias_level, @@ -775,18 +742,35 @@ static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {  	},  }; -#if IS_ENABLED(CONFIG_I2C)  static int uda1380_i2c_probe(struct i2c_client *i2c,  			     const struct i2c_device_id *id)  { +	struct uda1380_platform_data *pdata = i2c->dev.platform_data;  	struct uda1380_priv *uda1380;  	int ret; +	if (!pdata) +		return -EINVAL; +  	uda1380 = devm_kzalloc(&i2c->dev, sizeof(struct uda1380_priv),  			       GFP_KERNEL);  	if (uda1380 == NULL)  		return -ENOMEM; +	if (gpio_is_valid(pdata->gpio_reset)) { +		ret = devm_gpio_request_one(&i2c->dev, pdata->gpio_reset, +			GPIOF_OUT_INIT_LOW, "uda1380 reset"); +		if (ret) +			return ret; +	} + +	if (gpio_is_valid(pdata->gpio_power)) { +		ret = devm_gpio_request_one(&i2c->dev, pdata->gpio_power, +			GPIOF_OUT_INIT_LOW, "uda1380 power"); +		if (ret) +			return ret; +	} +  	i2c_set_clientdata(i2c, uda1380);  	uda1380->control_data = i2c; @@ -815,27 +799,8 @@ static struct i2c_driver uda1380_i2c_driver = {  	.remove =   uda1380_i2c_remove,  	.id_table = uda1380_i2c_id,  }; -#endif -static int __init uda1380_modinit(void) -{ -	int ret = 0; -#if IS_ENABLED(CONFIG_I2C) -	ret = i2c_add_driver(&uda1380_i2c_driver); -	if (ret != 0) -		pr_err("Failed to register UDA1380 I2C driver: %d\n", ret); -#endif -	return ret; -} -module_init(uda1380_modinit); - -static void __exit uda1380_exit(void) -{ -#if IS_ENABLED(CONFIG_I2C) -	i2c_del_driver(&uda1380_i2c_driver); -#endif -} -module_exit(uda1380_exit); +module_i2c_driver(uda1380_i2c_driver);  MODULE_AUTHOR("Giorgio Padrin");  MODULE_DESCRIPTION("Audio support for codec Philips UDA1380"); diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h index 942e3927c72b..69a326ac3c1a 100644 --- a/sound/soc/codecs/uda1380.h +++ b/sound/soc/codecs/uda1380.h @@ -72,8 +72,4 @@  #define R22_SKIP_DCFIL	0x0002  #define R23_AGC_EN	0x0001 -#define UDA1380_DAI_DUPLEX	0 /* playback and capture on single DAI */ -#define UDA1380_DAI_PLAYBACK	1 /* playback DAI */ -#define UDA1380_DAI_CAPTURE	2 /* capture DAI */ -  #endif /* _UDA1380_H */ diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 606bf88abfc4..d83dab57a1d1 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -999,7 +999,7 @@ static DECLARE_TLV_DB_SCALE(in_tlv, -6300, 100, 0);  static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);  static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0); -static const char *wm2200_mixer_texts[] = { +static const char * const wm2200_mixer_texts[] = {  	"None",  	"Tone Generator",  	"AEC Loopback", @@ -1033,7 +1033,7 @@ static const char *wm2200_mixer_texts[] = {  	"DSP2.6",  }; -static int wm2200_mixer_values[] = { +static unsigned int wm2200_mixer_values[] = {  	0x00,  	0x04,   /* Tone */  	0x08,   /* AEC */ diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 93876c6d48ee..e7ab37d0dd32 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -607,6 +607,9 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,  		break;  	case SND_SOC_DAPM_PRE_PMD:  		break; +	case SND_SOC_DAPM_PRE_PMU: +	case SND_SOC_DAPM_POST_PMD: +		return arizona_clk_ev(w, kcontrol, event);  	default:  		return 0;  	} @@ -1077,9 +1080,11 @@ static const struct snd_kcontrol_new wm5102_aec_loopback_mux =  static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = {  SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,  		    0, wm5102_sysclk_ev, -		    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +		    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | +		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),  SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, -		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), +		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev, +		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),  SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,  		    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),  SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, @@ -1903,7 +1908,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = {  static int wm5102_open(struct snd_compr_stream *stream)  {  	struct snd_soc_pcm_runtime *rtd = stream->private_data; -	struct wm5102_priv *priv = snd_soc_codec_get_drvdata(rtd->codec); +	struct wm5102_priv *priv = snd_soc_platform_get_drvdata(rtd->platform);  	return wm_adsp_compr_open(&priv->core.adsp[0], stream);  } @@ -1926,18 +1931,10 @@ static irqreturn_t wm5102_adsp2_irq(int irq, void *data)  static int wm5102_codec_probe(struct snd_soc_codec *codec)  {  	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); +	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);  	struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); -	struct arizona *arizona = priv->core.arizona;  	int ret; -	ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, -				  "ADSP2 Compressed IRQ", wm5102_adsp2_irq, -				  priv); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret); -		return ret; -	} -  	ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec);  	if (ret)  		return ret; @@ -1949,8 +1946,9 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)  	arizona_init_spk(codec);  	arizona_init_gpio(codec); +	arizona_init_notifiers(codec); -	snd_soc_dapm_disable_pin(dapm, "HAPTICS"); +	snd_soc_component_disable_pin(component, "HAPTICS");  	priv->core.arizona->dapm = dapm; @@ -1965,16 +1963,11 @@ err_adsp2_codec_probe:  static int wm5102_codec_remove(struct snd_soc_codec *codec)  {  	struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); -	struct arizona *arizona = priv->core.arizona;  	wm_adsp2_codec_remove(&priv->core.adsp[0], codec);  	priv->core.arizona->dapm = NULL; -	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); - -	arizona_free_spk(codec); -  	return 0;  } @@ -2092,25 +2085,47 @@ static int wm5102_probe(struct platform_device *pdev)  	pm_runtime_enable(&pdev->dev);  	pm_runtime_idle(&pdev->dev); +	ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, +				  "ADSP2 Compressed IRQ", wm5102_adsp2_irq, +				  wm5102); +	if (ret != 0) { +		dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); +		return ret; +	} + +	ret = arizona_init_spk_irqs(arizona); +	if (ret < 0) +		goto err_dsp_irq; +  	ret = snd_soc_register_platform(&pdev->dev, &wm5102_compr_platform);  	if (ret < 0) {  		dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); -		return ret; +		goto err_spk_irqs;  	}  	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5102,  				      wm5102_dai, ARRAY_SIZE(wm5102_dai));  	if (ret < 0) {  		dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); -		snd_soc_unregister_platform(&pdev->dev); +		goto err_platform;  	}  	return ret; + +err_platform: +	snd_soc_unregister_platform(&pdev->dev); +err_spk_irqs: +	arizona_free_spk_irqs(arizona); +err_dsp_irq: +	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102); + +	return ret;  }  static int wm5102_remove(struct platform_device *pdev)  {  	struct wm5102_priv *wm5102 = platform_get_drvdata(pdev); +	struct arizona *arizona = wm5102->core.arizona;  	snd_soc_unregister_platform(&pdev->dev);  	snd_soc_unregister_codec(&pdev->dev); @@ -2118,6 +2133,10 @@ static int wm5102_remove(struct platform_device *pdev)  	wm_adsp2_remove(&wm5102->core.adsp[0]); +	arizona_free_spk_irqs(arizona); + +	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102); +  	return 0;  } diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 06bae3b23fce..585fc706c1b0 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -183,7 +183,9 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,  				regmap_write_async(regmap, patch[i].reg,  						   patch[i].def);  		break; - +	case SND_SOC_DAPM_PRE_PMU: +	case SND_SOC_DAPM_POST_PMD: +		return arizona_clk_ev(w, kcontrol, event);  	default:  		break;  	} @@ -1073,9 +1075,11 @@ static const struct snd_kcontrol_new wm5110_output_anc_src[] = {  static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {  SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, -		    0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU), +		    0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU | +		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),  SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, -		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), +		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev, +		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),  SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,  		    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),  SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, @@ -2220,7 +2224,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = {  static int wm5110_open(struct snd_compr_stream *stream)  {  	struct snd_soc_pcm_runtime *rtd = stream->private_data; -	struct wm5110_priv *priv = snd_soc_codec_get_drvdata(rtd->codec); +	struct wm5110_priv *priv = snd_soc_platform_get_drvdata(rtd->platform);  	struct arizona *arizona = priv->core.arizona;  	int n_adsp; @@ -2269,8 +2273,8 @@ static irqreturn_t wm5110_adsp2_irq(int irq, void *data)  static int wm5110_codec_probe(struct snd_soc_codec *codec)  {  	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); +	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);  	struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); -	struct arizona *arizona = priv->core.arizona;  	int i, ret;  	priv->core.arizona->dapm = dapm; @@ -2280,14 +2284,6 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)  	arizona_init_mono(codec);  	arizona_init_notifiers(codec); -	ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, -				  "ADSP2 Compressed IRQ", wm5110_adsp2_irq, -				  priv); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret); -		return ret; -	} -  	for (i = 0; i < WM5110_NUM_ADSP; ++i) {  		ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec);  		if (ret) @@ -2300,7 +2296,7 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)  	if (ret)  		goto err_adsp2_codec_probe; -	snd_soc_dapm_disable_pin(dapm, "HAPTICS"); +	snd_soc_component_disable_pin(component, "HAPTICS");  	return 0; @@ -2308,15 +2304,12 @@ err_adsp2_codec_probe:  	for (--i; i >= 0; --i)  		wm_adsp2_codec_remove(&priv->core.adsp[i], codec); -	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); -  	return ret;  }  static int wm5110_codec_remove(struct snd_soc_codec *codec)  {  	struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); -	struct arizona *arizona = priv->core.arizona;  	int i;  	for (i = 0; i < WM5110_NUM_ADSP; ++i) @@ -2324,10 +2317,6 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec)  	priv->core.arizona->dapm = NULL; -	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); - -	arizona_free_spk(codec); -  	return 0;  } @@ -2449,25 +2438,47 @@ static int wm5110_probe(struct platform_device *pdev)  	pm_runtime_enable(&pdev->dev);  	pm_runtime_idle(&pdev->dev); +	ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, +				  "ADSP2 Compressed IRQ", wm5110_adsp2_irq, +				  wm5110); +	if (ret != 0) { +		dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); +		return ret; +	} + +	ret = arizona_init_spk_irqs(arizona); +	if (ret < 0) +		goto err_dsp_irq; +  	ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform);  	if (ret < 0) {  		dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); -		return ret; +		goto err_spk_irqs;  	}  	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,  				      wm5110_dai, ARRAY_SIZE(wm5110_dai));  	if (ret < 0) {  		dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); -		snd_soc_unregister_platform(&pdev->dev); +		goto err_platform;  	}  	return ret; + +err_platform: +	snd_soc_unregister_platform(&pdev->dev); +err_spk_irqs: +	arizona_free_spk_irqs(arizona); +err_dsp_irq: +	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110); + +	return ret;  }  static int wm5110_remove(struct platform_device *pdev)  {  	struct wm5110_priv *wm5110 = platform_get_drvdata(pdev); +	struct arizona *arizona = wm5110->core.arizona;  	int i;  	snd_soc_unregister_platform(&pdev->dev); @@ -2477,6 +2488,10 @@ static int wm5110_remove(struct platform_device *pdev)  	for (i = 0; i < WM5110_NUM_ADSP; i++)  		wm_adsp2_remove(&wm5110->core.adsp[i]); +	arizona_free_spk_irqs(arizona); + +	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110); +  	return 0;  } diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index deb2e075428e..6d0a2723bfde 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -446,7 +446,6 @@ static const struct regmap_config wm8523_regmap = {  	.volatile_reg = wm8523_volatile_register,  }; -#if IS_ENABLED(CONFIG_I2C)  static int wm8523_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -543,29 +542,8 @@ static struct i2c_driver wm8523_i2c_driver = {  	.remove =   wm8523_i2c_remove,  	.id_table = wm8523_i2c_id,  }; -#endif -static int __init wm8523_modinit(void) -{ -	int ret; -#if IS_ENABLED(CONFIG_I2C) -	ret = i2c_add_driver(&wm8523_i2c_driver); -	if (ret != 0) { -		printk(KERN_ERR "Failed to register WM8523 I2C driver: %d\n", -		       ret); -	} -#endif -	return 0; -} -module_init(wm8523_modinit); - -static void __exit wm8523_exit(void) -{ -#if IS_ENABLED(CONFIG_I2C) -	i2c_del_driver(&wm8523_i2c_driver); -#endif -} -module_exit(wm8523_exit); +module_i2c_driver(wm8523_i2c_driver);  MODULE_DESCRIPTION("ASoC WM8523 driver");  MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index faa7287a5253..910801dddd64 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -1,5 +1,5 @@  /* - * wm8580.c  --  WM8580 ALSA Soc Audio driver + * wm8580.c  --  WM8580 and WM8581 ALSA Soc Audio driver   *   * Copyright 2008-12 Wolfson Microelectronics PLC.   * @@ -12,6 +12,9 @@   *  The WM8580 is a multichannel codec with S/PDIF support, featuring six   *  DAC channels and two ADC channels.   * + *  The WM8581 is a multichannel codec with S/PDIF support, featuring eight + *  DAC channels and two ADC channels. + *   *  Currently only the primary audio interface is supported - S/PDIF and   *  the secondary audio interfaces are not.   */ @@ -65,6 +68,8 @@  #define WM8580_DIGITAL_ATTENUATION_DACR2     0x17  #define WM8580_DIGITAL_ATTENUATION_DACL3     0x18  #define WM8580_DIGITAL_ATTENUATION_DACR3     0x19 +#define WM8581_DIGITAL_ATTENUATION_DACL4     0x1A +#define WM8581_DIGITAL_ATTENUATION_DACR4     0x1B  #define WM8580_MASTER_DIGITAL_ATTENUATION    0x1C  #define WM8580_ADC_CONTROL1                  0x1D  #define WM8580_SPDTXCHAN0                    0x1E @@ -236,12 +241,17 @@ static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = {  	"PVDD",  }; +struct wm8580_driver_data { +	int num_dacs; +}; +  /* codec private data */  struct wm8580_priv {  	struct regmap *regmap;  	struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES];  	struct pll_state a;  	struct pll_state b; +	const struct wm8580_driver_data *drvdata;  	int sysclk[2];  }; @@ -306,6 +316,19 @@ SOC_DOUBLE("Capture Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 1),  SOC_SINGLE("Capture High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),  }; +static const struct snd_kcontrol_new wm8581_snd_controls[] = { +SOC_DOUBLE_R_EXT_TLV("DAC4 Playback Volume", +		     WM8581_DIGITAL_ATTENUATION_DACL4, +		     WM8581_DIGITAL_ATTENUATION_DACR4, +		     0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv), + +SOC_SINGLE("DAC4 Deemphasis Switch", WM8580_DAC_CONTROL3, 3, 1, 0), + +SOC_DOUBLE("DAC4 Invert Switch", WM8580_DAC_CONTROL4,  8, 7, 1, 0), + +SOC_SINGLE("DAC4 Switch", WM8580_DAC_CONTROL5, 3, 1, 1), +}; +  static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = {  SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1),  SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1), @@ -324,6 +347,13 @@ SND_SOC_DAPM_INPUT("AINL"),  SND_SOC_DAPM_INPUT("AINR"),  }; +static const struct snd_soc_dapm_widget wm8581_dapm_widgets[] = { +SND_SOC_DAPM_DAC("DAC4", "Playback", WM8580_PWRDN1, 5, 1), + +SND_SOC_DAPM_OUTPUT("VOUT4L"), +SND_SOC_DAPM_OUTPUT("VOUT4R"), +}; +  static const struct snd_soc_dapm_route wm8580_dapm_routes[] = {  	{ "VOUT1L", NULL, "DAC1" },  	{ "VOUT1R", NULL, "DAC1" }, @@ -338,6 +368,11 @@ static const struct snd_soc_dapm_route wm8580_dapm_routes[] = {  	{ "ADC", NULL, "AINR" },  }; +static const struct snd_soc_dapm_route wm8581_dapm_routes[] = { +	{ "VOUT4L", NULL, "DAC4" }, +	{ "VOUT4R", NULL, "DAC4" }, +}; +  /* PLL divisors */  struct _pll_div {  	u32 prescale:1; @@ -815,10 +850,21 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,  	return 0;  } +static int wm8580_playback_startup(struct snd_pcm_substream *substream, +			   struct snd_soc_dai *dai) +{ +	struct snd_soc_codec *codec = dai->codec; +	struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); + +	return snd_pcm_hw_constraint_minmax(substream->runtime, +		SNDRV_PCM_HW_PARAM_CHANNELS, 1, wm8580->drvdata->num_dacs * 2); +} +  #define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\  			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)  static const struct snd_soc_dai_ops wm8580_dai_ops_playback = { +	.startup	= wm8580_playback_startup,  	.set_sysclk	= wm8580_set_sysclk,  	.hw_params	= wm8580_paif_hw_params,  	.set_fmt	= wm8580_set_paif_dai_fmt, @@ -842,7 +888,6 @@ static struct snd_soc_dai_driver wm8580_dai[] = {  		.playback = {  			.stream_name = "Playback",  			.channels_min = 1, -			.channels_max = 6,  			.rates = SNDRV_PCM_RATE_8000_192000,  			.formats = WM8580_FORMATS,  		}, @@ -865,8 +910,22 @@ static struct snd_soc_dai_driver wm8580_dai[] = {  static int wm8580_probe(struct snd_soc_codec *codec)  {  	struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); +	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);  	int ret = 0; +	switch (wm8580->drvdata->num_dacs) { +	case 4: +		snd_soc_add_codec_controls(codec, wm8581_snd_controls, +					ARRAY_SIZE(wm8581_snd_controls)); +		snd_soc_dapm_new_controls(dapm, wm8581_dapm_widgets, +					ARRAY_SIZE(wm8581_dapm_widgets)); +		snd_soc_dapm_add_routes(dapm, wm8581_dapm_routes, +					ARRAY_SIZE(wm8581_dapm_routes)); +		break; +	default: +		break; +	} +  	ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies),  				    wm8580->supplies);  	if (ret != 0) { @@ -914,12 +973,6 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8580 = {  	},  }; -static const struct of_device_id wm8580_of_match[] = { -	{ .compatible = "wlf,wm8580" }, -	{ }, -}; -MODULE_DEVICE_TABLE(of, wm8580_of_match); -  static const struct regmap_config wm8580_regmap = {  	.reg_bits = 7,  	.val_bits = 9, @@ -932,10 +985,25 @@ static const struct regmap_config wm8580_regmap = {  	.volatile_reg = wm8580_volatile,  }; -#if IS_ENABLED(CONFIG_I2C) +static const struct wm8580_driver_data wm8580_data = { +	.num_dacs = 3, +}; + +static const struct wm8580_driver_data wm8581_data = { +	.num_dacs = 4, +}; + +static const struct of_device_id wm8580_of_match[] = { +	{ .compatible = "wlf,wm8580", .data = &wm8580_data }, +	{ .compatible = "wlf,wm8581", .data = &wm8581_data }, +	{ }, +}; +MODULE_DEVICE_TABLE(of, wm8580_of_match); +  static int wm8580_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { +	const struct of_device_id *of_id;  	struct wm8580_priv *wm8580;  	int ret, i; @@ -960,6 +1028,15 @@ static int wm8580_i2c_probe(struct i2c_client *i2c,  	i2c_set_clientdata(i2c, wm8580); +	of_id = of_match_device(wm8580_of_match, &i2c->dev); +	if (of_id) +		wm8580->drvdata = of_id->data; + +	if (!wm8580->drvdata) { +		dev_err(&i2c->dev, "failed to find driver data\n"); +		return -EINVAL; +	} +  	ret =  snd_soc_register_codec(&i2c->dev,  			&soc_codec_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai)); @@ -973,7 +1050,8 @@ static int wm8580_i2c_remove(struct i2c_client *client)  }  static const struct i2c_device_id wm8580_i2c_id[] = { -	{ "wm8580", 0 }, +	{ "wm8580", (kernel_ulong_t)&wm8580_data }, +	{ "wm8581", (kernel_ulong_t)&wm8581_data },  	{ }  };  MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id); @@ -987,31 +1065,10 @@ static struct i2c_driver wm8580_i2c_driver = {  	.remove =   wm8580_i2c_remove,  	.id_table = wm8580_i2c_id,  }; -#endif -static int __init wm8580_modinit(void) -{ -	int ret = 0; - -#if IS_ENABLED(CONFIG_I2C) -	ret = i2c_add_driver(&wm8580_i2c_driver); -	if (ret != 0) { -		pr_err("Failed to register WM8580 I2C driver: %d\n", ret); -	} -#endif - -	return ret; -} -module_init(wm8580_modinit); - -static void __exit wm8580_exit(void) -{ -#if IS_ENABLED(CONFIG_I2C) -	i2c_del_driver(&wm8580_i2c_driver); -#endif -} -module_exit(wm8580_exit); +module_i2c_driver(wm8580_i2c_driver);  MODULE_DESCRIPTION("ASoC WM8580 driver");  MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); +MODULE_AUTHOR("Matt Flax <flatmax@flatmax.org>");  MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h index 94edac144bcb..8b39e3677ac8 100644 --- a/sound/soc/codecs/wm8753.h +++ b/sound/soc/codecs/wm8753.h @@ -112,7 +112,4 @@  #define WM8753_VXCLK_DIV_8	(3 << 6)  #define WM8753_VXCLK_DIV_16	(4 << 6) -#define WM8753_DAI_HIFI		0 -#define WM8753_DAI_VOICE		1 -  #endif diff --git a/sound/soc/codecs/wm8978.h b/sound/soc/codecs/wm8978.h index 6ae43495b7cf..0dcf6868dff6 100644 --- a/sound/soc/codecs/wm8978.h +++ b/sound/soc/codecs/wm8978.h @@ -78,8 +78,8 @@ enum wm8978_clk_id {  };  enum wm8978_sysclk_src { +	WM8978_MCLK = 0,  	WM8978_PLL, -	WM8978_MCLK  };  #endif	/* __WM8978_H__ */ diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 2f2821b3382f..ee0c8639c743 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -108,6 +108,9 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,  		break;  	case SND_SOC_DAPM_PRE_PMD:  		break; +	case SND_SOC_DAPM_PRE_PMU: +	case SND_SOC_DAPM_POST_PMD: +		return arizona_clk_ev(w, kcontrol, event);  	default:  		return 0;  	} @@ -408,9 +411,11 @@ static const struct snd_kcontrol_new wm8997_aec_loopback_mux =  static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = {  SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,  		    0, wm8997_sysclk_ev, -		    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +		    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | +		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),  SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, -		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), +		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev, +		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),  SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,  		    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),  SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, @@ -1055,11 +1060,13 @@ static struct snd_soc_dai_driver wm8997_dai[] = {  static int wm8997_codec_probe(struct snd_soc_codec *codec)  {  	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); +	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);  	struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);  	arizona_init_spk(codec); +	arizona_init_notifiers(codec); -	snd_soc_dapm_disable_pin(dapm, "HAPTICS"); +	snd_soc_component_disable_pin(component, "HAPTICS");  	priv->core.arizona->dapm = dapm; @@ -1072,8 +1079,6 @@ static int wm8997_codec_remove(struct snd_soc_codec *codec)  	priv->core.arizona->dapm = NULL; -	arizona_free_spk(codec); -  	return 0;  } @@ -1119,7 +1124,7 @@ static int wm8997_probe(struct platform_device *pdev)  {  	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);  	struct wm8997_priv *wm8997; -	int i; +	int i, ret;  	wm8997 = devm_kzalloc(&pdev->dev, sizeof(struct wm8997_priv),  			      GFP_KERNEL); @@ -1159,15 +1164,33 @@ static int wm8997_probe(struct platform_device *pdev)  	pm_runtime_enable(&pdev->dev);  	pm_runtime_idle(&pdev->dev); -	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8997, -				      wm8997_dai, ARRAY_SIZE(wm8997_dai)); +	ret = arizona_init_spk_irqs(arizona); +	if (ret < 0) +		return ret; + +	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8997, +				     wm8997_dai, ARRAY_SIZE(wm8997_dai)); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); +		goto err_spk_irqs; +	} + +err_spk_irqs: +	arizona_free_spk_irqs(arizona); + +	return ret;  }  static int wm8997_remove(struct platform_device *pdev)  { +	struct wm8997_priv *wm8997 = platform_get_drvdata(pdev); +	struct arizona *arizona = wm8997->core.arizona; +  	snd_soc_unregister_codec(&pdev->dev);  	pm_runtime_disable(&pdev->dev); +	arizona_free_spk_irqs(arizona); +  	return 0;  } diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index bcc2e1060a6c..3694f5958d86 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -541,9 +541,11 @@ static const struct snd_kcontrol_new wm8998_aec_loopback_mux[] = {  static const struct snd_soc_dapm_widget wm8998_dapm_widgets[] = {  SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, -		    ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0), +		    ARIZONA_SYSCLK_ENA_SHIFT, 0, arizona_clk_ev, +		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),  SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, -		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), +		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev, +		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),  SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,  		    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),  SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, @@ -1318,13 +1320,15 @@ static int wm8998_codec_probe(struct snd_soc_codec *codec)  {  	struct wm8998_priv *priv = snd_soc_codec_get_drvdata(codec);  	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); +	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);  	priv->core.arizona->dapm = dapm;  	arizona_init_spk(codec);  	arizona_init_gpio(codec); +	arizona_init_notifiers(codec); -	snd_soc_dapm_disable_pin(dapm, "HAPTICS"); +	snd_soc_component_disable_pin(component, "HAPTICS");  	return 0;  } @@ -1335,8 +1339,6 @@ static int wm8998_codec_remove(struct snd_soc_codec *codec)  	priv->core.arizona->dapm = NULL; -	arizona_free_spk(codec); -  	return 0;  } @@ -1385,7 +1387,7 @@ static int wm8998_probe(struct platform_device *pdev)  {  	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);  	struct wm8998_priv *wm8998; -	int i; +	int i, ret;  	wm8998 = devm_kzalloc(&pdev->dev, sizeof(struct wm8998_priv),  			      GFP_KERNEL); @@ -1417,15 +1419,35 @@ static int wm8998_probe(struct platform_device *pdev)  	pm_runtime_enable(&pdev->dev);  	pm_runtime_idle(&pdev->dev); -	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8998, -				      wm8998_dai, ARRAY_SIZE(wm8998_dai)); +	ret = arizona_init_spk_irqs(arizona); +	if (ret < 0) +		return ret; + +	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8998, +				     wm8998_dai, ARRAY_SIZE(wm8998_dai)); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); +		goto err_spk_irqs; +	} + +	return ret; + +err_spk_irqs: +	arizona_free_spk_irqs(arizona); + +	return ret;  }  static int wm8998_remove(struct platform_device *pdev)  { +	struct wm8998_priv *wm8998 = platform_get_drvdata(pdev); +	struct arizona *arizona = wm8998->core.arizona; +  	snd_soc_unregister_codec(&pdev->dev);  	pm_runtime_disable(&pdev->dev); +	arizona_free_spk_irqs(arizona); +  	return 0;  } diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 856867ec2813..6febef337dd2 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1304,7 +1304,6 @@ static const struct regmap_config wm9081_regmap = {  	.cache_type = REGCACHE_RBTREE,  }; -#if IS_ENABLED(CONFIG_I2C)  static int wm9081_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  { @@ -1384,7 +1383,6 @@ static struct i2c_driver wm9081_i2c_driver = {  	.remove =   wm9081_i2c_remove,  	.id_table = wm9081_i2c_id,  }; -#endif  module_i2c_driver(wm9081_i2c_driver); diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index dcdd055db57b..f6d5c0f2aea5 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -14,37 +14,58 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/device.h> +#include <linux/regmap.h>  #include <sound/core.h>  #include <sound/pcm.h>  #include <sound/ac97_codec.h>  #include <sound/initval.h>  #include <sound/soc.h> -#include "wm9705.h" -  #define WM9705_VENDOR_ID 0x574d4c05  #define WM9705_VENDOR_ID_MASK 0xffffffff -/* - * WM9705 register cache - */ -static const u16 wm9705_reg[] = { -	0x6150, 0x8000, 0x8000, 0x8000, /* 0x0  */ -	0x0000, 0x8000, 0x8008, 0x8008, /* 0x8  */ -	0x8808, 0x8808, 0x8808, 0x8808, /* 0x10 */ -	0x8808, 0x0000, 0x8000, 0x0000, /* 0x18 */ -	0x0000, 0x0000, 0x0000, 0x000f, /* 0x20 */ -	0x0605, 0x0000, 0xbb80, 0x0000, /* 0x28 */ -	0x0000, 0xbb80, 0x0000, 0x0000, /* 0x30 */ -	0x0000, 0x2000, 0x0000, 0x0000, /* 0x38 */ -	0x0000, 0x0000, 0x0000, 0x0000, /* 0x40 */ -	0x0000, 0x0000, 0x0000, 0x0000, /* 0x48 */ -	0x0000, 0x0000, 0x0000, 0x0000, /* 0x50 */ -	0x0000, 0x0000, 0x0000, 0x0000, /* 0x58 */ -	0x0000, 0x0000, 0x0000, 0x0000, /* 0x60 */ -	0x0000, 0x0000, 0x0000, 0x0000, /* 0x68 */ -	0x0000, 0x0808, 0x0000, 0x0006, /* 0x70 */ -	0x0000, 0x0000, 0x574d, 0x4c05, /* 0x78 */ +static const struct reg_default wm9705_reg_defaults[] = { +	{ 0x02, 0x8000 }, +	{ 0x04, 0x8000 }, +	{ 0x06, 0x8000 }, +	{ 0x0a, 0x8000 }, +	{ 0x0c, 0x8008 }, +	{ 0x0e, 0x8008 }, +	{ 0x10, 0x8808 }, +	{ 0x12, 0x8808 }, +	{ 0x14, 0x8808 }, +	{ 0x16, 0x8808 }, +	{ 0x18, 0x8808 }, +	{ 0x1a, 0x0000 }, +	{ 0x1c, 0x8000 }, +	{ 0x20, 0x0000 }, +	{ 0x22, 0x0000 }, +	{ 0x26, 0x000f }, +	{ 0x28, 0x0605 }, +	{ 0x2a, 0x0000 }, +	{ 0x2c, 0xbb80 }, +	{ 0x32, 0xbb80 }, +	{ 0x34, 0x2000 }, +	{ 0x5a, 0x0000 }, +	{ 0x5c, 0x0000 }, +	{ 0x72, 0x0808 }, +	{ 0x74, 0x0000 }, +	{ 0x76, 0x0006 }, +	{ 0x78, 0x0000 }, +	{ 0x7a, 0x0000 }, +}; + +static const struct regmap_config wm9705_regmap_config = { +	.reg_bits = 16, +	.reg_stride = 2, +	.val_bits = 16, +	.max_register = 0x7e, +	.cache_type = REGCACHE_RBTREE, + +	.volatile_reg = regmap_ac97_default_volatile, + +	.reg_defaults = wm9705_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm9705_reg_defaults),  };  static const struct snd_kcontrol_new wm9705_snd_ac97_controls[] = { @@ -203,57 +224,20 @@ static const struct snd_soc_dapm_route wm9705_audio_map[] = {  	{"Right ADC", NULL, "ADC PGA"},  }; -/* We use a register cache to enhance read performance. */ -static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) -{ -	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); -	u16 *cache = codec->reg_cache; - -	switch (reg) { -	case AC97_RESET: -	case AC97_VENDOR_ID1: -	case AC97_VENDOR_ID2: -		return soc_ac97_ops->read(ac97, reg); -	default: -		reg = reg >> 1; - -		if (reg >= (ARRAY_SIZE(wm9705_reg))) -			return -EIO; - -		return cache[reg]; -	} -} - -static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, -	unsigned int val) -{ -	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); -	u16 *cache = codec->reg_cache; - -	soc_ac97_ops->write(ac97, reg, val); -	reg = reg >> 1; -	if (reg < (ARRAY_SIZE(wm9705_reg))) -		cache[reg] = val; - -	return 0; -} -  static int ac97_prepare(struct snd_pcm_substream *substream,  			struct snd_soc_dai *dai)  {  	struct snd_soc_codec *codec = dai->codec;  	int reg; -	u16 vra; -	vra = ac97_read(codec, AC97_EXTENDED_STATUS); -	ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1); +	snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x1, 0x1);  	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)  		reg = AC97_PCM_FRONT_DAC_RATE;  	else  		reg = AC97_PCM_LR_ADC_RATE; -	return ac97_write(codec, reg, substream->runtime->rate); +	return snd_soc_write(codec, reg, substream->runtime->rate);  }  #define WM9705_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \ @@ -299,9 +283,9 @@ static struct snd_soc_dai_driver wm9705_dai[] = {  #ifdef CONFIG_PM  static int wm9705_soc_suspend(struct snd_soc_codec *codec)  { -	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - -	soc_ac97_ops->write(ac97, AC97_POWERDOWN, 0xffff); +	regcache_cache_bypass(codec->component.regmap, true); +	snd_soc_write(codec, AC97_POWERDOWN, 0xffff); +	regcache_cache_bypass(codec->component.regmap, false);  	return 0;  } @@ -309,17 +293,14 @@ static int wm9705_soc_suspend(struct snd_soc_codec *codec)  static int wm9705_soc_resume(struct snd_soc_codec *codec)  {  	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); -	int i, ret; -	u16 *cache = codec->reg_cache; +	int ret;  	ret = snd_ac97_reset(ac97, true, WM9705_VENDOR_ID,  		WM9705_VENDOR_ID_MASK);  	if (ret < 0)  		return ret; -	for (i = 2; i < ARRAY_SIZE(wm9705_reg) << 1; i += 2) { -		soc_ac97_ops->write(ac97, i, cache[i>>1]); -	} +	regcache_sync(codec->component.regmap);  	return 0;  } @@ -331,6 +312,8 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec)  static int wm9705_soc_probe(struct snd_soc_codec *codec)  {  	struct snd_ac97 *ac97; +	struct regmap *regmap; +	int ret;  	ac97 = snd_soc_new_ac97_codec(codec, WM9705_VENDOR_ID,  		WM9705_VENDOR_ID_MASK); @@ -339,15 +322,26 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec)  		return PTR_ERR(ac97);  	} +	regmap = regmap_init_ac97(ac97, &wm9705_regmap_config); +	if (IS_ERR(regmap)) { +		ret = PTR_ERR(regmap); +		goto err_free_ac97_codec; +	} +  	snd_soc_codec_set_drvdata(codec, ac97); +	snd_soc_codec_init_regmap(codec, regmap);  	return 0; +err_free_ac97_codec: +	snd_soc_free_ac97_codec(ac97); +	return ret;  }  static int wm9705_soc_remove(struct snd_soc_codec *codec)  {  	struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); +	snd_soc_codec_exit_regmap(codec);  	snd_soc_free_ac97_codec(ac97);  	return 0;  } @@ -357,12 +351,6 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm9705 = {  	.remove = 	wm9705_soc_remove,  	.suspend =	wm9705_soc_suspend,  	.resume =	wm9705_soc_resume, -	.read = ac97_read, -	.write = ac97_write, -	.reg_cache_size = ARRAY_SIZE(wm9705_reg), -	.reg_word_size = sizeof(u16), -	.reg_cache_step = 2, -	.reg_cache_default = wm9705_reg,  	.component_driver = {  		.controls		= wm9705_snd_ac97_controls, diff --git a/sound/soc/codecs/wm9705.h b/sound/soc/codecs/wm9705.h deleted file mode 100644 index 23ea9ce47359..000000000000 --- a/sound/soc/codecs/wm9705.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * wm9705.h  --  WM9705 Soc Audio driver - */ - -#ifndef _WM9705_H -#define _WM9705_H - -#define WM9705_DAI_AC97_HIFI	0 -#define WM9705_DAI_AC97_AUX	1 - -#endif diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 557709eac698..1a3e1797994a 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -15,13 +15,13 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/device.h> +#include <linux/regmap.h>  #include <sound/core.h>  #include <sound/pcm.h>  #include <sound/ac97_codec.h>  #include <sound/initval.h>  #include <sound/soc.h>  #include <sound/tlv.h> -#include "wm9712.h"  #define WM9712_VENDOR_ID 0x574d4c12  #define WM9712_VENDOR_ID_MASK 0xffffffff @@ -32,31 +32,66 @@ struct wm9712_priv {  	struct mutex lock;  }; -static unsigned int ac97_read(struct snd_soc_codec *codec, -	unsigned int reg); -static int ac97_write(struct snd_soc_codec *codec, -	unsigned int reg, unsigned int val); +static const struct reg_default wm9712_reg_defaults[] = { +	{ 0x02, 0x8000 }, +	{ 0x04, 0x8000 }, +	{ 0x06, 0x8000 }, +	{ 0x08, 0x0f0f }, +	{ 0x0a, 0xaaa0 }, +	{ 0x0c, 0xc008 }, +	{ 0x0e, 0x6808 }, +	{ 0x10, 0xe808 }, +	{ 0x12, 0xaaa0 }, +	{ 0x14, 0xad00 }, +	{ 0x16, 0x8000 }, +	{ 0x18, 0xe808 }, +	{ 0x1a, 0x3000 }, +	{ 0x1c, 0x8000 }, +	{ 0x20, 0x0000 }, +	{ 0x22, 0x0000 }, +	{ 0x26, 0x000f }, +	{ 0x28, 0x0605 }, +	{ 0x2a, 0x0410 }, +	{ 0x2c, 0xbb80 }, +	{ 0x2e, 0xbb80 }, +	{ 0x32, 0xbb80 }, +	{ 0x34, 0x2000 }, +	{ 0x4c, 0xf83e }, +	{ 0x4e, 0xffff }, +	{ 0x50, 0x0000 }, +	{ 0x52, 0x0000 }, +	{ 0x56, 0xf83e }, +	{ 0x58, 0x0008 }, +	{ 0x5c, 0x0000 }, +	{ 0x60, 0xb032 }, +	{ 0x62, 0x3e00 }, +	{ 0x64, 0x0000 }, +	{ 0x76, 0x0006 }, +	{ 0x78, 0x0001 }, +	{ 0x7a, 0x0000 }, +}; -/* - * WM9712 register cache - */ -static const u16 wm9712_reg[] = { -	0x6174, 0x8000, 0x8000, 0x8000, /*  6 */ -	0x0f0f, 0xaaa0, 0xc008, 0x6808, /*  e */ -	0xe808, 0xaaa0, 0xad00, 0x8000, /* 16 */ -	0xe808, 0x3000, 0x8000, 0x0000, /* 1e */ -	0x0000, 0x0000, 0x0000, 0x000f, /* 26 */ -	0x0405, 0x0410, 0xbb80, 0xbb80, /* 2e */ -	0x0000, 0xbb80, 0x0000, 0x0000, /* 36 */ -	0x0000, 0x2000, 0x0000, 0x0000, /* 3e */ -	0x0000, 0x0000, 0x0000, 0x0000, /* 46 */ -	0x0000, 0x0000, 0xf83e, 0xffff, /* 4e */ -	0x0000, 0x0000, 0x0000, 0xf83e, /* 56 */ -	0x0008, 0x0000, 0x0000, 0x0000, /* 5e */ -	0xb032, 0x3e00, 0x0000, 0x0000, /* 66 */ -	0x0000, 0x0000, 0x0000, 0x0000, /* 6e */ -	0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ -	0x0001, 0x0000, 0x574d, 0x4c12, /* 7e */ +static bool wm9712_volatile_reg(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case AC97_REC_GAIN: +		return true; +	default: +		return regmap_ac97_default_volatile(dev, reg); +	} +} + +static const struct regmap_config wm9712_regmap_config = { +	.reg_bits = 16, +	.reg_stride = 2, +	.val_bits = 16, +	.max_register = 0x7e, +	.cache_type = REGCACHE_RBTREE, + +	.volatile_reg = wm9712_volatile_reg, + +	.reg_defaults = wm9712_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm9712_reg_defaults),  };  #define HPL_MIXER	0x0 @@ -187,7 +222,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value;  	unsigned int mixer, mask, shift, old; -	struct snd_soc_dapm_update update; +	struct snd_soc_dapm_update update = { 0 };  	bool change;  	mixer = mc->shift >> 8; @@ -485,75 +520,36 @@ static const struct snd_soc_dapm_route wm9712_audio_map[] = {  	{"ROUT2", NULL, "Speaker PGA"},  }; -static unsigned int ac97_read(struct snd_soc_codec *codec, -	unsigned int reg) -{ -	struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); -	u16 *cache = codec->reg_cache; - -	if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || -		reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || -		reg == AC97_REC_GAIN) -		return soc_ac97_ops->read(wm9712->ac97, reg); -	else { -		reg = reg >> 1; - -		if (reg >= (ARRAY_SIZE(wm9712_reg))) -			return -EIO; - -		return cache[reg]; -	} -} - -static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, -	unsigned int val) -{ -	struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); -	u16 *cache = codec->reg_cache; - -	soc_ac97_ops->write(wm9712->ac97, reg, val); -	reg = reg >> 1; -	if (reg < (ARRAY_SIZE(wm9712_reg))) -		cache[reg] = val; - -	return 0; -} -  static int ac97_prepare(struct snd_pcm_substream *substream,  			struct snd_soc_dai *dai)  {  	struct snd_soc_codec *codec = dai->codec;  	int reg; -	u16 vra;  	struct snd_pcm_runtime *runtime = substream->runtime; -	vra = ac97_read(codec, AC97_EXTENDED_STATUS); -	ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1); +	snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x1, 0x1);  	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)  		reg = AC97_PCM_FRONT_DAC_RATE;  	else  		reg = AC97_PCM_LR_ADC_RATE; -	return ac97_write(codec, reg, runtime->rate); +	return snd_soc_write(codec, reg, runtime->rate);  }  static int ac97_aux_prepare(struct snd_pcm_substream *substream,  			    struct snd_soc_dai *dai)  {  	struct snd_soc_codec *codec = dai->codec; -	u16 vra, xsle;  	struct snd_pcm_runtime *runtime = substream->runtime; -	vra = ac97_read(codec, AC97_EXTENDED_STATUS); -	ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1); -	xsle = ac97_read(codec, AC97_PCI_SID); -	ac97_write(codec, AC97_PCI_SID, xsle | 0x8000); +	snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x1, 0x1); +	snd_soc_update_bits(codec, AC97_PCI_SID, 0x8000, 0x8000);  	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)  		return -ENODEV; -	return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); +	return snd_soc_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate);  }  #define WM9712_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ @@ -605,12 +601,12 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec,  	case SND_SOC_BIAS_PREPARE:  		break;  	case SND_SOC_BIAS_STANDBY: -		ac97_write(codec, AC97_POWERDOWN, 0x0000); +		snd_soc_write(codec, AC97_POWERDOWN, 0x0000);  		break;  	case SND_SOC_BIAS_OFF:  		/* disable everything including AC link */ -		ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); -		ac97_write(codec, AC97_POWERDOWN, 0xffff); +		snd_soc_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); +		snd_soc_write(codec, AC97_POWERDOWN, 0xffff);  		break;  	}  	return 0; @@ -619,8 +615,7 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec,  static int wm9712_soc_resume(struct snd_soc_codec *codec)  {  	struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); -	int i, ret; -	u16 *cache = codec->reg_cache; +	int ret;  	ret = snd_ac97_reset(wm9712->ac97, true, WM9712_VENDOR_ID,  		WM9712_VENDOR_ID_MASK); @@ -629,15 +624,8 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec)  	snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); -	if (ret == 0) { -		/* Sync reg_cache with the hardware after cold reset */ -		for (i = 2; i < ARRAY_SIZE(wm9712_reg) << 1; i += 2) { -			if (i == AC97_INT_PAGING || i == AC97_POWERDOWN || -			    (i > 0x58 && i != 0x5c)) -				continue; -			soc_ac97_ops->write(wm9712->ac97, i, cache[i>>1]); -		} -	} +	if (ret == 0) +		regcache_sync(codec->component.regmap);  	return ret;  } @@ -645,6 +633,7 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec)  static int wm9712_soc_probe(struct snd_soc_codec *codec)  {  	struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); +	struct regmap *regmap;  	int ret;  	wm9712->ac97 = snd_soc_new_ac97_codec(codec, WM9712_VENDOR_ID, @@ -655,16 +644,28 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)  		return ret;  	} +	regmap = regmap_init_ac97(wm9712->ac97, &wm9712_regmap_config); +	if (IS_ERR(regmap)) { +		ret = PTR_ERR(regmap); +		goto err_free_ac97_codec; +	} + +	snd_soc_codec_init_regmap(codec, regmap); +  	/* set alc mux to none */ -	ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); +	snd_soc_update_bits(codec, AC97_VIDEO, 0x3000, 0x3000);  	return 0; +err_free_ac97_codec: +	snd_soc_free_ac97_codec(wm9712->ac97); +	return ret;  }  static int wm9712_soc_remove(struct snd_soc_codec *codec)  {  	struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); +	snd_soc_codec_exit_regmap(codec);  	snd_soc_free_ac97_codec(wm9712->ac97);  	return 0;  } @@ -673,14 +674,8 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm9712 = {  	.probe = 	wm9712_soc_probe,  	.remove = 	wm9712_soc_remove,  	.resume =	wm9712_soc_resume, -	.read = ac97_read, -	.write = ac97_write,  	.set_bias_level = wm9712_set_bias_level,  	.suspend_bias_off = true, -	.reg_cache_size = ARRAY_SIZE(wm9712_reg), -	.reg_word_size = sizeof(u16), -	.reg_cache_step = 2, -	.reg_cache_default = wm9712_reg,  	.component_driver = {  		.controls		= wm9712_snd_ac97_controls, diff --git a/sound/soc/codecs/wm9712.h b/sound/soc/codecs/wm9712.h deleted file mode 100644 index fb69c3aa4ed0..000000000000 --- a/sound/soc/codecs/wm9712.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * wm9712.h  --  WM9712 Soc Audio driver - */ - -#ifndef _WM9712_H -#define _WM9712_H - -#define WM9712_DAI_AC97_HIFI	0 -#define WM9712_DAI_AC97_AUX		1 - -#endif diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index e4301ddb1b84..7e4822185feb 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -231,7 +231,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value;  	unsigned int mixer, mask, shift, old; -	struct snd_soc_dapm_update update; +	struct snd_soc_dapm_update update = { 0 };  	bool change;  	mixer = mc->shift >> 8; diff --git a/sound/soc/codecs/wm9713.h b/sound/soc/codecs/wm9713.h index 53df11b1f727..7ecffc563016 100644 --- a/sound/soc/codecs/wm9713.h +++ b/sound/soc/codecs/wm9713.h @@ -41,8 +41,4 @@  #define WM9713_PCMBCLK_DIV_8	(3 << 9)  #define WM9713_PCMBCLK_DIV_16	(4 << 9) -#define WM9713_DAI_AC97_HIFI	0 -#define WM9713_DAI_AC97_AUX		1 -#define WM9713_DAI_PCM_VOICE	2 -  #endif diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index b943dde8dbe5..593b7d1aed46 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -162,6 +162,16 @@  #define ADSP_MAX_STD_CTRL_SIZE               512 +#define WM_ADSP_ACKED_CTL_TIMEOUT_MS         100 +#define WM_ADSP_ACKED_CTL_N_QUICKPOLLS       10 +#define WM_ADSP_ACKED_CTL_MIN_VALUE          0 +#define WM_ADSP_ACKED_CTL_MAX_VALUE          0xFFFFFF + +/* + * Event control messages + */ +#define WM_ADSP_FW_EVENT_SHUTDOWN            0x000001 +  struct wm_adsp_buf {  	struct list_head list;  	void *buf; @@ -177,7 +187,7 @@ static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len,  	buf->buf = vmalloc(len);  	if (!buf->buf) { -		vfree(buf); +		kfree(buf);  		return NULL;  	}  	memcpy(buf->buf, src, len); @@ -441,11 +451,29 @@ struct wm_coeff_ctl {  	unsigned int offset;  	size_t len;  	unsigned int set:1; -	struct snd_kcontrol *kcontrol;  	struct soc_bytes_ext bytes_ext;  	unsigned int flags; +	unsigned int type;  }; +static const char *wm_adsp_mem_region_name(unsigned int type) +{ +	switch (type) { +	case WMFW_ADSP1_PM: +		return "PM"; +	case WMFW_ADSP1_DM: +		return "DM"; +	case WMFW_ADSP2_XM: +		return "XM"; +	case WMFW_ADSP2_YM: +		return "YM"; +	case WMFW_ADSP1_ZM: +		return "ZM"; +	default: +		return NULL; +	} +} +  #ifdef CONFIG_DEBUG_FS  static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s)  { @@ -727,6 +755,24 @@ static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext)  	return container_of(ext, struct wm_coeff_ctl, bytes_ext);  } +static int wm_coeff_base_reg(struct wm_coeff_ctl *ctl, unsigned int *reg) +{ +	const struct wm_adsp_alg_region *alg_region = &ctl->alg_region; +	struct wm_adsp *dsp = ctl->dsp; +	const struct wm_adsp_region *mem; + +	mem = wm_adsp_find_region(dsp, alg_region->type); +	if (!mem) { +		adsp_err(dsp, "No base for region %x\n", +			 alg_region->type); +		return -EINVAL; +	} + +	*reg = wm_adsp_region_to_reg(mem, ctl->alg_region.base + ctl->offset); + +	return 0; +} +  static int wm_coeff_info(struct snd_kcontrol *kctl,  			 struct snd_ctl_elem_info *uinfo)  { @@ -734,30 +780,94 @@ static int wm_coeff_info(struct snd_kcontrol *kctl,  		(struct soc_bytes_ext *)kctl->private_value;  	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); -	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; -	uinfo->count = ctl->len; +	switch (ctl->type) { +	case WMFW_CTL_TYPE_ACKED: +		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; +		uinfo->value.integer.min = WM_ADSP_ACKED_CTL_MIN_VALUE; +		uinfo->value.integer.max = WM_ADSP_ACKED_CTL_MAX_VALUE; +		uinfo->value.integer.step = 1; +		uinfo->count = 1; +		break; +	default: +		uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; +		uinfo->count = ctl->len; +		break; +	} +  	return 0;  } +static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl, +					unsigned int event_id) +{ +	struct wm_adsp *dsp = ctl->dsp; +	u32 val = cpu_to_be32(event_id); +	unsigned int reg; +	int i, ret; + +	ret = wm_coeff_base_reg(ctl, ®); +	if (ret) +		return ret; + +	adsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n", +		 event_id, ctl->alg_region.alg, +		 wm_adsp_mem_region_name(ctl->alg_region.type), ctl->offset); + +	ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val)); +	if (ret) { +		adsp_err(dsp, "Failed to write %x: %d\n", reg, ret); +		return ret; +	} + +	/* +	 * Poll for ack, we initially poll at ~1ms intervals for firmwares +	 * that respond quickly, then go to ~10ms polls. A firmware is unlikely +	 * to ack instantly so we do the first 1ms delay before reading the +	 * control to avoid a pointless bus transaction +	 */ +	for (i = 0; i < WM_ADSP_ACKED_CTL_TIMEOUT_MS;) { +		switch (i) { +		case 0 ... WM_ADSP_ACKED_CTL_N_QUICKPOLLS - 1: +			usleep_range(1000, 2000); +			i++; +			break; +		default: +			usleep_range(10000, 20000); +			i += 10; +			break; +		} + +		ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); +		if (ret) { +			adsp_err(dsp, "Failed to read %x: %d\n", reg, ret); +			return ret; +		} + +		if (val == 0) { +			adsp_dbg(dsp, "Acked control ACKED at poll %u\n", i); +			return 0; +		} +	} + +	adsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n", +		  reg, ctl->alg_region.alg, +		  wm_adsp_mem_region_name(ctl->alg_region.type), +		  ctl->offset); + +	return -ETIMEDOUT; +} +  static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,  				  const void *buf, size_t len)  { -	struct wm_adsp_alg_region *alg_region = &ctl->alg_region; -	const struct wm_adsp_region *mem;  	struct wm_adsp *dsp = ctl->dsp;  	void *scratch;  	int ret;  	unsigned int reg; -	mem = wm_adsp_find_region(dsp, alg_region->type); -	if (!mem) { -		adsp_err(dsp, "No base for region %x\n", -			 alg_region->type); -		return -EINVAL; -	} - -	reg = ctl->alg_region.base + ctl->offset; -	reg = wm_adsp_region_to_reg(mem, reg); +	ret = wm_coeff_base_reg(ctl, ®); +	if (ret) +		return ret;  	scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA);  	if (!scratch) @@ -823,25 +933,41 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,  	return ret;  } +static int wm_coeff_put_acked(struct snd_kcontrol *kctl, +			      struct snd_ctl_elem_value *ucontrol) +{ +	struct soc_bytes_ext *bytes_ext = +		(struct soc_bytes_ext *)kctl->private_value; +	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); +	unsigned int val = ucontrol->value.integer.value[0]; +	int ret; + +	if (val == 0) +		return 0;	/* 0 means no event */ + +	mutex_lock(&ctl->dsp->pwr_lock); + +	if (ctl->enabled) +		ret = wm_coeff_write_acked_control(ctl, val); +	else +		ret = -EPERM; + +	mutex_unlock(&ctl->dsp->pwr_lock); + +	return ret; +} +  static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,  				 void *buf, size_t len)  { -	struct wm_adsp_alg_region *alg_region = &ctl->alg_region; -	const struct wm_adsp_region *mem;  	struct wm_adsp *dsp = ctl->dsp;  	void *scratch;  	int ret;  	unsigned int reg; -	mem = wm_adsp_find_region(dsp, alg_region->type); -	if (!mem) { -		adsp_err(dsp, "No base for region %x\n", -			 alg_region->type); -		return -EINVAL; -	} - -	reg = ctl->alg_region.base + ctl->offset; -	reg = wm_adsp_region_to_reg(mem, reg); +	ret = wm_coeff_base_reg(ctl, ®); +	if (ret) +		return ret;  	scratch = kmalloc(len, GFP_KERNEL | GFP_DMA);  	if (!scratch) @@ -918,6 +1044,21 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,  	return ret;  } +static int wm_coeff_get_acked(struct snd_kcontrol *kcontrol, +			      struct snd_ctl_elem_value *ucontrol) +{ +	/* +	 * Although it's not useful to read an acked control, we must satisfy +	 * user-side assumptions that all controls are readable and that a +	 * write of the same value should be filtered out (it's valid to send +	 * the same event number again to the firmware). We therefore return 0, +	 * meaning "no event" so valid event numbers will always be a change +	 */ +	ucontrol->value.integer.value[0] = 0; + +	return 0; +} +  struct wmfw_ctl_work {  	struct wm_adsp *dsp;  	struct wm_coeff_ctl *ctl; @@ -967,30 +1108,35 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)  	kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);  	if (!kcontrol)  		return -ENOMEM; -	kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;  	kcontrol->name = ctl->name;  	kcontrol->info = wm_coeff_info; -	kcontrol->get = wm_coeff_get; -	kcontrol->put = wm_coeff_put;  	kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;  	kcontrol->tlv.c = snd_soc_bytes_tlv_callback;  	kcontrol->private_value = (unsigned long)&ctl->bytes_ext; +	kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len); -	ctl->bytes_ext.max = ctl->len; -	ctl->bytes_ext.get = wm_coeff_tlv_get; -	ctl->bytes_ext.put = wm_coeff_tlv_put; +	switch (ctl->type) { +	case WMFW_CTL_TYPE_ACKED: +		kcontrol->get = wm_coeff_get_acked; +		kcontrol->put = wm_coeff_put_acked; +		break; +	default: +		kcontrol->get = wm_coeff_get; +		kcontrol->put = wm_coeff_put; -	kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len); +		ctl->bytes_ext.max = ctl->len; +		ctl->bytes_ext.get = wm_coeff_tlv_get; +		ctl->bytes_ext.put = wm_coeff_tlv_put; +		break; +	} -	ret = snd_soc_add_card_controls(dsp->card, kcontrol, 1); +	ret = snd_soc_add_codec_controls(dsp->codec, kcontrol, 1);  	if (ret < 0)  		goto err_kcontrol;  	kfree(kcontrol); -	ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card, ctl->name); -  	return 0;  err_kcontrol: @@ -1035,6 +1181,27 @@ static int wm_coeff_sync_controls(struct wm_adsp *dsp)  	return 0;  } +static void wm_adsp_signal_event_controls(struct wm_adsp *dsp, +					  unsigned int event) +{ +	struct wm_coeff_ctl *ctl; +	int ret; + +	list_for_each_entry(ctl, &dsp->ctl_list, list) { +		if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT) +			continue; + +		if (!ctl->enabled) +			continue; + +		ret = wm_coeff_write_acked_control(ctl, event); +		if (ret) +			adsp_warn(dsp, +				  "Failed to send 0x%x event to alg 0x%x (%d)\n", +				  event, ctl->alg_region.alg, ret); +	} +} +  static void wm_adsp_ctl_work(struct work_struct *work)  {  	struct wmfw_ctl_work *ctl_work = container_of(work, @@ -1056,34 +1223,16 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,  				  const struct wm_adsp_alg_region *alg_region,  				  unsigned int offset, unsigned int len,  				  const char *subname, unsigned int subname_len, -				  unsigned int flags) +				  unsigned int flags, unsigned int type)  {  	struct wm_coeff_ctl *ctl;  	struct wmfw_ctl_work *ctl_work;  	char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; -	char *region_name; +	const char *region_name;  	int ret; -	if (flags & WMFW_CTL_FLAG_SYS) -		return 0; - -	switch (alg_region->type) { -	case WMFW_ADSP1_PM: -		region_name = "PM"; -		break; -	case WMFW_ADSP1_DM: -		region_name = "DM"; -		break; -	case WMFW_ADSP2_XM: -		region_name = "XM"; -		break; -	case WMFW_ADSP2_YM: -		region_name = "YM"; -		break; -	case WMFW_ADSP1_ZM: -		region_name = "ZM"; -		break; -	default: +	region_name = wm_adsp_mem_region_name(alg_region->type); +	if (!region_name) {  		adsp_err(dsp, "Unknown region type: %d\n", alg_region->type);  		return -EINVAL;  	} @@ -1139,6 +1288,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,  	ctl->dsp = dsp;  	ctl->flags = flags; +	ctl->type = type;  	ctl->offset = offset;  	ctl->len = len;  	ctl->cache = kzalloc(ctl->len, GFP_KERNEL); @@ -1149,6 +1299,9 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,  	list_add(&ctl->list, &dsp->ctl_list); +	if (flags & WMFW_CTL_FLAG_SYS) +		return 0; +  	ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);  	if (!ctl_work) {  		ret = -ENOMEM; @@ -1308,6 +1461,21 @@ static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,  	adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);  } +static int wm_adsp_check_coeff_flags(struct wm_adsp *dsp, +				const struct wm_coeff_parsed_coeff *coeff_blk, +				unsigned int f_required, +				unsigned int f_illegal) +{ +	if ((coeff_blk->flags & f_illegal) || +	    ((coeff_blk->flags & f_required) != f_required)) { +		adsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n", +			 coeff_blk->flags, coeff_blk->ctl_type); +		return -EINVAL; +	} + +	return 0; +} +  static int wm_adsp_parse_coeff(struct wm_adsp *dsp,  			       const struct wmfw_region *region)  { @@ -1324,6 +1492,28 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp,  		switch (coeff_blk.ctl_type) {  		case SNDRV_CTL_ELEM_TYPE_BYTES:  			break; +		case WMFW_CTL_TYPE_ACKED: +			if (coeff_blk.flags & WMFW_CTL_FLAG_SYS) +				continue;	/* ignore */ + +			ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk, +						WMFW_CTL_FLAG_VOLATILE | +						WMFW_CTL_FLAG_WRITEABLE | +						WMFW_CTL_FLAG_READABLE, +						0); +			if (ret) +				return -EINVAL; +			break; +		case WMFW_CTL_TYPE_HOSTEVENT: +			ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk, +						WMFW_CTL_FLAG_SYS | +						WMFW_CTL_FLAG_VOLATILE | +						WMFW_CTL_FLAG_WRITEABLE | +						WMFW_CTL_FLAG_READABLE, +						0); +			if (ret) +				return -EINVAL; +			break;  		default:  			adsp_err(dsp, "Unknown control type: %d\n",  				 coeff_blk.ctl_type); @@ -1338,7 +1528,8 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp,  					     coeff_blk.len,  					     coeff_blk.name,  					     coeff_blk.name_len, -					     coeff_blk.flags); +					     coeff_blk.flags, +					     coeff_blk.ctl_type);  		if (ret < 0)  			adsp_err(dsp, "Failed to create control: %.*s, %d\n",  				 coeff_blk.name_len, coeff_blk.name, ret); @@ -1491,23 +1682,11 @@ static int wm_adsp_load(struct wm_adsp *dsp)  			reg = offset;  			break;  		case WMFW_ADSP1_PM: -			region_name = "PM"; -			reg = wm_adsp_region_to_reg(mem, offset); -			break;  		case WMFW_ADSP1_DM: -			region_name = "DM"; -			reg = wm_adsp_region_to_reg(mem, offset); -			break;  		case WMFW_ADSP2_XM: -			region_name = "XM"; -			reg = wm_adsp_region_to_reg(mem, offset); -			break;  		case WMFW_ADSP2_YM: -			region_name = "YM"; -			reg = wm_adsp_region_to_reg(mem, offset); -			break;  		case WMFW_ADSP1_ZM: -			region_name = "ZM"; +			region_name = wm_adsp_mem_region_name(type);  			reg = wm_adsp_region_to_reg(mem, offset);  			break;  		default: @@ -1750,7 +1929,8 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp)  				len -= be32_to_cpu(adsp1_alg[i].dm);  				len *= 4;  				wm_adsp_create_control(dsp, alg_region, 0, -						       len, NULL, 0, 0); +						     len, NULL, 0, 0, +						     SNDRV_CTL_ELEM_TYPE_BYTES);  			} else {  				adsp_warn(dsp, "Missing length info for region DM with ID %x\n",  					  be32_to_cpu(adsp1_alg[i].alg.id)); @@ -1770,7 +1950,8 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp)  				len -= be32_to_cpu(adsp1_alg[i].zm);  				len *= 4;  				wm_adsp_create_control(dsp, alg_region, 0, -						       len, NULL, 0, 0); +						     len, NULL, 0, 0, +						     SNDRV_CTL_ELEM_TYPE_BYTES);  			} else {  				adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",  					  be32_to_cpu(adsp1_alg[i].alg.id)); @@ -1861,7 +2042,8 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)  				len -= be32_to_cpu(adsp2_alg[i].xm);  				len *= 4;  				wm_adsp_create_control(dsp, alg_region, 0, -						       len, NULL, 0, 0); +						     len, NULL, 0, 0, +						     SNDRV_CTL_ELEM_TYPE_BYTES);  			} else {  				adsp_warn(dsp, "Missing length info for region XM with ID %x\n",  					  be32_to_cpu(adsp2_alg[i].alg.id)); @@ -1881,7 +2063,8 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)  				len -= be32_to_cpu(adsp2_alg[i].ym);  				len *= 4;  				wm_adsp_create_control(dsp, alg_region, 0, -						       len, NULL, 0, 0); +						     len, NULL, 0, 0, +						     SNDRV_CTL_ELEM_TYPE_BYTES);  			} else {  				adsp_warn(dsp, "Missing length info for region YM with ID %x\n",  					  be32_to_cpu(adsp2_alg[i].alg.id)); @@ -1901,7 +2084,8 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)  				len -= be32_to_cpu(adsp2_alg[i].zm);  				len *= 4;  				wm_adsp_create_control(dsp, alg_region, 0, -						       len, NULL, 0, 0); +						     len, NULL, 0, 0, +						     SNDRV_CTL_ELEM_TYPE_BYTES);  			} else {  				adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",  					  be32_to_cpu(adsp2_alg[i].alg.id)); @@ -2114,7 +2298,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,  	int ret;  	unsigned int val; -	dsp->card = codec->component.card; +	dsp->codec = codec;  	mutex_lock(&dsp->pwr_lock); @@ -2325,8 +2509,6 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,  	struct wm_adsp *dsp = &dsps[w->shift];  	struct wm_coeff_ctl *ctl; -	dsp->card = codec->component.card; -  	switch (event) {  	case SND_SOC_DAPM_PRE_PMU:  		wm_adsp2_set_dspclk(dsp, freq); @@ -2393,14 +2575,22 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,  		mutex_lock(&dsp->pwr_lock); -		if (wm_adsp_fw[dsp->fw].num_caps != 0) +		if (wm_adsp_fw[dsp->fw].num_caps != 0) {  			ret = wm_adsp_buffer_init(dsp); +			if (ret < 0) { +				mutex_unlock(&dsp->pwr_lock); +				goto err; +			} +		}  		mutex_unlock(&dsp->pwr_lock);  		break;  	case SND_SOC_DAPM_PRE_PMD: +		/* Tell the firmware to cleanup */ +		wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN); +  		/* Log firmware state, it can be useful for analysis */  		wm_adsp2_show_fw_status(dsp); @@ -2441,6 +2631,8 @@ EXPORT_SYMBOL_GPL(wm_adsp2_event);  int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec)  { +	dsp->codec = codec; +  	wm_adsp2_init_debugfs(dsp, codec);  	return snd_soc_add_codec_controls(codec, diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 362dd7ce60d8..411d062c13f2 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -44,7 +44,7 @@ struct wm_adsp {  	int type;  	struct device *dev;  	struct regmap *regmap; -	struct snd_soc_card *card; +	struct snd_soc_codec *codec;  	int base;  	int sysclk_reg; @@ -110,18 +110,17 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,  int wm_adsp2_event(struct snd_soc_dapm_widget *w,  		   struct snd_kcontrol *kcontrol, int event); -extern int wm_adsp_compr_open(struct wm_adsp *dsp, -			      struct snd_compr_stream *stream); -extern int wm_adsp_compr_free(struct snd_compr_stream *stream); -extern int wm_adsp_compr_set_params(struct snd_compr_stream *stream, -				    struct snd_compr_params *params); -extern int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, -				  struct snd_compr_caps *caps); -extern int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd); -extern int wm_adsp_compr_handle_irq(struct wm_adsp *dsp); -extern int wm_adsp_compr_pointer(struct snd_compr_stream *stream, -				 struct snd_compr_tstamp *tstamp); -extern int wm_adsp_compr_copy(struct snd_compr_stream *stream, -			      char __user *buf, size_t count); +int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream); +int wm_adsp_compr_free(struct snd_compr_stream *stream); +int wm_adsp_compr_set_params(struct snd_compr_stream *stream, +			     struct snd_compr_params *params); +int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, +			   struct snd_compr_caps *caps); +int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd); +int wm_adsp_compr_handle_irq(struct wm_adsp *dsp); +int wm_adsp_compr_pointer(struct snd_compr_stream *stream, +			  struct snd_compr_tstamp *tstamp); +int wm_adsp_compr_copy(struct snd_compr_stream *stream, +		       char __user *buf, size_t count);  #endif diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h index 7613d60d62ea..ec78b9da020f 100644 --- a/sound/soc/codecs/wmfw.h +++ b/sound/soc/codecs/wmfw.h @@ -26,6 +26,10 @@  #define WMFW_CTL_FLAG_WRITEABLE   0x0002  #define WMFW_CTL_FLAG_READABLE    0x0001 +/* Non-ALSA coefficient types start at 0x1000 */ +#define WMFW_CTL_TYPE_ACKED       0x1000 /* acked control */ +#define WMFW_CTL_TYPE_HOSTEVENT   0x1001 /* event control */ +  struct wmfw_header {  	char magic[4];  	__le32 len; diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 19bdcac71775..37f9b6201918 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -40,6 +40,7 @@ config SND_SOC_FSL_SPDIF  	select REGMAP_MMIO  	select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n  	select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && (MXC_TZIC || MXC_AVIC) +	select BITREVERSE  	help  	  Say Y if you want to add Sony/Philips Digital Interface (SPDIF)  	  support for the Freescale CPUs. diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c index b2acd3293ea8..f200d1cfc4bd 100644 --- a/sound/soc/fsl/efika-audio-fabric.c +++ b/sound/soc/fsl/efika-audio-fabric.c @@ -27,7 +27,6 @@  #include "mpc5200_dma.h"  #include "mpc5200_psc_ac97.h" -#include "../codecs/stac9766.h"  #define DRV_NAME "efika-audio-fabric" diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index dffd549a0e2a..9998aea23597 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -183,7 +183,7 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,  	return 0;  } -static struct snd_soc_ops fsl_asoc_card_ops = { +static const struct snd_soc_ops fsl_asoc_card_ops = {  	.hw_params = fsl_asoc_card_hw_params,  }; diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index 201a70d1027a..1b60958e2080 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c @@ -61,7 +61,7 @@ static int imx_hifi_hw_params(struct snd_pcm_substream *substream,  	return 0;  } -static struct snd_soc_ops imx_hifi_ops = { +static const struct snd_soc_ops imx_hifi_ops = {  	.hw_params = imx_hifi_hw_params,  }; diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 1cb39309f5d5..cf026252cd4a 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -1,5 +1,5 @@  /* - * simple-card-core.c + * simple-card-utils.c   *   * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>   * @@ -195,9 +195,6 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai);  int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link)  { -	if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) -		return -EINVAL; -  	/* Assumes platform == cpu */  	if (!dai_link->platform_of_node)  		dai_link->platform_of_node = dai_link->cpu_of_node; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index f608f8d23f3d..a385ff6bfa4b 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -174,7 +174,7 @@ err:  	return ret;  } -static struct snd_soc_ops asoc_simple_card_ops = { +static const struct snd_soc_ops asoc_simple_card_ops = {  	.startup = asoc_simple_card_startup,  	.shutdown = asoc_simple_card_shutdown,  	.hw_params = asoc_simple_card_hw_params, diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index b9973a56bcb0..bb86ee042490 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -22,7 +22,7 @@  #include <sound/soc-dai.h>  #include <sound/simple_card_utils.h> -struct asoc_simple_card_priv { +struct simple_card_data {  	struct snd_soc_card snd_card;  	struct snd_soc_codec_conf codec_conf;  	struct asoc_simple_dai *dai_props; @@ -42,7 +42,7 @@ struct asoc_simple_card_priv {  static int asoc_simple_card_startup(struct snd_pcm_substream *substream)  {  	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct asoc_simple_card_priv *priv =	snd_soc_card_get_drvdata(rtd->card); +	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);  	struct asoc_simple_dai *dai_props =  		simple_priv_to_props(priv, rtd->num); @@ -52,21 +52,21 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)  static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)  {  	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct asoc_simple_card_priv *priv =	snd_soc_card_get_drvdata(rtd->card); +	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);  	struct asoc_simple_dai *dai_props =  		simple_priv_to_props(priv, rtd->num);  	clk_disable_unprepare(dai_props->clk);  } -static struct snd_soc_ops asoc_simple_card_ops = { +static const struct snd_soc_ops asoc_simple_card_ops = {  	.startup = asoc_simple_card_startup,  	.shutdown = asoc_simple_card_shutdown,  };  static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)  { -	struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); +	struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);  	struct snd_soc_dai *dai;  	struct snd_soc_dai_link *dai_link;  	struct asoc_simple_dai *dai_props; @@ -84,7 +84,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)  static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,  					struct snd_pcm_hw_params *params)  { -	struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); +	struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);  	struct snd_interval *rate = hw_param_interval(params,  						      SNDRV_PCM_HW_PARAM_RATE);  	struct snd_interval *channels = hw_param_interval(params, @@ -101,8 +101,8 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,  	return 0;  } -static int asoc_simple_card_parse_links(struct device_node *np, -					struct asoc_simple_card_priv *priv, +static int asoc_simple_card_dai_link_of(struct device_node *np, +					struct simple_card_data *priv,  					unsigned int daifmt,  					int idx, bool is_fe)  { @@ -195,22 +195,35 @@ static int asoc_simple_card_parse_links(struct device_node *np,  	return 0;  } -static int asoc_simple_card_dai_link_of(struct device_node *node, -				 struct asoc_simple_card_priv *priv) +static int asoc_simple_card_parse_of(struct device_node *node, +				     struct simple_card_data *priv) +  {  	struct device *dev = simple_priv_to_dev(priv);  	struct device_node *np;  	unsigned int daifmt = 0; -	int ret, i;  	bool is_fe; +	int ret, i; + +	if (!node) +		return -EINVAL; + +	ret = snd_soc_of_parse_audio_routing(&priv->snd_card, PREFIX "routing"); +	if (ret < 0) +		return ret; + +	/* sampling rate convert */ +	of_property_read_u32(node, PREFIX "convert-rate", &priv->convert_rate); + +	/* channels transfer */ +	of_property_read_u32(node, PREFIX "convert-channels", &priv->convert_channels);  	/* find 1st codec */  	np = of_get_child_by_name(node, PREFIX "codec");  	if (!np)  		return -ENODEV; -	ret = asoc_simple_card_parse_daifmt(dev, node, np, -					    PREFIX, &daifmt); +	ret = asoc_simple_card_parse_daifmt(dev, node, np, PREFIX, &daifmt);  	if (ret < 0)  		return ret; @@ -220,58 +233,12 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,  		if (strcmp(np->name, PREFIX "cpu") == 0)  			is_fe = true; -		ret = asoc_simple_card_parse_links(np, priv, daifmt, i, is_fe); +		ret = asoc_simple_card_dai_link_of(np, priv, daifmt, i, is_fe);  		if (ret < 0)  			return ret;  		i++;  	} -	return 0; -} - -static int asoc_simple_card_parse_of(struct device_node *node, -			      struct asoc_simple_card_priv *priv, -			      struct device *dev) -{ -	struct asoc_simple_dai *props; -	struct snd_soc_dai_link *links; -	int ret; -	int num; - -	if (!node) -		return -EINVAL; - -	num = of_get_child_count(node); -	props = devm_kzalloc(dev, sizeof(*props) * num, GFP_KERNEL); -	links = devm_kzalloc(dev, sizeof(*links) * num, GFP_KERNEL); -	if (!props || !links) -		return -ENOMEM; - -	priv->dai_props	= props; -	priv->dai_link	= links; - -	/* Init snd_soc_card */ -	priv->snd_card.owner			= THIS_MODULE; -	priv->snd_card.dev			= dev; -	priv->snd_card.dai_link			= priv->dai_link; -	priv->snd_card.num_links		= num; -	priv->snd_card.codec_conf		= &priv->codec_conf; -	priv->snd_card.num_configs		= 1; - -	ret = snd_soc_of_parse_audio_routing(&priv->snd_card, PREFIX "routing"); -	if (ret < 0) -		return ret; - -	/* sampling rate convert */ -	of_property_read_u32(node, PREFIX "convert-rate", &priv->convert_rate); - -	/* channels transfer */ -	of_property_read_u32(node, PREFIX "convert-channels", &priv->convert_channels); - -	ret = asoc_simple_card_dai_link_of(node, priv); -	if (ret < 0) -		return ret; -  	ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX);  	if (ret < 0)  		return ret; @@ -286,17 +253,37 @@ static int asoc_simple_card_parse_of(struct device_node *node,  static int asoc_simple_card_probe(struct platform_device *pdev)  { -	struct asoc_simple_card_priv *priv; -	struct device_node *np = pdev->dev.of_node; +	struct simple_card_data *priv; +	struct snd_soc_dai_link *dai_link; +	struct asoc_simple_dai *dai_props;  	struct device *dev = &pdev->dev; -	int ret; +	struct device_node *np = pdev->dev.of_node; +	int num, ret;  	/* Allocate the private data */  	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);  	if (!priv)  		return -ENOMEM; -	ret = asoc_simple_card_parse_of(np, priv, dev); +	num = of_get_child_count(np); + +	dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL); +	dai_link  = devm_kzalloc(dev, sizeof(*dai_link)  * num, GFP_KERNEL); +	if (!dai_props || !dai_link) +		return -ENOMEM; + +	priv->dai_props				= dai_props; +	priv->dai_link				= dai_link; + +	/* Init snd_soc_card */ +	priv->snd_card.owner			= THIS_MODULE; +	priv->snd_card.dev			= dev; +	priv->snd_card.dai_link			= priv->dai_link; +	priv->snd_card.num_links		= num; +	priv->snd_card.codec_conf		= &priv->codec_conf; +	priv->snd_card.num_configs		= 1; + +	ret = asoc_simple_card_parse_of(np, priv);  	if (ret < 0) {  		if (ret != -EPROBE_DEFER)  			dev_err(dev, "parse error %d\n", ret); diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 0838478c4c3f..c7b3cbf92faf 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -937,7 +937,7 @@ int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable)  	struct sst_data *drv = snd_soc_dai_get_drvdata(dai);  	int ssp_id; -	dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); +	dev_dbg(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id);  	if (strcmp(id, "ssp0-port") == 0)  		ssp_id = SSP_MODEM; diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 25c6d87c818e..f5a8050351b5 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -771,6 +771,9 @@ static int sst_soc_prepare(struct device *dev)  	struct sst_data *drv = dev_get_drvdata(dev);  	struct snd_soc_pcm_runtime *rtd; +	if (!drv->soc_card) +		return 0; +  	/* suspend all pcms first */  	snd_soc_suspend(drv->soc_card->dev);  	snd_soc_poweroff(drv->soc_card->dev); @@ -793,6 +796,9 @@ static void sst_soc_complete(struct device *dev)  	struct sst_data *drv = dev_get_drvdata(dev);  	struct snd_soc_pcm_runtime *rtd; +	if (!drv->soc_card) +		return; +  	/* restart SSPs */  	list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) {  		struct snd_soc_dai *dai = rtd->cpu_dai; diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index 9b6e27385dc9..f9ba71315e33 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -27,6 +27,7 @@  #include <linux/pm_qos.h>  #include <linux/async.h>  #include <linux/acpi.h> +#include <linux/sysfs.h>  #include <sound/core.h>  #include <sound/soc.h>  #include <asm/platform_sst_audio.h> @@ -242,6 +243,32 @@ int sst_alloc_drv_context(struct intel_sst_drv **ctx,  }  EXPORT_SYMBOL_GPL(sst_alloc_drv_context); +static ssize_t firmware_version_show(struct device *dev, +			    struct device_attribute *attr, char *buf) +{ +	struct intel_sst_drv *ctx = dev_get_drvdata(dev); + +	if (ctx->fw_version.type == 0 && ctx->fw_version.major == 0 && +	    ctx->fw_version.minor == 0 && ctx->fw_version.build == 0) +		return sprintf(buf, "FW not yet loaded\n"); +	else +		return sprintf(buf, "v%02x.%02x.%02x.%02x\n", +			       ctx->fw_version.type, ctx->fw_version.major, +			       ctx->fw_version.minor, ctx->fw_version.build); + +} + +DEVICE_ATTR_RO(firmware_version); + +static const struct attribute *sst_fw_version_attrs[] = { +	&dev_attr_firmware_version.attr, +	NULL, +}; + +static const struct attribute_group sst_fw_version_attr_group = { +	.attrs = (struct attribute **)sst_fw_version_attrs, +}; +  int sst_context_init(struct intel_sst_drv *ctx)  {  	int ret = 0, i; @@ -315,8 +342,19 @@ int sst_context_init(struct intel_sst_drv *ctx)  		dev_err(ctx->dev, "Firmware download failed:%d\n", ret);  		goto do_free_mem;  	} + +	ret = sysfs_create_group(&ctx->dev->kobj, +				 &sst_fw_version_attr_group); +	if (ret) { +		dev_err(ctx->dev, +			"Unable to create sysfs\n"); +		goto err_sysfs; +	} +  	sst_register(ctx->dev);  	return 0; +err_sysfs: +	sysfs_remove_group(&ctx->dev->kobj, &sst_fw_version_attr_group);  do_free_mem:  	destroy_workqueue(ctx->post_msg_wq); @@ -330,6 +368,7 @@ void sst_context_cleanup(struct intel_sst_drv *ctx)  	pm_runtime_disable(ctx->dev);  	sst_unregister(ctx->dev);  	sst_set_fw_state_locked(ctx, SST_SHUTDOWN); +	sysfs_remove_group(&ctx->dev->kobj, &sst_fw_version_attr_group);  	flush_scheduled_work();  	destroy_workqueue(ctx->post_msg_wq);  	pm_qos_remove_request(ctx->qos); diff --git a/sound/soc/intel/atom/sst/sst.h b/sound/soc/intel/atom/sst/sst.h index 3f493862e98d..5c9a51cc77aa 100644 --- a/sound/soc/intel/atom/sst/sst.h +++ b/sound/soc/intel/atom/sst/sst.h @@ -436,6 +436,7 @@ struct intel_sst_drv {  	 */  	char firmware_name[FW_NAME_SIZE]; +	struct snd_sst_fw_version fw_version;  	struct sst_fw_save	*fw_save;  }; diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 0a88537ca58a..f4d92bbc5373 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -452,6 +452,8 @@ static struct sst_acpi_mach sst_acpi_bytcr[] = {  static struct sst_acpi_mach sst_acpi_chv[] = {  	{"10EC5670", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,  						&chv_platform_data }, +	{"10EC5672", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, +						&chv_platform_data },  	{"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,  						&chv_platform_data },  	{"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index bfc889950bb2..374bb61c596d 100644 --- a/sound/soc/intel/atom/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -236,6 +236,17 @@ static void process_fw_init(struct intel_sst_drv *sst_drv_ctx,  		retval = init->result;  		goto ret;  	} +	dev_info(sst_drv_ctx->dev, "FW Version %02x.%02x.%02x.%02x\n", +			init->fw_version.type, init->fw_version.major, +			init->fw_version.minor, init->fw_version.build); +	dev_dbg(sst_drv_ctx->dev, "Build date %s Time %s\n", +			init->build_info.date, init->build_info.time); + +	/* Save FW version */ +	sst_drv_ctx->fw_version.type = init->fw_version.type; +	sst_drv_ctx->fw_version.major = init->fw_version.major; +	sst_drv_ctx->fw_version.minor = init->fw_version.minor; +	sst_drv_ctx->fw_version.build = init->fw_version.build;  ret:  	sst_wake_up_block(sst_drv_ctx, retval, FW_DWNL_ID, 0 , NULL, 0); diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index 4ccc80e5e8cc..51bdeeecb7c8 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -104,7 +104,7 @@ int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params)  	sst_init_stream(&sst_drv_ctx->streams[str_id], alloc_param.codec_type,  			str_id, alloc_param.operation, 0); -	dev_info(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n", +	dev_dbg(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n",  			str_id, pipe_id);  	ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD,  			IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param), @@ -415,7 +415,7 @@ int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)  		str_info->status = STREAM_UN_INIT;  		mutex_unlock(&str_info->lock); -		dev_info(sst_drv_ctx->dev, "Free for str %d pipe %#x\n", +		dev_dbg(sst_drv_ctx->dev, "Free for str %d pipe %#x\n",  				str_id, str_info->pipe_id);  		retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,  				IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0, diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c index 7ab14ce65a73..260447da32b8 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c @@ -23,7 +23,6 @@  #include <linux/slab.h>  #include <linux/delay.h>  #include <linux/platform_device.h> -#include <linux/kthread.h>  #include <linux/firmware.h>  #include <linux/io.h>  #include <asm/div64.h> @@ -338,7 +337,7 @@ static irqreturn_t sst_byt_irq_thread(int irq, void *context)  	spin_unlock_irqrestore(&sst->spinlock, flags);  	/* continue to send any remaining messages... */ -	kthread_queue_work(&ipc->kworker, &ipc->kwork); +	schedule_work(&ipc->kwork);  	return IRQ_HANDLED;  } diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 547e6705bf6d..53c6b4cbb1e1 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -156,7 +156,7 @@ static int bdw_rt5677_hw_params(struct snd_pcm_substream *substream,  	return ret;  } -static struct snd_soc_ops bdw_rt5677_ops = { +static const struct snd_soc_ops bdw_rt5677_ops = {  	.hw_params = bdw_rt5677_hw_params,  }; diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 7486a0022fde..4d7e9decfa92 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -126,7 +126,7 @@ static int broadwell_rt286_hw_params(struct snd_pcm_substream *substream,  	return ret;  } -static struct snd_soc_ops broadwell_rt286_ops = { +static const struct snd_soc_ops broadwell_rt286_ops = {  	.hw_params = broadwell_rt286_hw_params,  }; @@ -220,10 +220,12 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {  };  static int broadwell_suspend(struct snd_soc_card *card){ -	struct snd_soc_codec *codec; +	struct snd_soc_component *component; + +	list_for_each_entry(component, &card->component_dev_list, card_list) { +		if (!strcmp(component->name, "i2c-INT343A:00")) { +			struct snd_soc_codec *codec = snd_soc_component_to_codec(component); -	list_for_each_entry(codec, &card->codec_dev_list, card_list) { -		if (!strcmp(codec->component.name, "i2c-INT343A:00")) {  			dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n");  			rt286_mic_detect(codec, NULL);  			break; @@ -233,10 +235,12 @@ static int broadwell_suspend(struct snd_soc_card *card){  }  static int broadwell_resume(struct snd_soc_card *card){ -	struct snd_soc_codec *codec; +	struct snd_soc_component *component; + +	list_for_each_entry(component, &card->component_dev_list, card_list) { +		if (!strcmp(component->name, "i2c-INT343A:00")) { +			struct snd_soc_codec *codec = snd_soc_component_to_codec(component); -	list_for_each_entry(codec, &card->codec_dev_list, card_list) { -		if (!strcmp(codec->component.name, "i2c-INT343A:00")) {  			dev_dbg(codec->dev, "enabling jack detect for resume.\n");  			rt286_mic_detect(codec, &broadwell_headset);  			break; diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 865a21e557cc..1b4330cd2739 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -30,6 +30,7 @@  #define BXT_DIALOG_CODEC_DAI	"da7219-hifi"  #define BXT_MAXIM_CODEC_DAI	"HiFi"  #define DUAL_CHANNEL		2 +#define QUAD_CHANNEL		4  static struct snd_soc_jack broxton_headset; @@ -182,6 +183,16 @@ static struct snd_pcm_hw_constraint_list constraints_channels = {  	.mask = 0,  }; +static unsigned int channels_quad[] = { +	QUAD_CHANNEL, +}; + +static struct snd_pcm_hw_constraint_list constraints_channels_quad = { +	.count = ARRAY_SIZE(channels_quad), +	.list = channels_quad, +	.mask = 0, +}; +  static int bxt_fe_startup(struct snd_pcm_substream *substream)  {  	struct snd_pcm_runtime *runtime = substream->runtime; @@ -248,7 +259,7 @@ static int broxton_da7219_hw_free(struct snd_pcm_substream *substream)  	return ret;  } -static struct snd_soc_ops broxton_da7219_ops = { +static const struct snd_soc_ops broxton_da7219_ops = {  	.hw_params = broxton_da7219_hw_params,  	.hw_free = broxton_da7219_hw_free,  }; @@ -258,7 +269,10 @@ static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd,  {  	struct snd_interval *channels = hw_param_interval(params,  						SNDRV_PCM_HW_PARAM_CHANNELS); -	channels->min = channels->max = DUAL_CHANNEL; +	if (params_channels(params) == 2) +		channels->min = channels->max = 2; +	else +		channels->min = channels->max = 4;  	return 0;  } @@ -267,9 +281,9 @@ static int broxton_dmic_startup(struct snd_pcm_substream *substream)  {  	struct snd_pcm_runtime *runtime = substream->runtime; -	runtime->hw.channels_max = DUAL_CHANNEL; +	runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL;  	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, -			&constraints_channels); +			&constraints_channels_quad);  	return snd_pcm_hw_constraint_list(substream->runtime, 0,  			SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); @@ -295,7 +309,7 @@ static int broxton_refcap_startup(struct snd_pcm_substream *substream)  			&constraints_16000);  }; -static struct snd_soc_ops broxton_refcap_ops = { +static const struct snd_soc_ops broxton_refcap_ops = {  	.startup = broxton_refcap_startup,  }; @@ -348,7 +362,7 @@ static struct snd_soc_dai_link broxton_dais[] = {  		.dynamic = 1,  		.ops = &broxton_refcap_ops,  	}, -	[BXT_DPCM_AUDIO_DMIC_CP] +	[BXT_DPCM_AUDIO_DMIC_CP] =  	{  		.name = "Bxt Audio DMIC cap",  		.stream_name = "dmiccap", diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index d610bdca1608..1309405b3808 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -181,7 +181,7 @@ static int broxton_rt298_hw_params(struct snd_pcm_substream *substream,  	return ret;  } -static struct snd_soc_ops broxton_rt298_ops = { +static const struct snd_soc_ops broxton_rt298_ops = {  	.hw_params = broxton_rt298_hw_params,  }; @@ -230,7 +230,7 @@ static int broxton_dmic_startup(struct snd_pcm_substream *substream)  				SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);  } -static struct snd_soc_ops broxton_dmic_ops = { +static const struct snd_soc_ops broxton_dmic_ops = {  	.startup = broxton_dmic_startup,  }; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index bff77a1f27fc..507a86a5eafe 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -57,9 +57,7 @@ struct byt_rt5640_private {  	struct clk *mclk;  }; -static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | -					BYT_RT5640_DMIC_EN | -					BYT_RT5640_MCLK_EN; +static unsigned long byt_rt5640_quirk = BYT_RT5640_MCLK_EN;  static void log_quirks(struct device *dev)  { @@ -597,11 +595,11 @@ static int byt_rt5640_aif1_startup(struct snd_pcm_substream *substream)  			SNDRV_PCM_HW_PARAM_RATE, 48000);  } -static struct snd_soc_ops byt_rt5640_aif1_ops = { +static const struct snd_soc_ops byt_rt5640_aif1_ops = {  	.startup = byt_rt5640_aif1_startup,  }; -static struct snd_soc_ops byt_rt5640_be_ssp2_ops = { +static const struct snd_soc_ops byt_rt5640_be_ssp2_ops = {  	.hw_params = byt_rt5640_aif1_hw_params,  }; @@ -689,6 +687,10 @@ static bool is_valleyview(void)  	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_rt5640_mc_probe(struct platform_device *pdev)  { @@ -698,6 +700,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)  	int i;  	int dai_index;  	struct byt_rt5640_private *priv; +	bool is_bytcr = false;  	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);  	if (!priv) @@ -734,10 +737,61 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)  		struct sst_platform_info *p_info = mach->pdata;  		const struct sst_res_info *res_info = p_info->res_info; -		/* TODO: use CHAN package info from BIOS to detect AIF1/AIF2 */ -		if (res_info->acpi_ipc_irq_index == 0) { +		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 sst_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 = sst_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_rt5640_quirk |= BYT_RT5640_SSP0_AIF1; +			} else  if (chan_package.aif_value == 2) { +				dev_info(&pdev->dev, "BIOS Routing: AIF2 connected\n"); +				byt_rt5640_quirk |= BYT_RT5640_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_rt5640_quirk |= BYT_RT5640_SSP0_AIF2;  		} + +		/* change defaults for Baytrail-CR capture */ +		byt_rt5640_quirk |= BYT_RT5640_IN1_MAP; +		byt_rt5640_quirk |= BYT_RT5640_DIFF_MIC; +	} else { +		byt_rt5640_quirk |= (BYT_RT5640_DMIC1_MAP | +				BYT_RT5640_DMIC_EN);  	}  	/* check quirks before creating card */ diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 35f591eab3c9..2d24dc04b597 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -219,11 +219,11 @@ static int byt_rt5651_aif1_startup(struct snd_pcm_substream *substream)  			&constraints_48000);  } -static struct snd_soc_ops byt_rt5651_aif1_ops = { +static const struct snd_soc_ops byt_rt5651_aif1_ops = {  	.startup = byt_rt5651_aif1_startup,  }; -static struct snd_soc_ops byt_rt5651_be_ssp2_ops = { +static const struct snd_soc_ops byt_rt5651_be_ssp2_ops = {  	.hw_params = byt_rt5651_aif1_hw_params,  }; diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index cdcced9f32b6..742bc0d4e681 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -204,11 +204,11 @@ static int cht_max98090_headset_init(struct snd_soc_component *component)  	return ts3a227e_enable_jack_detect(component, &ctx->jack);  } -static struct snd_soc_ops cht_aif1_ops = { +static const struct snd_soc_ops cht_aif1_ops = {  	.startup = cht_aif1_startup,  }; -static struct snd_soc_ops cht_be_ssp2_ops = { +static const struct snd_soc_ops cht_be_ssp2_ops = {  	.hw_params = cht_aif1_hw_params,  }; diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 56056ed7fcfd..f504a0e18f91 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -44,6 +44,7 @@ struct cht_acpi_card {  struct cht_mc_private {  	struct snd_soc_jack jack;  	struct cht_acpi_card *acpi_card; +	char codec_name[16];  };  static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) @@ -250,11 +251,11 @@ static int cht_aif1_startup(struct snd_pcm_substream *substream)  			SNDRV_PCM_HW_PARAM_RATE, 48000);  } -static struct snd_soc_ops cht_aif1_ops = { +static const struct snd_soc_ops cht_aif1_ops = {  	.startup = cht_aif1_startup,  }; -static struct snd_soc_ops cht_be_ssp2_ops = { +static const struct snd_soc_ops cht_be_ssp2_ops = {  	.hw_params = cht_aif1_hw_params,  }; @@ -354,7 +355,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)  	int i;  	struct cht_mc_private *drv;  	struct snd_soc_card *card = snd_soc_cards[0].soc_card; -	char codec_name[16];  	struct sst_acpi_mach *mach;  	const char *i2c_name = NULL;  	int dai_index = 0; @@ -374,12 +374,12 @@ static int snd_cht_mc_probe(struct platform_device *pdev)  	}  	card->dev = &pdev->dev;  	mach = card->dev->platform_data; -	sprintf(codec_name, "i2c-%s:00", drv->acpi_card->codec_id); +	sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id);  	/* set correct codec name */  	for (i = 0; i < ARRAY_SIZE(cht_dailink); i++)  		if (!strcmp(card->dai_link[i].codec_name, "i2c-10EC5645:00")) { -			card->dai_link[i].codec_name = kstrdup(codec_name, GFP_KERNEL); +			card->dai_link[i].codec_name = drv->codec_name;  			dai_index = i;  		} diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index df9d254baa18..e4d46d4360d7 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -25,12 +25,14 @@  #include <sound/jack.h>  #include "../../codecs/rt5670.h"  #include "../atom/sst-atom-controls.h" +#include "../common/sst-acpi.h"  /* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */  #define CHT_PLAT_CLK_3_HZ	19200000  #define CHT_CODEC_DAI	"rt5670-aif1"  static struct snd_soc_jack cht_bsw_headset; +static char cht_bsw_codec_name[16];  /* Headset jack detection DAPM pins */  static struct snd_soc_jack_pin cht_bsw_headset_pins[] = { @@ -225,11 +227,11 @@ static int cht_aif1_startup(struct snd_pcm_substream *substream)  			SNDRV_PCM_HW_PARAM_RATE, 48000);  } -static struct snd_soc_ops cht_aif1_ops = { +static const struct snd_soc_ops cht_aif1_ops = {  	.startup = cht_aif1_startup,  }; -static struct snd_soc_ops cht_be_ssp2_ops = { +static const struct snd_soc_ops cht_be_ssp2_ops = {  	.hw_params = cht_aif1_hw_params,  }; @@ -292,10 +294,12 @@ static struct snd_soc_dai_link cht_dailink[] = {  static int cht_suspend_pre(struct snd_soc_card *card)  { -	struct snd_soc_codec *codec; +	struct snd_soc_component *component; + +	list_for_each_entry(component, &card->component_dev_list, card_list) { +		if (!strcmp(component->name, "i2c-10EC5670:00")) { +			struct snd_soc_codec *codec = snd_soc_component_to_codec(component); -	list_for_each_entry(codec, &card->codec_dev_list, card_list) { -		if (!strcmp(codec->component.name, "i2c-10EC5670:00")) {  			dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n");  			rt5670_jack_suspend(codec);  			break; @@ -306,10 +310,12 @@ static int cht_suspend_pre(struct snd_soc_card *card)  static int cht_resume_post(struct snd_soc_card *card)  { -	struct snd_soc_codec *codec; +	struct snd_soc_component *component; + +	list_for_each_entry(component, &card->component_dev_list, card_list) { +		if (!strcmp(component->name, "i2c-10EC5670:00")) { +			struct snd_soc_codec *codec = snd_soc_component_to_codec(component); -	list_for_each_entry(codec, &card->codec_dev_list, card_list) { -		if (!strcmp(codec->component.name, "i2c-10EC5670:00")) {  			dev_dbg(codec->dev, "enabling jack detect for resume.\n");  			rt5670_jack_resume(codec);  			break; @@ -335,9 +341,33 @@ static struct snd_soc_card snd_soc_card_cht = {  	.resume_post = cht_resume_post,  }; +#define RT5672_I2C_DEFAULT	"i2c-10EC5670:00" +  static int snd_cht_mc_probe(struct platform_device *pdev)  {  	int ret_val = 0; +	struct sst_acpi_mach *mach = pdev->dev.platform_data; +	const char *i2c_name; +	int i; + +	strcpy(cht_bsw_codec_name, RT5672_I2C_DEFAULT); + +	/* fixup codec name based on HID */ +	if (mach) { +		i2c_name = sst_acpi_find_name_from_hid(mach->id); +		if (i2c_name) { +			snprintf(cht_bsw_codec_name, sizeof(cht_bsw_codec_name), +				 "i2c-%s", i2c_name); +			for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { +				if (!strcmp(cht_dailink[i].codec_name, +					    RT5672_I2C_DEFAULT)) { +					cht_dailink[i].codec_name = +						cht_bsw_codec_name; +					break; +				} +			} +		} +	}  	/* register the soc card */  	snd_soc_card_cht.dev = &pdev->dev; diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index 863f1d5e2a2c..5e1ea0371c90 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -81,7 +81,7 @@ static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream,  	return ret;  } -static struct snd_soc_ops haswell_rt5640_ops = { +static const struct snd_soc_ops haswell_rt5640_ops = {  	.hw_params = haswell_rt5640_hw_params,  }; diff --git a/sound/soc/intel/boards/mfld_machine.c b/sound/soc/intel/boards/mfld_machine.c index 34f46c72a0e2..4e08885f37aa 100644 --- a/sound/soc/intel/boards/mfld_machine.c +++ b/sound/soc/intel/boards/mfld_machine.c @@ -81,9 +81,9 @@ static struct snd_soc_jack_zone mfld_zones[] = {  };  /* sound card controls */ -static const char *headset_switch_text[] = {"Earpiece", "Headset"}; +static const char * const headset_switch_text[] = {"Earpiece", "Headset"}; -static const char *lo_text[] = {"Vibra", "Headset", "IHF", "None"}; +static const char * const lo_text[] = {"Vibra", "Headset", "IHF", "None"};  static const struct soc_enum headset_enum =  	SOC_ENUM_SINGLE_EXT(2, headset_switch_text); diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 25db5be7fdfa..fddd1cd12f13 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -332,7 +332,7 @@ static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream,  	return ret;  } -static struct snd_soc_ops skylake_nau8825_ops = { +static const struct snd_soc_ops skylake_nau8825_ops = {  	.hw_params = skylake_nau8825_hw_params,  }; @@ -382,7 +382,7 @@ static int skylake_dmic_startup(struct snd_pcm_substream *substream)  			SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);  } -static struct snd_soc_ops skylake_dmic_ops = { +static const struct snd_soc_ops skylake_dmic_ops = {  	.startup = skylake_dmic_startup,  }; @@ -416,7 +416,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream)  				&constraints_16000);  } -static struct snd_soc_ops skylaye_refcap_ops = { +static const struct snd_soc_ops skylaye_refcap_ops = {  	.startup = skylake_refcap_startup,  }; diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 69c5d5da4e86..8ab865ee0cad 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -394,7 +394,7 @@ static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream,  	return ret;  } -static struct snd_soc_ops skylake_nau8825_ops = { +static const struct snd_soc_ops skylake_nau8825_ops = {  	.hw_params = skylake_nau8825_hw_params,  }; @@ -430,7 +430,7 @@ static int skylake_dmic_startup(struct snd_pcm_substream *substream)  			SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);  } -static struct snd_soc_ops skylake_dmic_ops = { +static const struct snd_soc_ops skylake_dmic_ops = {  	.startup = skylake_dmic_startup,  }; @@ -464,7 +464,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream)  			&constraints_16000);  } -static struct snd_soc_ops skylaye_refcap_ops = { +static const struct snd_soc_ops skylaye_refcap_ops = {  	.startup = skylake_refcap_startup,  }; diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 88c61e8cb87f..dc5c3611a6ff 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -250,7 +250,7 @@ static int skylake_rt286_hw_params(struct snd_pcm_substream *substream,  	return ret;  } -static struct snd_soc_ops skylake_rt286_ops = { +static const struct snd_soc_ops skylake_rt286_ops = {  	.hw_params = skylake_rt286_hw_params,  }; @@ -289,7 +289,7 @@ static int skylake_dmic_startup(struct snd_pcm_substream *substream)  			SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);  } -static struct snd_soc_ops skylake_dmic_ops = { +static const struct snd_soc_ops skylake_dmic_ops = {  	.startup = skylake_dmic_startup,  }; diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h index 012742299dd5..214e000667ae 100644 --- a/sound/soc/intel/common/sst-acpi.h +++ b/sound/soc/intel/common/sst-acpi.h @@ -15,14 +15,29 @@  #include <linux/stddef.h>  #include <linux/acpi.h> -/* translation fron HID to I2C name, needed for DAI codec_name */ +struct sst_acpi_package_context { +	char *name;           /* package name */ +	int length;           /* number of elements */ +	struct acpi_buffer *format; +	struct acpi_buffer *state; +	bool data_valid; +}; +  #if IS_ENABLED(CONFIG_ACPI) +/* translation fron HID to I2C name, needed for DAI codec_name */  const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]); +bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], +				    struct sst_acpi_package_context *ctx);  #else  static inline const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])  {  	return NULL;  } +static inline bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], +					   struct sst_acpi_package_context *ctx) +{ +	return false; +}  #endif  /* acpi match */ diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c index 6c672ac79cce..62f3a8e0ec87 100644 --- a/sound/soc/intel/common/sst-ipc.c +++ b/sound/soc/intel/common/sst-ipc.c @@ -26,7 +26,6 @@  #include <linux/sched.h>  #include <linux/delay.h>  #include <linux/platform_device.h> -#include <linux/kthread.h>  #include <sound/asound.h>  #include "sst-dsp.h" @@ -109,10 +108,9 @@ static int ipc_tx_message(struct sst_generic_ipc *ipc, u64 header,  		ipc->ops.tx_data_copy(msg, tx_data, tx_bytes);  	list_add_tail(&msg->list, &ipc->tx_list); +	schedule_work(&ipc->kwork);  	spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); -	kthread_queue_work(&ipc->kworker, &ipc->kwork); -  	if (wait)  		return tx_wait_done(ipc, msg, rx_data);  	else @@ -156,42 +154,56 @@ free_mem:  	return -ENOMEM;  } -static void ipc_tx_msgs(struct kthread_work *work) +static void ipc_tx_msgs(struct work_struct *work)  {  	struct sst_generic_ipc *ipc =  		container_of(work, struct sst_generic_ipc, kwork);  	struct ipc_message *msg; -	unsigned long flags; -	spin_lock_irqsave(&ipc->dsp->spinlock, flags); +	spin_lock_irq(&ipc->dsp->spinlock); -	if (list_empty(&ipc->tx_list) || ipc->pending) { -		spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); -		return; -	} - -	/* if the DSP is busy, we will TX messages after IRQ. -	 * also postpone if we are in the middle of procesing completion irq*/ -	if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) { -		dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n"); -		spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); -		return; -	} +	while (!list_empty(&ipc->tx_list) && !ipc->pending) { +		/* if the DSP is busy, we will TX messages after IRQ. +		 * also postpone if we are in the middle of processing +		 * completion irq +		 */ +		if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) { +			dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n"); +			break; +		} -	msg = list_first_entry(&ipc->tx_list, struct ipc_message, list); -	list_move(&msg->list, &ipc->rx_list); +		msg = list_first_entry(&ipc->tx_list, struct ipc_message, list); +		list_move(&msg->list, &ipc->rx_list); -	if (ipc->ops.tx_msg != NULL) -		ipc->ops.tx_msg(ipc, msg); +		if (ipc->ops.tx_msg != NULL) +			ipc->ops.tx_msg(ipc, msg); +	} -	spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); +	spin_unlock_irq(&ipc->dsp->spinlock);  }  int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header,  	void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes)  { -	return ipc_tx_message(ipc, header, tx_data, tx_bytes, +	int ret; + +	/* +	 * DSP maybe in lower power active state, so +	 * check if the DSP supports DSP lp On method +	 * if so invoke that before sending IPC +	 */ +	if (ipc->ops.check_dsp_lp_on) +		if (ipc->ops.check_dsp_lp_on(ipc->dsp, true)) +			return -EIO; + +	ret = ipc_tx_message(ipc, header, tx_data, tx_bytes,  		rx_data, rx_bytes, 1); + +	if (ipc->ops.check_dsp_lp_on) +		if (ipc->ops.check_dsp_lp_on(ipc->dsp, false)) +			return -EIO; + +	return ret;  }  EXPORT_SYMBOL_GPL(sst_ipc_tx_message_wait); @@ -203,6 +215,14 @@ int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header,  }  EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nowait); +int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header, +	void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) +{ +	return ipc_tx_message(ipc, header, tx_data, tx_bytes, +		rx_data, rx_bytes, 1); +} +EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nopm); +  struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc,  	u64 header)  { @@ -280,19 +300,7 @@ int sst_ipc_init(struct sst_generic_ipc *ipc)  	if (ret < 0)  		return -ENOMEM; -	/* start the IPC message thread */ -	kthread_init_worker(&ipc->kworker); -	ipc->tx_thread = kthread_run(kthread_worker_fn, -					&ipc->kworker, "%s", -					dev_name(ipc->dev)); -	if (IS_ERR(ipc->tx_thread)) { -		dev_err(ipc->dev, "error: failed to create message TX task\n"); -		ret = PTR_ERR(ipc->tx_thread); -		kfree(ipc->msg); -		return ret; -	} - -	kthread_init_work(&ipc->kwork, ipc_tx_msgs); +	INIT_WORK(&ipc->kwork, ipc_tx_msgs);  	return 0;  }  EXPORT_SYMBOL_GPL(sst_ipc_init); @@ -301,8 +309,7 @@ void sst_ipc_fini(struct sst_generic_ipc *ipc)  {  	int i; -	if (ipc->tx_thread) -		kthread_stop(ipc->tx_thread); +	cancel_work_sync(&ipc->kwork);  	if (ipc->msg) {  		for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h index ceb7e468a3fa..7ed42a640ad6 100644 --- a/sound/soc/intel/common/sst-ipc.h +++ b/sound/soc/intel/common/sst-ipc.h @@ -23,7 +23,6 @@  #include <linux/list.h>  #include <linux/workqueue.h>  #include <linux/sched.h> -#include <linux/kthread.h>  #define IPC_MAX_MAILBOX_BYTES	256 @@ -52,6 +51,7 @@ struct sst_plat_ipc_ops {  	void (*tx_data_copy)(struct ipc_message *, char *, size_t);  	u64  (*reply_msg_match)(u64 header, u64 *mask);  	bool (*is_dsp_busy)(struct sst_dsp *dsp); +	int (*check_dsp_lp_on)(struct sst_dsp *dsp, bool state);  };  /* SST generic IPC data */ @@ -65,8 +65,7 @@ struct sst_generic_ipc {  	struct list_head empty_list;  	wait_queue_head_t wait_txq;  	struct task_struct *tx_thread; -	struct kthread_worker kworker; -	struct kthread_work kwork; +	struct work_struct kwork;  	bool pending;  	struct ipc_message *msg;  	int tx_data_max_size; @@ -81,6 +80,9 @@ int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header,  int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header,  	void *tx_data, size_t tx_bytes); +int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header, +	void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes); +  struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc,  	u64 header); diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c index 789843307a49..1070f3ad23e5 100644 --- a/sound/soc/intel/common/sst-match-acpi.c +++ b/sound/soc/intel/common/sst-match-acpi.c @@ -77,5 +77,62 @@ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines)  }  EXPORT_SYMBOL_GPL(sst_acpi_find_machine); +static acpi_status sst_acpi_find_package(acpi_handle handle, u32 level, +					void *context, void **ret) +{ +	struct acpi_device *adev; +	acpi_status status = AE_OK; +	struct sst_acpi_package_context *pkg_ctx = context; + +	pkg_ctx->data_valid = false; + +	if (acpi_bus_get_device(handle, &adev)) +		return AE_OK; + +	if (adev->status.present && adev->status.functional) { +		struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; +		union acpi_object  *myobj = NULL; + +		status = acpi_evaluate_object_typed(handle, pkg_ctx->name, +						NULL, &buffer, +						ACPI_TYPE_PACKAGE); +		if (ACPI_FAILURE(status)) +			return AE_OK; + +		myobj = buffer.pointer; +		if (!myobj || myobj->package.count != pkg_ctx->length) { +			kfree(buffer.pointer); +			return AE_OK; +		} + +		status = acpi_extract_package(myobj, +					pkg_ctx->format, pkg_ctx->state); +		if (ACPI_FAILURE(status)) { +			kfree(buffer.pointer); +			return AE_OK; +		} + +		kfree(buffer.pointer); +		pkg_ctx->data_valid = true; +		return AE_CTRL_TERMINATE; +	} + +	return AE_OK; +} + +bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], +				struct sst_acpi_package_context *ctx) +{ +	acpi_status status; + +	status = acpi_get_devices(hid, sst_acpi_find_package, ctx, NULL); + +	if (ACPI_FAILURE(status) || !ctx->data_valid) +		return false; + +	return true; +} +EXPORT_SYMBOL_GPL(sst_acpi_find_package_from_hid); +  MODULE_LICENSE("GPL v2");  MODULE_DESCRIPTION("Intel Common ACPI Match module"); diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index e432a31fd9f2..a3459d1682a6 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -26,7 +26,6 @@  #include <linux/delay.h>  #include <linux/sched.h>  #include <linux/platform_device.h> -#include <linux/kthread.h>  #include <linux/firmware.h>  #include <linux/dma-mapping.h>  #include <linux/debugfs.h> @@ -818,7 +817,7 @@ static irqreturn_t hsw_irq_thread(int irq, void *context)  	spin_unlock_irqrestore(&sst->spinlock, flags);  	/* continue to send any remaining messages... */ -	kthread_queue_work(&ipc->kworker, &ipc->kwork); +	schedule_work(&ipc->kwork);  	return IRQ_HANDLED;  } diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 1d251d59bcb9..1f9f33d34000 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -43,6 +43,9 @@  #define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000 +/* Delay before scheduling D0i3 entry */ +#define BXT_D0I3_DELAY 5000 +  static unsigned int bxt_get_errorcode(struct sst_dsp *ctx)  {  	 return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); @@ -288,6 +291,141 @@ sst_load_base_firmware_failed:  	return ret;  } +/* + * Decide the D0i3 state that can be targeted based on the usecase + * ref counts and DSP state + * + * Decision Matrix:  (X= dont care; state = target state) + * + * DSP state != SKL_DSP_RUNNING ; state = no d0i3 + * + * DSP state == SKL_DSP_RUNNING , the following matrix applies + * non_d0i3 >0; streaming =X; non_streaming =X; state = no d0i3 + * non_d0i3 =X; streaming =0; non_streaming =0; state = no d0i3 + * non_d0i3 =0; streaming >0; non_streaming =X; state = streaming d0i3 + * non_d0i3 =0; streaming =0; non_streaming =X; state = non-streaming d0i3 + */ +static int bxt_d0i3_target_state(struct sst_dsp *ctx) +{ +	struct skl_sst *skl = ctx->thread_context; +	struct skl_d0i3_data *d0i3 = &skl->d0i3; + +	if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING) +		return SKL_DSP_D0I3_NONE; + +	if (d0i3->non_d0i3) +		return SKL_DSP_D0I3_NONE; +	else if (d0i3->streaming) +		return SKL_DSP_D0I3_STREAMING; +	else if (d0i3->non_streaming) +		return SKL_DSP_D0I3_NON_STREAMING; +	else +		return SKL_DSP_D0I3_NONE; +} + +static void bxt_set_dsp_D0i3(struct work_struct *work) +{ +	int ret; +	struct skl_ipc_d0ix_msg msg; +	struct skl_sst *skl = container_of(work, +			struct skl_sst, d0i3.work.work); +	struct sst_dsp *ctx = skl->dsp; +	struct skl_d0i3_data *d0i3 = &skl->d0i3; +	int target_state; + +	dev_dbg(ctx->dev, "In %s:\n", __func__); + +	/* D0i3 entry allowed only if core 0 alone is running */ +	if (skl_dsp_get_enabled_cores(ctx) !=  SKL_DSP_CORE0_MASK) { +		dev_warn(ctx->dev, +				"D0i3 allowed when only core0 running:Exit\n"); +		return; +	} + +	target_state = bxt_d0i3_target_state(ctx); +	if (target_state == SKL_DSP_D0I3_NONE) +		return; + +	msg.instance_id = 0; +	msg.module_id = 0; +	msg.wake = 1; +	msg.streaming = 0; +	if (target_state == SKL_DSP_D0I3_STREAMING) +		msg.streaming = 1; + +	ret =  skl_ipc_set_d0ix(&skl->ipc, &msg); + +	if (ret < 0) { +		dev_err(ctx->dev, "Failed to set DSP to D0i3 state\n"); +		return; +	} + +	/* Set Vendor specific register D0I3C.I3 to enable D0i3*/ +	if (skl->update_d0i3c) +		skl->update_d0i3c(skl->dev, true); + +	d0i3->state = target_state; +	skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING_D0I3; +} + +static int bxt_schedule_dsp_D0i3(struct sst_dsp *ctx) +{ +	struct skl_sst *skl = ctx->thread_context; +	struct skl_d0i3_data *d0i3 = &skl->d0i3; + +	/* Schedule D0i3 only if the usecase ref counts are appropriate */ +	if (bxt_d0i3_target_state(ctx) != SKL_DSP_D0I3_NONE) { + +		dev_dbg(ctx->dev, "%s: Schedule D0i3\n", __func__); + +		schedule_delayed_work(&d0i3->work, +				msecs_to_jiffies(BXT_D0I3_DELAY)); +	} + +	return 0; +} + +static int bxt_set_dsp_D0i0(struct sst_dsp *ctx) +{ +	int ret; +	struct skl_ipc_d0ix_msg msg; +	struct skl_sst *skl = ctx->thread_context; + +	dev_dbg(ctx->dev, "In %s:\n", __func__); + +	/* First Cancel any pending attempt to put DSP to D0i3 */ +	cancel_delayed_work_sync(&skl->d0i3.work); + +	/* If DSP is currently in D0i3, bring it to D0i0 */ +	if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING_D0I3) +		return 0; + +	dev_dbg(ctx->dev, "Set DSP to D0i0\n"); + +	msg.instance_id = 0; +	msg.module_id = 0; +	msg.streaming = 0; +	msg.wake = 0; + +	if (skl->d0i3.state == SKL_DSP_D0I3_STREAMING) +		msg.streaming = 1; + +	/* Clear Vendor specific register D0I3C.I3 to disable D0i3*/ +	if (skl->update_d0i3c) +		skl->update_d0i3c(skl->dev, false); + +	ret =  skl_ipc_set_d0ix(&skl->ipc, &msg); +	if (ret < 0) { +		dev_err(ctx->dev, "Failed to set DSP to D0i0\n"); +		return ret; +	} + +	skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING; +	skl->d0i3.state = SKL_DSP_D0I3_NONE; + +	return 0; +} +  static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)  {  	struct skl_sst *skl = ctx->thread_context; @@ -414,6 +552,8 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)  static struct skl_dsp_fw_ops bxt_fw_ops = {  	.set_state_D0 = bxt_set_dsp_D0,  	.set_state_D3 = bxt_set_dsp_D3, +	.set_state_D0i3 = bxt_schedule_dsp_D0i3, +	.set_state_D0i0 = bxt_set_dsp_D0i0,  	.load_fw = bxt_load_base_firmware,  	.get_fw_errcode = bxt_get_errorcode,  	.load_library = bxt_load_library, @@ -470,10 +610,15 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,  	if (ret)  		return ret; +	/* set the D0i3 check */ +	skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0; +  	skl->cores.count = 2;  	skl->boot_complete = false;  	init_waitqueue_head(&skl->boot_wait);  	skl->is_first_boot = true; +	INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3); +	skl->d0i3.state = SKL_DSP_D0I3_NONE;  	if (dsp)  		*dsp = skl; diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 805b7f2173f3..e79cbcf6e462 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -294,6 +294,33 @@ int skl_free_dsp(struct skl *skl)  	return 0;  } +/* + * In the case of "suspend_active" i.e, the Audio IP being active + * during system suspend, immediately excecute any pending D0i3 work + * before suspending. This is needed for the IP to work in low power + * mode during system suspend. In the case of normal suspend, cancel + * any pending D0i3 work. + */ +int skl_suspend_late_dsp(struct skl *skl) +{ +	struct skl_sst *ctx = skl->skl_sst; +	struct delayed_work *dwork; + +	if (!ctx) +		return 0; + +	dwork = &ctx->d0i3.work; + +	if (dwork->work.func) { +		if (skl->supend_active) +			flush_delayed_work(dwork); +		else +			cancel_delayed_work_sync(dwork); +	} + +	return 0; +} +  int skl_suspend_dsp(struct skl *skl)  {  	struct skl_sst *ctx = skl->skl_sst; @@ -500,16 +527,14 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,  int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig)  {  	struct skl_dma_control *dma_ctrl; -	struct skl_i2s_config_blob config_blob;  	struct skl_ipc_large_config_msg msg = {0};  	int err = 0;  	/* -	 * if blob size is same as capablity size, then no dma control -	 * present so return +	 * if blob size zero, then return  	 */ -	if (mconfig->formats_config.caps_size == sizeof(config_blob)) +	if (mconfig->formats_config.caps_size == 0)  		return 0;  	msg.large_param_id = DMA_CONTROL_ID; @@ -523,7 +548,7 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig)  	dma_ctrl->node_id = skl_get_node_id(ctx, mconfig);  	/* size in dwords */ -	dma_ctrl->config_length = sizeof(config_blob) / 4; +	dma_ctrl->config_length = mconfig->formats_config.caps_size / 4;  	memcpy(dma_ctrl->config_data, mconfig->formats_config.caps,  				mconfig->formats_config.caps_size); @@ -531,7 +556,6 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig)  	err = skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)dma_ctrl);  	kfree(dma_ctrl); -  	return err;  } @@ -1042,7 +1066,8 @@ int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe)  	dev_dbg(ctx->dev, "%s: pipe_id = %d\n", __func__, pipe->ppl_id);  	ret = skl_ipc_create_pipeline(&ctx->ipc, pipe->memory_pages, -				pipe->pipe_priority, pipe->ppl_id); +				pipe->pipe_priority, pipe->ppl_id, +				pipe->lp_mode);  	if (ret < 0) {  		dev_err(ctx->dev, "Failed to create pipeline\n");  		return ret; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 58c728662600..84b5101e6ca6 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -144,6 +144,8 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,  	struct hdac_ext_stream *stream;  	struct snd_pcm_runtime *runtime = substream->runtime;  	struct skl_dma_params *dma_params; +	struct skl *skl = get_skl_ctx(dai->dev); +	struct skl_module_cfg *mconfig;  	dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -177,6 +179,9 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,  	skl_set_suspend_active(substream, dai, true);  	snd_pcm_set_sync(substream); +	mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); +	skl_tplg_d0i3_get(skl, mconfig->d0i3_caps); +  	return 0;  } @@ -302,6 +307,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,  	struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);  	struct skl_dma_params *dma_params = NULL;  	struct skl *skl = ebus_to_skl(ebus); +	struct skl_module_cfg *mconfig;  	dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -325,6 +331,9 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,  		skl->skl_sst->miscbdcg_disabled = false;  	} +	mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); +	skl_tplg_d0i3_put(skl, mconfig->d0i3_caps); +  	kfree(dma_params);  } @@ -1031,10 +1040,24 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer  			(struct snd_pcm_substream *substream)  {  	struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); +	struct hdac_ext_bus *ebus = get_bus_ctx(substream);  	unsigned int pos; -	/* use the position buffer as default */ -	pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); +	/* +	 * Use DPIB for Playback stream as the periodic DMA Position-in- +	 * Buffer Writes may be scheduled at the same time or later than +	 * the MSI and does not guarantee to reflect the Position of the +	 * last buffer that was transferred. Whereas DPIB register in +	 * HAD space reflects the actual data that is transferred. +	 * Use the position buffer for capture, as DPIB write gets +	 * completed earlier than the actual data written to the DDR. +	 */ +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +		pos = readl(ebus->bus.remap_addr + AZX_REG_VS_SDXDPIB_XBASE + +				(AZX_REG_VS_SDXDPIB_XINTERVAL * +				hdac_stream(hstream)->index)); +	else +		pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream));  	if (pos >= hdac_stream(hstream)->bufsize)  		pos = 0; @@ -1197,6 +1220,7 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)  			return ret;  		}  		skl_populate_modules(skl); +		skl->skl_sst->update_d0i3c = skl_update_d0i3c;  	}  	pm_runtime_mark_last_busy(platform->dev);  	pm_runtime_put_autosuspend(platform->dev); diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index efa2532114ba..c9f6d87381db 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -17,7 +17,6 @@  #include <linux/device.h>  #include <linux/mm.h> -#include <linux/kthread.h>  #include <linux/delay.h>  #include "../common/sst-dsp.h"  #include "../common/sst-dsp-priv.h" diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index b9e71d051fb1..7c272ba0f4b5 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -126,11 +126,21 @@ struct sst_dsp_device;  #define SKL_ADSPCS_CPA_SHIFT		24  #define SKL_ADSPCS_CPA_MASK(cm)		((cm) << SKL_ADSPCS_CPA_SHIFT) +/* DSP Core state */  enum skl_dsp_states {  	SKL_DSP_RUNNING = 1, +	/* Running in D0i3 state; can be in streaming or non-streaming D0i3 */ +	SKL_DSP_RUNNING_D0I3, /* Running in D0i3 state*/  	SKL_DSP_RESET,  }; +/* D0i3 substates */ +enum skl_dsp_d0i3_states { +	SKL_DSP_D0I3_NONE = -1, /* No D0i3 */ +	SKL_DSP_D0I3_NON_STREAMING = 0, +	SKL_DSP_D0I3_STREAMING = 1, +}; +  struct skl_dsp_fw_ops {  	int (*load_fw)(struct sst_dsp  *ctx);  	/* FW module parser/loader */ @@ -139,6 +149,8 @@ struct skl_dsp_fw_ops {  	int (*parse_fw)(struct sst_dsp *ctx);  	int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id);  	int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id); +	int (*set_state_D0i3)(struct sst_dsp *ctx); +	int (*set_state_D0i0)(struct sst_dsp *ctx);  	unsigned int (*get_fw_errcode)(struct sst_dsp *ctx);  	int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, u8 *mod_name);  	int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 797cf4053235..e1391dfbc9e9 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -81,6 +81,11 @@  #define IPC_INSTANCE_ID(x)		(((x) & IPC_INSTANCE_ID_MASK) \  					<< IPC_INSTANCE_ID_SHIFT) +#define IPC_PPL_LP_MODE_SHIFT           0 +#define IPC_PPL_LP_MODE_MASK            0x1 +#define IPC_PPL_LP_MODE(x)              (((x) & IPC_PPL_LP_MODE_MASK) \ +					<< IPC_PPL_LP_MODE_SHIFT) +  /* Set pipeline state message */  #define IPC_PPL_STATE_SHIFT		0  #define IPC_PPL_STATE_MASK		0x1F @@ -172,6 +177,17 @@  					<< IPC_INITIAL_BLOCK_SHIFT)  #define IPC_INITIAL_BLOCK_CLEAR		~(IPC_INITIAL_BLOCK_MASK \  					  << IPC_INITIAL_BLOCK_SHIFT) +/* Set D0ix IPC extension register */ +#define IPC_D0IX_WAKE_SHIFT		0 +#define IPC_D0IX_WAKE_MASK		0x1 +#define IPC_D0IX_WAKE(x)		(((x) & IPC_D0IX_WAKE_MASK) \ +					<< IPC_D0IX_WAKE_SHIFT) + +#define IPC_D0IX_STREAMING_SHIFT	1 +#define IPC_D0IX_STREAMING_MASK		0x1 +#define IPC_D0IX_STREAMING(x)		(((x) & IPC_D0IX_STREAMING_MASK) \ +					<< IPC_D0IX_STREAMING_SHIFT) +  enum skl_ipc_msg_target {  	IPC_FW_GEN_MSG = 0, @@ -258,7 +274,8 @@ enum skl_ipc_module_msg {  	IPC_MOD_LARGE_CONFIG_SET = 4,  	IPC_MOD_BIND = 5,  	IPC_MOD_UNBIND = 6, -	IPC_MOD_SET_DX = 7 +	IPC_MOD_SET_DX = 7, +	IPC_MOD_SET_D0IX = 8  };  static void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data, @@ -289,6 +306,23 @@ static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg)  		header->primary | SKL_ADSP_REG_HIPCI_BUSY);  } +int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state) +{ +	int ret; + +	/* check D0i3 support */ +	if (!dsp->fw_ops.set_state_D0i0) +		return 0; + +	/* Attempt D0i0 or D0i3 based on state */ +	if (state) +		ret = dsp->fw_ops.set_state_D0i0(dsp); +	else +		ret = dsp->fw_ops.set_state_D0i3(dsp); + +	return ret; +} +  static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc,  				u64 ipc_header)  { @@ -464,7 +498,7 @@ irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context)  	skl_ipc_int_enable(dsp);  	/* continue to send any remaining messages... */ -	kthread_queue_work(&ipc->kworker, &ipc->kwork); +	schedule_work(&ipc->kwork);  	return IRQ_HANDLED;  } @@ -547,7 +581,7 @@ void skl_ipc_free(struct sst_generic_ipc *ipc)  }  int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, -		u16 ppl_mem_size, u8 ppl_type, u8 instance_id) +		u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode)  {  	struct skl_ipc_header header = {0};  	u64 *ipc_header = (u64 *)(&header); @@ -560,6 +594,8 @@ int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc,  	header.primary |= IPC_PPL_TYPE(ppl_type);  	header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size); +	header.extension = IPC_PPL_LP_MODE(lp_mode); +  	dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);  	ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);  	if (ret < 0) { @@ -931,3 +967,32 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc,  	return ret;  }  EXPORT_SYMBOL_GPL(skl_sst_ipc_load_library); + +int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg) +{ +	struct skl_ipc_header header = {0}; +	u64 *ipc_header = (u64 *)(&header); +	int ret; + +	header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); +	header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); +	header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_D0IX); +	header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); +	header.primary |= IPC_MOD_ID(msg->module_id); + +	header.extension = IPC_D0IX_WAKE(msg->wake); +	header.extension |= IPC_D0IX_STREAMING(msg->streaming); + +	dev_dbg(ipc->dev, "In %s primary=%x ext=%x\n", __func__, +			header.primary,	header.extension); + +	/* +	 * Use the nopm IPC here as we dont want it checking for D0iX +	 */ +	ret = sst_ipc_tx_message_nopm(ipc, *ipc_header, NULL, 0, NULL, 0); +	if (ret < 0) +		dev_err(ipc->dev, "ipc: set d0ix failed, err %d\n", ret); + +	return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_set_d0ix); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 0334ed4af031..cc40341233fa 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -16,7 +16,6 @@  #ifndef __SKL_IPC_H  #define __SKL_IPC_H -#include <linux/kthread.h>  #include <linux/irqreturn.h>  #include "../common/sst-ipc.h" @@ -53,6 +52,23 @@ struct skl_dsp_cores {  	int usage_count[SKL_DSP_CORES_MAX];  }; +/** + * skl_d0i3_data: skl D0i3 counters data struct + * + * @streaming: Count of usecases that can attempt streaming D0i3 + * @non_streaming: Count of usecases that can attempt non-streaming D0i3 + * @non_d0i3: Count of usecases that cannot attempt D0i3 + * @state: current state + * @work: D0i3 worker thread + */ +struct skl_d0i3_data { +	int streaming; +	int non_streaming; +	int non_d0i3; +	enum skl_dsp_d0i3_states state; +	struct delayed_work work; +}; +  struct skl_sst {  	struct device *dev;  	struct sst_dsp *dsp; @@ -83,6 +99,11 @@ struct skl_sst {  	/* tplg manifest */  	struct skl_dfw_manifest manifest; + +	/* Callback to update D0i3C register */ +	void (*update_d0i3c)(struct device *dev, bool enable); + +	struct skl_d0i3_data d0i3;  };  struct skl_ipc_init_instance_msg { @@ -111,6 +132,13 @@ struct skl_ipc_large_config_msg {  	u32 param_data_size;  }; +struct skl_ipc_d0ix_msg { +	u32 module_id; +	u32 instance_id; +	u8 streaming; +	u8 wake; +}; +  #define SKL_IPC_BOOT_MSECS		3000  #define SKL_IPC_D3_MASK	0 @@ -119,7 +147,7 @@ struct skl_ipc_large_config_msg {  irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context);  int skl_ipc_create_pipeline(struct sst_generic_ipc *sst_ipc, -		u16 ppl_mem_size, u8 ppl_type, u8 instance_id); +		u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode);  int skl_ipc_delete_pipeline(struct sst_generic_ipc *sst_ipc, u8 instance_id); @@ -155,6 +183,11 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,  int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc,  			u8 dma_id, u8 table_id); +int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, +		struct skl_ipc_d0ix_msg *msg); + +int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state); +  void skl_ipc_int_enable(struct sst_dsp *dsp);  void skl_ipc_op_int_enable(struct sst_dsp *ctx);  void skl_ipc_op_int_disable(struct sst_dsp *ctx); diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c index 8dc03039b311..ea162fbf68e5 100644 --- a/sound/soc/intel/skylake/skl-sst-utils.c +++ b/sound/soc/intel/skylake/skl-sst-utils.c @@ -179,7 +179,7 @@ static inline int skl_getid_32(struct uuid_module *module, u64 *val,  		index = ffz(mask_val);  		pvt_id = index + word1_mask + word2_mask;  		if (pvt_id <= (max_inst - 1)) { -			*val |= 1 << (index + word1_mask); +			*val |= 1ULL << (index + word1_mask);  			return pvt_id;  		}  	} diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index b5b1934d8550..bd313c907b20 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -36,6 +36,44 @@  #define SKL_IN_DIR_BIT_MASK		BIT(0)  #define SKL_PIN_COUNT_MASK		GENMASK(7, 4) +void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps) +{ +	struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3; + +	switch (caps) { +	case SKL_D0I3_NONE: +		d0i3->non_d0i3++; +		break; + +	case SKL_D0I3_STREAMING: +		d0i3->streaming++; +		break; + +	case SKL_D0I3_NON_STREAMING: +		d0i3->non_streaming++; +		break; +	} +} + +void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps) +{ +	struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3; + +	switch (caps) { +	case SKL_D0I3_NONE: +		d0i3->non_d0i3--; +		break; + +	case SKL_D0I3_STREAMING: +		d0i3->streaming--; +		break; + +	case SKL_D0I3_NON_STREAMING: +		d0i3->non_streaming--; +		break; +	} +} +  /*   * SKL DSP driver modelling uses only few DAPM widgets so for rest we will   * ignore. This helpers checks if the SKL driver handles this widget type @@ -1519,6 +1557,10 @@ static int skl_tplg_fill_pipe_tkn(struct device *dev,  		pipe->memory_pages = tkn_val;  		break; +	case SKL_TKN_U32_PMODE: +		pipe->lp_mode = tkn_val; +		break; +  	default:  		dev_err(dev, "Token not handled %d\n", tkn);  		return -EINVAL; @@ -1826,6 +1868,10 @@ static int skl_tplg_get_token(struct device *dev,  		mconfig->converter = tkn_elem->value;  		break; +	case SKL_TKL_U32_D0I3_CAPS: +		mconfig->d0i3_caps = tkn_elem->value; +		break; +  	case SKL_TKN_U32_PIPE_ID:  		ret = skl_tplg_add_pipe(dev,  				mconfig, skl, tkn_elem); @@ -1841,6 +1887,7 @@ static int skl_tplg_get_token(struct device *dev,  	case SKL_TKN_U32_PIPE_CONN_TYPE:  	case SKL_TKN_U32_PIPE_PRIORITY:  	case SKL_TKN_U32_PIPE_MEM_PGS: +	case SKL_TKN_U32_PMODE:  		if (is_pipe_exists) {  			ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,  					tkn_elem->token, tkn_elem->value); diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index a519360f42a6..08d39280b07b 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -113,23 +113,6 @@ struct skl_cpr_gtw_cfg {  	u32 config_data[1];  } __packed; -struct skl_i2s_config_blob { -	u32 gateway_attrib; -	u32 tdm_ts_group[8]; -	u32 ssc0; -	u32 ssc1; -	u32 sscto; -	u32 sspsp; -	u32 sstsa; -	u32 ssrsa; -	u32 ssc2; -	u32 sspsp2; -	u32 ssc3; -	u32 ssioc; -	u32 mdivc; -	u32 mdivr; -} __packed; -  struct skl_dma_control {  	u32 node_id;  	u32 config_length; @@ -279,6 +262,7 @@ struct skl_pipe {  	u8 pipe_priority;  	u16 conn_type;  	u32 memory_pages; +	u8 lp_mode;  	struct skl_pipe_params *p_params;  	enum skl_pipe_state state;  	struct list_head w_list; @@ -293,6 +277,12 @@ enum skl_module_state {  	SKL_MODULE_UNLOADED = 4,  }; +enum d0i3_capability { +	SKL_D0I3_NONE = 0, +	SKL_D0I3_STREAMING = 1, +	SKL_D0I3_NON_STREAMING = 2, +}; +  struct skl_module_cfg {  	u8 guid[16];  	struct skl_module_inst_id id; @@ -319,6 +309,7 @@ struct skl_module_cfg {  	u32 converter;  	u32 vbus_id;  	u32 mem_pages; +	enum d0i3_capability d0i3_caps;  	struct skl_module_pin *m_in_pin;  	struct skl_module_pin *m_out_pin;  	enum skl_module_type m_type; @@ -361,6 +352,9 @@ struct skl_module_cfg *skl_tplg_fe_get_cpr_module(  int skl_tplg_update_pipe_params(struct device *dev,  		struct skl_module_cfg *mconfig, struct skl_pipe_params *params); +void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps); +void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps); +  int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe);  int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 06fa5e85dd0e..da5db5098274 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -26,6 +26,7 @@  #include <linux/pm_runtime.h>  #include <linux/platform_device.h>  #include <linux/firmware.h> +#include <linux/delay.h>  #include <sound/pcm.h>  #include "../common/sst-acpi.h"  #include <sound/hda_register.h> @@ -109,6 +110,52 @@ static int skl_init_chip(struct hdac_bus *bus, bool full_reset)  	return ret;  } +void skl_update_d0i3c(struct device *dev, bool enable) +{ +	struct pci_dev *pci = to_pci_dev(dev); +	struct hdac_ext_bus *ebus = pci_get_drvdata(pci); +	struct hdac_bus *bus = ebus_to_hbus(ebus); +	u8 reg; +	int timeout = 50; + +	reg = snd_hdac_chip_readb(bus, VS_D0I3C); +	/* Do not write to D0I3C until command in progress bit is cleared */ +	while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { +		udelay(10); +		reg = snd_hdac_chip_readb(bus, VS_D0I3C); +	} + +	/* Highly unlikely. But if it happens, flag error explicitly */ +	if (!timeout) { +		dev_err(bus->dev, "Before D0I3C update: D0I3C CIP timeout\n"); +		return; +	} + +	if (enable) +		reg = reg | AZX_REG_VS_D0I3C_I3; +	else +		reg = reg & (~AZX_REG_VS_D0I3C_I3); + +	snd_hdac_chip_writeb(bus, VS_D0I3C, reg); + +	timeout = 50; +	/* Wait for cmd in progress to be cleared before exiting the function */ +	reg = snd_hdac_chip_readb(bus, VS_D0I3C); +	while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { +		udelay(10); +		reg = snd_hdac_chip_readb(bus, VS_D0I3C); +	} + +	/* Highly unlikely. But if it happens, flag error explicitly */ +	if (!timeout) { +		dev_err(bus->dev, "After D0I3C update: D0I3C CIP timeout\n"); +		return; +	} + +	dev_dbg(bus->dev, "D0I3C register = 0x%x\n", +			snd_hdac_chip_readb(bus, VS_D0I3C)); +} +  /* called from IRQ */  static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr)  { @@ -181,6 +228,15 @@ static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect)  	return 0;  } +static int skl_suspend_late(struct device *dev) +{ +	struct pci_dev *pci = to_pci_dev(dev); +	struct hdac_ext_bus *ebus = pci_get_drvdata(pci); +	struct skl *skl = ebus_to_skl(ebus); + +	return skl_suspend_late_dsp(skl); +} +  #ifdef CONFIG_PM  static int _skl_suspend(struct hdac_ext_bus *ebus)  { @@ -243,7 +299,6 @@ static int skl_suspend(struct device *dev)  		enable_irq_wake(bus->irq);  		pci_save_state(pci); -		pci_disable_device(pci);  	} else {  		ret = _skl_suspend(ebus);  		if (ret < 0) @@ -286,7 +341,6 @@ static int skl_resume(struct device *dev)  	 */  	if (skl->supend_active) {  		pci_restore_state(pci); -		ret = pci_enable_device(pci);  		snd_hdac_ext_bus_link_power_up_all(ebus);  		disable_irq_wake(bus->irq);  		/* @@ -345,6 +399,7 @@ static int skl_runtime_resume(struct device *dev)  static const struct dev_pm_ops skl_pm = {  	SET_SYSTEM_SLEEP_PM_OPS(skl_suspend, skl_resume)  	SET_RUNTIME_PM_OPS(skl_runtime_suspend, skl_runtime_resume, NULL) +	.suspend_late = skl_suspend_late,  };  /* diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 5d4fbb094c48..4986e3929dd3 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -52,6 +52,9 @@  #define AZX_PGCTL_LSRMD_MASK		(1 << 4)  #define AZX_PCIREG_CGCTL		0x48  #define AZX_CGCTL_MISCBDCGE_MASK	(1 << 6) +/* D0I3C Register fields */ +#define AZX_REG_VS_D0I3C_CIP      0x1 /* Command in progress */ +#define AZX_REG_VS_D0I3C_I3       0x4 /* D0i3 enable */  struct skl_dsp_resource {  	u32 max_mcps; @@ -121,8 +124,11 @@ int skl_get_dmic_geo(struct skl *skl);  int skl_nhlt_update_topology_bin(struct skl *skl);  int skl_init_dsp(struct skl *skl);  int skl_free_dsp(struct skl *skl); +int skl_suspend_late_dsp(struct skl *skl);  int skl_suspend_dsp(struct skl *skl);  int skl_resume_dsp(struct skl *skl);  void skl_cleanup_resources(struct skl *skl);  const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); +void skl_update_d0i3c(struct device *dev, bool enable); +  #endif /* __SOUND_SOC_SKL_H */ diff --git a/sound/soc/kirkwood/armada-370-db.c b/sound/soc/kirkwood/armada-370-db.c index e0304d544f26..677a48d7b891 100644 --- a/sound/soc/kirkwood/armada-370-db.c +++ b/sound/soc/kirkwood/armada-370-db.c @@ -42,7 +42,7 @@ static int a370db_hw_params(struct snd_pcm_substream *substream,  	return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN);  } -static struct snd_soc_ops a370db_ops = { +static const struct snd_soc_ops a370db_ops = {  	.hw_params = a370db_hw_params,  }; diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index 13631003cb7c..a002ab892772 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -735,6 +735,11 @@ static int mxs_saif_probe(struct platform_device *pdev)  	else  		saif->id = ret; +	if (saif->id >= ARRAY_SIZE(mxs_saif)) { +		dev_err(&pdev->dev, "get wrong saif id\n"); +		return -EINVAL; +	} +  	/*  	 * If there is no "fsl,saif-master" phandle, it's a saif  	 * master.  Otherwise, it's a slave and its phandle points @@ -749,11 +754,11 @@ static int mxs_saif_probe(struct platform_device *pdev)  			return ret;  		else  			saif->master_id = ret; -	} -	if (saif->master_id >= ARRAY_SIZE(mxs_saif)) { -		dev_err(&pdev->dev, "get wrong master id\n"); -		return -EINVAL; +		if (saif->master_id >= ARRAY_SIZE(mxs_saif)) { +			dev_err(&pdev->dev, "get wrong master id\n"); +			return -EINVAL; +		}  	}  	mxs_saif[saif->id] = saif; diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index 2b23ffbac6b1..a96276e77332 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -68,7 +68,7 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream,  	return 0;  } -static struct snd_soc_ops mxs_sgtl5000_hifi_ops = { +static const struct snd_soc_ops mxs_sgtl5000_hifi_ops = {  	.hw_params = mxs_sgtl5000_hw_params,  }; diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index dcbb7aa9830c..311774e9ca46 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -244,9 +244,9 @@ static const struct snd_soc_dapm_route corgi_audio_map[] = {  	{"MICIN", NULL, "Line Jack"},  }; -static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", -	"Off"}; -static const char *spk_function[] = {"On", "Off"}; +static const char * const jack_function[] = {"Headphone", "Mic", "Line", +	"Headset", "Off"}; +static const char * const spk_function[] = {"On", "Off"};  static const struct soc_enum corgi_enum[] = {  	SOC_ENUM_SINGLE_EXT(5, jack_function),  	SOC_ENUM_SINGLE_EXT(2, spk_function), diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c index 1de876529aa1..086c37a85630 100644 --- a/sound/soc/pxa/e740_wm9705.c +++ b/sound/soc/pxa/e740_wm9705.c @@ -22,7 +22,6 @@  #include <asm/mach-types.h> -#include "../codecs/wm9705.h"  #include "pxa2xx-ac97.h" diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c index b7eb7cd5df7d..7823278012a6 100644 --- a/sound/soc/pxa/e750_wm9705.c +++ b/sound/soc/pxa/e750_wm9705.c @@ -22,7 +22,6 @@  #include <asm/mach-types.h> -#include "../codecs/wm9705.h"  #include "pxa2xx-ac97.h"  static int e750_spk_amp_event(struct snd_soc_dapm_widget *w, diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index 41bf71466a7b..07b9c6e17df9 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c @@ -21,7 +21,6 @@  #include <mach/audio.h>  #include <mach/eseries-gpio.h> -#include "../codecs/wm9712.h"  #include "pxa2xx-ac97.h"  static int e800_spk_amp_event(struct snd_soc_dapm_widget *w, diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c index 64743a05aeae..966163d1c813 100644 --- a/sound/soc/pxa/em-x270.c +++ b/sound/soc/pxa/em-x270.c @@ -30,7 +30,6 @@  #include <asm/mach-types.h>  #include <mach/audio.h> -#include "../codecs/wm9712.h"  #include "pxa2xx-ac97.h"  static struct snd_soc_dai_link em_x270_dai[] = { diff --git a/sound/soc/pxa/hx4700.c b/sound/soc/pxa/hx4700.c index ecbf2873b7ff..85483049b916 100644 --- a/sound/soc/pxa/hx4700.c +++ b/sound/soc/pxa/hx4700.c @@ -27,8 +27,6 @@  #include <asm/mach-types.h>  #include "pxa2xx-i2s.h" -#include "../codecs/ak4641.h" -  static struct snd_soc_jack hs_jack;  /* Headphones jack detection DAPM pin */ diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index 62b8377a9d2b..2d4d4455fe87 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c @@ -376,7 +376,7 @@ static const struct snd_soc_dapm_route audio_map[] = {  	{"VINM", NULL, "Call Mic"},  }; -static const char *input_select[] = {"Call Mic", "Headset Mic"}; +static const char * const input_select[] = {"Call Mic", "Headset Mic"};  static const struct soc_enum magician_in_sel_enum =  	SOC_ENUM_SINGLE_EXT(2, input_select); diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c index d1661fa6ee08..0fe0abec8fc4 100644 --- a/sound/soc/pxa/mioa701_wm9713.c +++ b/sound/soc/pxa/mioa701_wm9713.c @@ -187,7 +187,7 @@ static int mioa701_wm9713_probe(struct platform_device *pdev)  	mioa701.dev = &pdev->dev;  	rc = devm_snd_soc_register_card(&pdev->dev, &mioa701);  	if (!rc) -		dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will" +		dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will "  			 "lead to overheating and possible destruction of your device."  			 " Do not use without a good knowledge of mio's board design!\n");  	return rc; diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index bcc81e920a67..387492d46b6c 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c @@ -27,7 +27,6 @@  #include <mach/audio.h>  #include <linux/platform_data/asoc-palm27x.h> -#include "../codecs/wm9712.h"  #include "pxa2xx-ac97.h"  static struct snd_soc_jack hs_jack; diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index 4b3b714f5ee7..a879aba0691f 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -209,8 +209,8 @@ static const struct snd_soc_dapm_route poodle_audio_map[] = {  	{"MICIN", NULL, "Microphone"},  }; -static const char *jack_function[] = {"Off", "Headphone"}; -static const char *spk_function[] = {"Off", "On"}; +static const char * const jack_function[] = {"Off", "Headphone"}; +static const char * const spk_function[] = {"Off", "On"};  static const struct soc_enum poodle_enum[] = {  	SOC_ENUM_SINGLE_EXT(2, jack_function),  	SOC_ENUM_SINGLE_EXT(2, spk_function), diff --git a/sound/soc/pxa/pxa-ssp.h b/sound/soc/pxa/pxa-ssp.h index bc79da221c0d..abf6ec080258 100644 --- a/sound/soc/pxa/pxa-ssp.h +++ b/sound/soc/pxa/pxa-ssp.h @@ -9,12 +9,6 @@  #ifndef _PXA_SSP_H  #define _PXA_SSP_H -/* pxa DAI SSP IDs */ -#define PXA_DAI_SSP1			0 -#define PXA_DAI_SSP2			1 -#define PXA_DAI_SSP3			2 -#define PXA_DAI_SSP4			3 -  /* SSP clock sources */  #define PXA_SSP_CLK_PLL	0  #define PXA_SSP_CLK_EXT	1 diff --git a/sound/soc/pxa/pxa2xx-i2s.h b/sound/soc/pxa/pxa2xx-i2s.h index 070f3c6059fe..7e218e2105a9 100644 --- a/sound/soc/pxa/pxa2xx-i2s.h +++ b/sound/soc/pxa/pxa2xx-i2s.h @@ -9,9 +9,6 @@  #ifndef _PXA2XX_I2S_H  #define _PXA2XX_I2S_H -/* pxa2xx DAI ID's */ -#define PXA2XX_DAI_I2S			0 -  /* I2S clock */  #define PXA2XX_I2S_SYSCLK		0 diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 0e02634c8b7f..07d77cddac60 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -241,9 +241,9 @@ static const struct snd_soc_dapm_route spitz_audio_map[] = {  	{"LINPUT1", NULL, "Line Jack"},  }; -static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", -	"Off"}; -static const char *spk_function[] = {"On", "Off"}; +static const char * const jack_function[] = {"Headphone", "Mic", "Line", +	"Headset", "Off"}; +static const char * const spk_function[] = {"On", "Off"};  static const struct soc_enum spitz_enum[] = {  	SOC_ENUM_SINGLE_EXT(5, jack_function),  	SOC_ENUM_SINGLE_EXT(2, spk_function), diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index c508f024ecfb..2e312c62e3c7 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -31,7 +31,6 @@  #include <mach/tosa.h>  #include <mach/audio.h> -#include "../codecs/wm9712.h"  #include "pxa2xx-ac97.h"  #define TOSA_HP        0 @@ -170,9 +169,9 @@ static const struct snd_soc_dapm_route audio_map[] = {  	{"Mic Bias", NULL, "Headset Jack"},  }; -static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", -	"Off"}; -static const char *spk_function[] = {"On", "Off"}; +static const char * const jack_function[] = {"Headphone", "Mic", "Line", +	"Headset", "Off"}; +static const char * const spk_function[] = {"On", "Off"};  static const struct soc_enum tosa_enum[] = {  	SOC_ENUM_SINGLE_EXT(5, jack_function),  	SOC_ENUM_SINGLE_EXT(2, spk_function), diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index 07f91e918b23..d084d7468299 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -123,20 +123,15 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card)  			return ERR_PTR(-EINVAL);  		} -		link->codec_of_node = of_parse_phandle(codec, "sound-dai", 0); -		if (!link->codec_of_node) { -			dev_err(card->dev, "error getting codec phandle\n"); -			return ERR_PTR(-EINVAL); -		} -  		ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name);  		if (ret) {  			dev_err(card->dev, "error getting cpu dai name\n");  			return ERR_PTR(ret);  		} -		ret = snd_soc_of_get_dai_name(codec, &link->codec_dai_name); -		if (ret) { +		ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); + +		if (ret < 0) {  			dev_err(card->dev, "error getting codec dai name\n");  			return ERR_PTR(ret);  		} diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index b392e51de94d..dd5bdd0da730 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -25,8 +25,7 @@  #include "lpass.h"  struct lpass_pcm_data { -	int rdma_ch; -	int wrdma_ch; +	int dma_ch;  	int i2s_port;  }; @@ -78,6 +77,9 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)  	dma_ch = 0;  	if (v->alloc_dma_channel)  		dma_ch = v->alloc_dma_channel(drvdata, dir); +	else +		dma_ch = 0; +  	if (dma_ch < 0)  		return dma_ch; @@ -92,10 +94,7 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)  			return ret;  	} -	if (dir == SNDRV_PCM_STREAM_PLAYBACK) -		data->rdma_ch = dma_ch; -	else -		data->wrdma_ch = dma_ch; +	data->dma_ch = dma_ch;  	snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware); @@ -122,20 +121,12 @@ static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream)  		snd_soc_platform_get_drvdata(soc_runtime->platform);  	struct lpass_variant *v = drvdata->variant;  	struct lpass_pcm_data *data; -	int dma_ch, dir = substream->stream;  	data = runtime->private_data;  	v = drvdata->variant; - -	if (dir == SNDRV_PCM_STREAM_PLAYBACK) -		dma_ch = data->rdma_ch; -	else -		dma_ch = data->wrdma_ch; - -	drvdata->substream[dma_ch] = NULL; - +	drvdata->substream[data->dma_ch] = NULL;  	if (v->free_dma_channel) -		v->free_dma_channel(drvdata, dma_ch); +		v->free_dma_channel(drvdata, data->dma_ch);  	return 0;  } @@ -156,10 +147,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,  	int bitwidth;  	int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start; -	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) -		ch = pcm_data->rdma_ch; -	else -		ch = pcm_data->wrdma_ch; +	ch = pcm_data->dma_ch;  	bitwidth = snd_pcm_format_width(format);  	if (bitwidth < 0) { @@ -246,11 +234,7 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)  	unsigned int reg;  	int ret; -	if (substream->stream ==  SNDRV_PCM_STREAM_PLAYBACK) -		reg = LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch); -	else -		reg = LPAIF_WRDMACTL_REG(v, pcm_data->wrdma_ch); - +	reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream);  	ret = regmap_write(drvdata->lpaif_map, reg, 0);  	if (ret)  		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", @@ -270,10 +254,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)  	struct lpass_variant *v = drvdata->variant;  	int ret, ch, dir = substream->stream; -	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) -		ch = pcm_data->rdma_ch; -	else -		ch = pcm_data->wrdma_ch; +	ch = pcm_data->dma_ch;  	ret = regmap_write(drvdata->lpaif_map,  			LPAIF_DMABASE_REG(v, ch, dir), @@ -325,10 +306,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,  	struct lpass_variant *v = drvdata->variant;  	int ret, ch, dir = substream->stream; -	if (dir == SNDRV_PCM_STREAM_PLAYBACK) -		ch = pcm_data->rdma_ch; -	else -		ch = pcm_data->wrdma_ch; +	ch = pcm_data->dma_ch;  	switch (cmd) {  	case SNDRV_PCM_TRIGGER_START: @@ -403,10 +381,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(  	unsigned int base_addr, curr_addr;  	int ret, ch, dir = substream->stream; -	if (dir == SNDRV_PCM_STREAM_PLAYBACK) -		ch = pcm_data->rdma_ch; -	else -		ch = pcm_data->wrdma_ch; +	ch = pcm_data->dma_ch;  	ret = regmap_read(drvdata->lpaif_map,  			LPAIF_DMABASE_REG(v, ch, dir), &base_addr); diff --git a/sound/soc/qcom/storm.c b/sound/soc/qcom/storm.c index 2d833bffdba0..8fcac2ac3aa6 100644 --- a/sound/soc/qcom/storm.c +++ b/sound/soc/qcom/storm.c @@ -58,7 +58,7 @@ static int storm_ops_hw_params(struct snd_pcm_substream *substream,  	return 0;  } -static struct snd_soc_ops storm_soc_ops = { +static const struct snd_soc_ops storm_soc_ops = {  	.hw_params	= storm_ops_hw_params,  }; diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index 9ed735a6cf49..3475c61a5fa0 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -38,7 +38,7 @@  #define SOUND_FS	256 -unsigned int rt5514_dmic_delay; +static unsigned int rt5514_dmic_delay;  static struct snd_soc_jack rockchip_sound_jack; @@ -228,15 +228,15 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)  	return 0;  } -static struct snd_soc_ops rockchip_sound_max98357a_ops = { +static const struct snd_soc_ops rockchip_sound_max98357a_ops = {  	.hw_params = rockchip_sound_max98357a_hw_params,  }; -static struct snd_soc_ops rockchip_sound_rt5514_ops = { +static const struct snd_soc_ops rockchip_sound_rt5514_ops = {  	.hw_params = rockchip_sound_rt5514_hw_params,  }; -static struct snd_soc_ops rockchip_sound_da7219_ops = { +static const struct snd_soc_ops rockchip_sound_da7219_ops = {  	.hw_params = rockchip_sound_da7219_hw_params,  }; diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index e70ffad07184..789d6f1e2b5f 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -119,7 +119,7 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream,  	return ret;  } -static struct snd_soc_ops rk_aif1_ops = { +static const struct snd_soc_ops rk_aif1_ops = {  	.hw_params = rk_aif1_hw_params,  }; diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c index 440a8026346a..9e0c17805807 100644 --- a/sound/soc/rockchip/rockchip_rt5645.c +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -135,7 +135,7 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime)  				     &headset_jack);  } -static struct snd_soc_ops rk_aif1_ops = { +static const struct snd_soc_ops rk_aif1_ops = {  	.hw_params = rk_aif1_hw_params,  }; diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index f6023b46c107..7c423151ef7d 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -1,6 +1,7 @@  menuconfig SND_SOC_SAMSUNG  	tristate "ASoC support for Samsung" -	depends on (PLAT_SAMSUNG || ARCH_EXYNOS) +	depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST +	depends on COMMON_CLK  	select SND_SOC_GENERIC_DMAENGINE_PCM  	---help---  	  Say Y or M if you want to add support for codecs attached to @@ -22,10 +23,6 @@ config SND_S3C2412_SOC_I2S  config SND_SAMSUNG_PCM  	tristate "Samsung PCM interface support" -config SND_SAMSUNG_AC97 -	tristate -	select SND_SOC_AC97_BUS -  config SND_SAMSUNG_SPDIF  	tristate "Samsung SPDIF transmitter support"  	select SND_SOC_SPDIF @@ -53,7 +50,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750  config SND_SOC_SAMSUNG_SMDK_WM8580  	tristate "SoC I2S Audio support for WM8580 on SMDK" -	depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 +	depends on MACH_SMDK6410 || COMPILE_TEST  	depends on I2C  	select SND_SOC_WM8580  	select SND_SAMSUNG_I2S @@ -69,26 +66,6 @@ config SND_SOC_SAMSUNG_SMDK_WM8994  	help  		Say Y if you want to add support for SoC audio on the SMDKs. -config SND_SOC_SAMSUNG_SMDK2443_WM9710 -	tristate "SoC AC97 Audio support for SMDK2443 - WM9710" -	depends on MACH_SMDK2443 -	select AC97_BUS -	select SND_SOC_AC97_CODEC -	select SND_SAMSUNG_AC97 -	help -	  Say Y if you want to add support for SoC audio on smdk2443 -	  with the WM9710. - -config SND_SOC_SAMSUNG_LN2440SBC_ALC650 -	tristate "SoC AC97 Audio support for LN2440SBC - ALC650" -	depends on ARCH_S3C24XX -	select AC97_BUS -	select SND_SOC_AC97_CODEC -	select SND_SAMSUNG_AC97 -	help -	  Say Y if you want to add support for SoC audio on ln2440sbc -	  with the ALC650. -  config SND_SOC_SAMSUNG_S3C24XX_UDA134X  	tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"  	depends on ARCH_S3C24XX @@ -131,17 +108,10 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380  	help  	  This driver provides audio support for HP iPAQ RX1950 PDA. -config SND_SOC_SAMSUNG_SMDK_WM9713 -	tristate "SoC AC97 Audio support for SMDK with WM9713" -	depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 -	select SND_SOC_WM9713 -	select SND_SAMSUNG_AC97 -	help -	  Say Y if you want to add support for SoC audio on the SMDK. -  config SND_SOC_SMARTQ  	tristate "SoC I2S Audio support for SmartQ board" -	depends on MACH_SMARTQ && I2C +	depends on MACH_SMARTQ || COMPILE_TEST +	depends on I2C  	select SND_SAMSUNG_I2S  	select SND_SOC_WM8750 @@ -151,15 +121,6 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF  	help  	  Say Y if you want to add support for SoC S/PDIF audio on the SMDK. -config SND_SOC_SMDK_WM8580_PCM -	tristate "SoC PCM Audio support for WM8580 on SMDK" -	depends on MACH_SMDKV210 || MACH_SMDKC110 -	depends on I2C -	select SND_SOC_WM8580 -	select SND_SAMSUNG_PCM -	help -	  Say Y if you want to add support for SoC audio on the SMDK. -  config SND_SOC_SMDK_WM8994_PCM  	tristate "SoC PCM Audio support for WM8994 on SMDK"  	depends on I2C=y @@ -229,4 +190,13 @@ config SND_SOC_ARNDALE_RT5631_ALC5631          select SND_SAMSUNG_I2S          select SND_SOC_RT5631 +config SND_SOC_SAMSUNG_TM2_WM5110 +	tristate "SoC I2S Audio support for WM5110 on TM2 board" +	depends on SND_SOC_SAMSUNG && MFD_ARIZONA && I2C && SPI_MASTER +	select SND_SOC_MAX98504 +	select SND_SOC_WM5110 +	select SND_SAMSUNG_I2S +	help +	  Say Y if you want to add support for SoC audio on the TM2 board. +  endif #SND_SOC_SAMSUNG diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 5d03f5ce6916..b5df5e2e3d94 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -3,7 +3,6 @@ snd-soc-s3c-dma-objs := dmaengine.o  snd-soc-idma-objs := idma.o  snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o  snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o -snd-soc-ac97-objs := ac97.o  snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o  snd-soc-samsung-spdif-objs := spdif.o  snd-soc-pcm-objs := pcm.o @@ -11,7 +10,6 @@ snd-soc-i2s-objs := i2s.o  obj-$(CONFIG_SND_SOC_SAMSUNG) += snd-soc-s3c-dma.o  obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o -obj-$(CONFIG_SND_SAMSUNG_AC97) += snd-soc-ac97.o  obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o  obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o  obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o @@ -36,7 +34,6 @@ snd-soc-snow-objs := snow.o  snd-soc-smdk-wm9713-objs := smdk_wm9713.o  snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o  snd-soc-smdk-spdif-objs := smdk_spdif.o -snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o  snd-soc-smdk-wm8994pcm-objs := smdk_wm8994pcm.o  snd-soc-speyside-objs := speyside.o  snd-soc-tobermory-objs := tobermory.o @@ -44,11 +41,10 @@ snd-soc-lowland-objs := lowland.o  snd-soc-littlemill-objs := littlemill.o  snd-soc-bells-objs := bells.o  snd-soc-arndale-rt5631-objs := arndale_rt5631.o +snd-soc-tm2-wm5110-objs := tm2_wm5110.o  obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o  obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o -obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o -obj-$(CONFIG_SND_SOC_SAMSUNG_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o  obj-$(CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o  obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC) += snd-soc-s3c24xx-simtec.o  obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o @@ -58,10 +54,8 @@ obj-$(CONFIG_SND_SOC_SAMSUNG_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o  obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8580) += snd-soc-smdk-wm8580.o  obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994) += snd-soc-smdk-wm8994.o  obj-$(CONFIG_SND_SOC_SNOW) += snd-soc-snow.o -obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o  obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o  obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o -obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o  obj-$(CONFIG_SND_SOC_SMDK_WM8994_PCM) += snd-soc-smdk-wm8994pcm.o  obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o  obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o @@ -69,3 +63,4 @@ obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o  obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o  obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o  obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o +obj-$(CONFIG_SND_SOC_SAMSUNG_TM2_WM5110) += snd-soc-tm2-wm5110.o diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c deleted file mode 100644 index cbc0023c2bc8..000000000000 --- a/sound/soc/samsung/ac97.c +++ /dev/null @@ -1,437 +0,0 @@ -/* sound/soc/samsung/ac97.c - * - * ALSA SoC Audio Layer - S3C AC97 Controller driver - * 	Evolved from s3c2443-ac97.c - * - * Copyright (c) 2010 Samsung Electronics Co. Ltd - *	Author: Jaswinder Singh <jassisinghbrar@gmail.com> - * 	Credits: Graeme Gregory, Sean Choi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/io.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/module.h> - -#include <sound/soc.h> - -#include "regs-ac97.h" -#include <linux/platform_data/asoc-s3c.h> - -#include "dma.h" - -#define AC_CMD_ADDR(x) (x << 16) -#define AC_CMD_DATA(x) (x & 0xffff) - -#define S3C_AC97_DAI_PCM 0 -#define S3C_AC97_DAI_MIC 1 - -struct s3c_ac97_info { -	struct clk         *ac97_clk; -	void __iomem	   *regs; -	struct mutex       lock; -	struct completion  done; -}; -static struct s3c_ac97_info s3c_ac97; - -static struct snd_dmaengine_dai_dma_data s3c_ac97_pcm_out = { -	.addr_width	= 4, -}; - -static struct snd_dmaengine_dai_dma_data s3c_ac97_pcm_in = { -	.addr_width	= 4, -}; - -static struct snd_dmaengine_dai_dma_data s3c_ac97_mic_in = { -	.addr_width	= 4, -}; - -static void s3c_ac97_activate(struct snd_ac97 *ac97) -{ -	u32 ac_glbctrl, stat; - -	stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7; -	if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE) -		return; /* Return if already active */ - -	reinit_completion(&s3c_ac97.done); - -	ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); -	ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON; -	writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); -	msleep(1); - -	ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE; -	writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); -	msleep(1); - -	ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); -	ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; -	writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - -	if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) -		pr_err("AC97: Unable to activate!\n"); -} - -static unsigned short s3c_ac97_read(struct snd_ac97 *ac97, -	unsigned short reg) -{ -	u32 ac_glbctrl, ac_codec_cmd; -	u32 stat, addr, data; - -	mutex_lock(&s3c_ac97.lock); - -	s3c_ac97_activate(ac97); - -	reinit_completion(&s3c_ac97.done); - -	ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); -	ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg); -	writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); - -	udelay(50); - -	ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); -	ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; -	writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - -	if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) -		pr_err("AC97: Unable to read!\n"); - -	stat = readl(s3c_ac97.regs + S3C_AC97_STAT); -	addr = (stat >> 16) & 0x7f; -	data = (stat & 0xffff); - -	if (addr != reg) -		pr_err("ac97: req addr = %02x, rep addr = %02x\n", -			reg, addr); - -	mutex_unlock(&s3c_ac97.lock); - -	return (unsigned short)data; -} - -static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg, -	unsigned short val) -{ -	u32 ac_glbctrl, ac_codec_cmd; - -	mutex_lock(&s3c_ac97.lock); - -	s3c_ac97_activate(ac97); - -	reinit_completion(&s3c_ac97.done); - -	ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); -	ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val); -	writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); - -	udelay(50); - -	ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); -	ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; -	writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - -	if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) -		pr_err("AC97: Unable to write!\n"); - -	ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); -	ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ; -	writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); - -	mutex_unlock(&s3c_ac97.lock); -} - -static void s3c_ac97_cold_reset(struct snd_ac97 *ac97) -{ -	pr_debug("AC97: Cold reset\n"); -	writel(S3C_AC97_GLBCTRL_COLDRESET, -			s3c_ac97.regs + S3C_AC97_GLBCTRL); -	msleep(1); - -	writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL); -	msleep(1); -} - -static void s3c_ac97_warm_reset(struct snd_ac97 *ac97) -{ -	u32 stat; - -	stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7; -	if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE) -		return; /* Return if already active */ - -	pr_debug("AC97: Warm reset\n"); - -	writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL); -	msleep(1); - -	writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL); -	msleep(1); - -	s3c_ac97_activate(ac97); -} - -static irqreturn_t s3c_ac97_irq(int irq, void *dev_id) -{ -	u32 ac_glbctrl, ac_glbstat; - -	ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT); - -	if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) { - -		ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); -		ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE; -		writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - -		complete(&s3c_ac97.done); -	} - -	ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); -	ac_glbctrl |= (1<<30); /* Clear interrupt */ -	writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - -	return IRQ_HANDLED; -} - -static struct snd_ac97_bus_ops s3c_ac97_ops = { -	.read       = s3c_ac97_read, -	.write      = s3c_ac97_write, -	.warm_reset = s3c_ac97_warm_reset, -	.reset      = s3c_ac97_cold_reset, -}; - -static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, -				struct snd_soc_dai *dai) -{ -	u32 ac_glbctrl; - -	ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); -	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -		ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK; -	else -		ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK; - -	switch (cmd) { -	case SNDRV_PCM_TRIGGER_START: -	case SNDRV_PCM_TRIGGER_RESUME: -	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -			ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA; -		else -			ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA; -		break; - -	case SNDRV_PCM_TRIGGER_STOP: -	case SNDRV_PCM_TRIGGER_SUSPEND: -	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -		break; -	} - -	writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - -	return 0; -} - -static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, -				    int cmd, struct snd_soc_dai *dai) -{ -	u32 ac_glbctrl; - -	ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); -	ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK; - -	switch (cmd) { -	case SNDRV_PCM_TRIGGER_START: -	case SNDRV_PCM_TRIGGER_RESUME: -	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -		ac_glbctrl |= S3C_AC97_GLBCTRL_MICINTM_DMA; -		break; - -	case SNDRV_PCM_TRIGGER_STOP: -	case SNDRV_PCM_TRIGGER_SUSPEND: -	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -		break; -	} - -	writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - -	return 0; -} - -static const struct snd_soc_dai_ops s3c_ac97_dai_ops = { -	.trigger	= s3c_ac97_trigger, -}; - -static const struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = { -	.trigger	= s3c_ac97_mic_trigger, -}; - -static int s3c_ac97_dai_probe(struct snd_soc_dai *dai) -{ -	snd_soc_dai_init_dma_data(dai, &s3c_ac97_pcm_out, &s3c_ac97_pcm_in); - -	return 0; -} - -static int s3c_ac97_mic_dai_probe(struct snd_soc_dai *dai) -{ -	snd_soc_dai_init_dma_data(dai, NULL, &s3c_ac97_mic_in); - -	return 0; -} - -static struct snd_soc_dai_driver s3c_ac97_dai[] = { -	[S3C_AC97_DAI_PCM] = { -		.name =	"samsung-ac97", -		.bus_control = true, -		.playback = { -			.stream_name = "AC97 Playback", -			.channels_min = 2, -			.channels_max = 2, -			.rates = SNDRV_PCM_RATE_8000_48000, -			.formats = SNDRV_PCM_FMTBIT_S16_LE,}, -		.capture = { -			.stream_name = "AC97 Capture", -			.channels_min = 2, -			.channels_max = 2, -			.rates = SNDRV_PCM_RATE_8000_48000, -			.formats = SNDRV_PCM_FMTBIT_S16_LE,}, -		.probe = s3c_ac97_dai_probe, -		.ops = &s3c_ac97_dai_ops, -	}, -	[S3C_AC97_DAI_MIC] = { -		.name = "samsung-ac97-mic", -		.bus_control = true, -		.capture = { -			.stream_name = "AC97 Mic Capture", -			.channels_min = 1, -			.channels_max = 1, -			.rates = SNDRV_PCM_RATE_8000_48000, -			.formats = SNDRV_PCM_FMTBIT_S16_LE,}, -		.probe = s3c_ac97_mic_dai_probe, -		.ops = &s3c_ac97_mic_dai_ops, -	}, -}; - -static const struct snd_soc_component_driver s3c_ac97_component = { -	.name		= "s3c-ac97", -}; - -static int s3c_ac97_probe(struct platform_device *pdev) -{ -	struct resource *mem_res, *irq_res; -	struct s3c_audio_pdata *ac97_pdata; -	int ret; - -	ac97_pdata = pdev->dev.platform_data; -	if (!ac97_pdata || !ac97_pdata->cfg_gpio) { -		dev_err(&pdev->dev, "cfg_gpio callback not provided!\n"); -		return -EINVAL; -	} - -	/* Check for availability of necessary resource */ -	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -	if (!irq_res) { -		dev_err(&pdev->dev, "AC97 IRQ not provided!\n"); -		return -ENXIO; -	} - -	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	s3c_ac97.regs = devm_ioremap_resource(&pdev->dev, mem_res); -	if (IS_ERR(s3c_ac97.regs)) -		return PTR_ERR(s3c_ac97.regs); - -	s3c_ac97_pcm_out.filter_data = ac97_pdata->dma_playback; -	s3c_ac97_pcm_out.addr = mem_res->start + S3C_AC97_PCM_DATA; -	s3c_ac97_pcm_in.filter_data = ac97_pdata->dma_capture; -	s3c_ac97_pcm_in.addr = mem_res->start + S3C_AC97_PCM_DATA; -	s3c_ac97_mic_in.filter_data = ac97_pdata->dma_capture_mic; -	s3c_ac97_mic_in.addr = mem_res->start + S3C_AC97_MIC_DATA; - -	init_completion(&s3c_ac97.done); -	mutex_init(&s3c_ac97.lock); - -	s3c_ac97.ac97_clk = devm_clk_get(&pdev->dev, "ac97"); -	if (IS_ERR(s3c_ac97.ac97_clk)) { -		dev_err(&pdev->dev, "ac97 failed to get ac97_clock\n"); -		ret = -ENODEV; -		goto err2; -	} -	clk_prepare_enable(s3c_ac97.ac97_clk); - -	if (ac97_pdata->cfg_gpio(pdev)) { -		dev_err(&pdev->dev, "Unable to configure gpio\n"); -		ret = -EINVAL; -		goto err3; -	} - -	ret = request_irq(irq_res->start, s3c_ac97_irq, -					0, "AC97", NULL); -	if (ret < 0) { -		dev_err(&pdev->dev, "ac97: interrupt request failed.\n"); -		goto err4; -	} - -	ret = snd_soc_set_ac97_ops(&s3c_ac97_ops); -	if (ret != 0) { -		dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret); -		goto err4; -	} - -	ret = samsung_asoc_dma_platform_register(&pdev->dev, -						 ac97_pdata->dma_filter, -						 NULL, NULL); -	if (ret) { -		dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); -		goto err5; -	} - -	ret = devm_snd_soc_register_component(&pdev->dev, &s3c_ac97_component, -					 s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai)); -	if (ret) -		goto err5; - -	return 0; -err5: -	free_irq(irq_res->start, NULL); -err4: -err3: -	clk_disable_unprepare(s3c_ac97.ac97_clk); -err2: -	snd_soc_set_ac97_ops(NULL); -	return ret; -} - -static int s3c_ac97_remove(struct platform_device *pdev) -{ -	struct resource *irq_res; - -	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -	if (irq_res) -		free_irq(irq_res->start, NULL); - -	clk_disable_unprepare(s3c_ac97.ac97_clk); -	snd_soc_set_ac97_ops(NULL); - -	return 0; -} - -static struct platform_driver s3c_ac97_driver = { -	.probe  = s3c_ac97_probe, -	.remove = s3c_ac97_remove, -	.driver = { -		.name = "samsung-ac97", -	}, -}; - -module_platform_driver(s3c_ac97_driver); - -MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>"); -MODULE_DESCRIPTION("AC97 driver for the Samsung SoC"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:samsung-ac97"); diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c index 9104c98deeb7..cda656e4afc6 100644 --- a/sound/soc/samsung/dmaengine.c +++ b/sound/soc/samsung/dmaengine.c @@ -37,12 +37,8 @@ int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter,  	pcm_conf->prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config;  	pcm_conf->compat_filter_fn = filter; -	if (dev->of_node) { -		pcm_conf->chan_names[SNDRV_PCM_STREAM_PLAYBACK] = tx; -		pcm_conf->chan_names[SNDRV_PCM_STREAM_CAPTURE] = rx; -	} else { -		flags |= SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME; -	} +	pcm_conf->chan_names[SNDRV_PCM_STREAM_PLAYBACK] = tx; +	pcm_conf->chan_names[SNDRV_PCM_STREAM_CAPTURE] = rx;  	return devm_snd_dmaengine_pcm_register(dev, pcm_conf, flags);  } diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 7825bff45ae3..e00974bc5616 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1029,12 +1029,13 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)  static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)  {  	struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai); +	unsigned long flags;  	if (!is_secondary(i2s)) {  		if (i2s->quirks & QUIRK_NEED_RSTCLR) { -			spin_lock(i2s->lock); +			spin_lock_irqsave(i2s->lock, flags);  			writel(0, i2s->addr + I2SCON); -			spin_unlock(i2s->lock); +			spin_unlock_irqrestore(i2s->lock, flags);  		}  	} @@ -1304,8 +1305,6 @@ static int samsung_i2s_probe(struct platform_device *pdev)  	}  	pri_dai->dma_playback.addr = regs_base + I2STXD;  	pri_dai->dma_capture.addr = regs_base + I2SRXD; -	pri_dai->dma_playback.chan_name = "tx"; -	pri_dai->dma_capture.chan_name = "rx";  	pri_dai->dma_playback.addr_width = 4;  	pri_dai->dma_capture.addr_width = 4;  	pri_dai->quirks = quirks; @@ -1330,7 +1329,6 @@ static int samsung_i2s_probe(struct platform_device *pdev)  		sec_dai->lock = &pri_dai->spinlock;  		sec_dai->variant_regs = pri_dai->variant_regs;  		sec_dai->dma_playback.addr = regs_base + I2STXDS; -		sec_dai->dma_playback.chan_name = "tx-sec";  		if (!np) {  			sec_dai->dma_playback.filter_data = i2s_pdata->dma_play_sec; diff --git a/sound/soc/samsung/ln2440sbc_alc650.c b/sound/soc/samsung/ln2440sbc_alc650.c deleted file mode 100644 index 9342fc270c2b..000000000000 --- a/sound/soc/samsung/ln2440sbc_alc650.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SoC audio for ln2440sbc - * - * Copyright 2007 KonekTel, a.s. - * Author: Ivan Kuten - *         ivan.kuten@promwad.com - * - * Heavily based on smdk2443_wm9710.c - * Copyright 2007 Wolfson Microelectronics PLC. - * Author: Graeme Gregory - *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com - * - *  This program is free software; you can redistribute it and/or modify - *  it under the terms of the GNU General Public License version 2 as - *  published by the Free Software Foundation. - * - */ - -#include <linux/module.h> -#include <sound/soc.h> - -static struct snd_soc_card ln2440sbc; - -static struct snd_soc_dai_link ln2440sbc_dai[] = { -{ -	.name = "AC97", -	.stream_name = "AC97 HiFi", -	.cpu_dai_name = "samsung-ac97", -	.codec_dai_name = "ac97-hifi", -	.codec_name = "ac97-codec", -	.platform_name = "samsung-ac97", -}, -}; - -static struct snd_soc_card ln2440sbc = { -	.name = "LN2440SBC", -	.owner = THIS_MODULE, -	.dai_link = ln2440sbc_dai, -	.num_links = ARRAY_SIZE(ln2440sbc_dai), -}; - -static struct platform_device *ln2440sbc_snd_ac97_device; - -static int __init ln2440sbc_init(void) -{ -	int ret; - -	ln2440sbc_snd_ac97_device = platform_device_alloc("soc-audio", -1); -	if (!ln2440sbc_snd_ac97_device) -		return -ENOMEM; - -	platform_set_drvdata(ln2440sbc_snd_ac97_device, &ln2440sbc); -	ret = platform_device_add(ln2440sbc_snd_ac97_device); - -	if (ret) -		platform_device_put(ln2440sbc_snd_ac97_device); - -	return ret; -} - -static void __exit ln2440sbc_exit(void) -{ -	platform_device_unregister(ln2440sbc_snd_ac97_device); -} - -module_init(ln2440sbc_init); -module_exit(ln2440sbc_exit); - -/* Module information */ -MODULE_AUTHOR("Ivan Kuten"); -MODULE_DESCRIPTION("ALSA SoC ALC650 LN2440SBC"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index c484985812ed..d50a6377c23d 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -499,13 +499,6 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)  	pcm_pdata = pdev->dev.platform_data; -	/* Check for availability of necessary resource */ -	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!mem_res) { -		dev_err(&pdev->dev, "Unable to get register resource\n"); -		return -ENXIO; -	} -  	if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) {  		dev_err(&pdev->dev, "Unable to configure gpio\n");  		return -EINVAL; @@ -519,36 +512,26 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)  	/* Default is 128fs */  	pcm->sclk_per_fs = 128; +	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	pcm->regs = devm_ioremap_resource(&pdev->dev, mem_res); +	if (IS_ERR(pcm->regs)) +		return PTR_ERR(pcm->regs); +  	pcm->cclk = devm_clk_get(&pdev->dev, "audio-bus");  	if (IS_ERR(pcm->cclk)) { -		dev_err(&pdev->dev, "failed to get audio-bus\n"); -		ret = PTR_ERR(pcm->cclk); -		goto err1; +		dev_err(&pdev->dev, "failed to get audio-bus clock\n"); +		return PTR_ERR(pcm->cclk);  	}  	clk_prepare_enable(pcm->cclk);  	/* record our pcm structure for later use in the callbacks */  	dev_set_drvdata(&pdev->dev, pcm); -	if (!request_mem_region(mem_res->start, -				resource_size(mem_res), "samsung-pcm")) { -		dev_err(&pdev->dev, "Unable to request register region\n"); -		ret = -EBUSY; -		goto err2; -	} - -	pcm->regs = ioremap(mem_res->start, 0x100); -	if (pcm->regs == NULL) { -		dev_err(&pdev->dev, "cannot ioremap registers\n"); -		ret = -ENXIO; -		goto err3; -	} -  	pcm->pclk = devm_clk_get(&pdev->dev, "pcm");  	if (IS_ERR(pcm->pclk)) { -		dev_err(&pdev->dev, "failed to get pcm_clock\n"); -		ret = -ENOENT; -		goto err4; +		dev_err(&pdev->dev, "failed to get pcm clock\n"); +		ret = PTR_ERR(pcm->pclk); +		goto err_dis_cclk;  	}  	clk_prepare_enable(pcm->pclk); @@ -569,7 +552,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)  						 NULL, NULL);  	if (ret) {  		dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); -		goto err5; +		goto err_dis_pclk;  	}  	pm_runtime_enable(&pdev->dev); @@ -578,36 +561,25 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)  					 &s3c_pcm_dai[pdev->id], 1);  	if (ret != 0) {  		dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret); -		goto err6; +		goto err_dis_pm;  	}  	return 0; -err6: + +err_dis_pm:  	pm_runtime_disable(&pdev->dev); -err5: +err_dis_pclk:  	clk_disable_unprepare(pcm->pclk); -err4: -	iounmap(pcm->regs); -err3: -	release_mem_region(mem_res->start, resource_size(mem_res)); -err2: +err_dis_cclk:  	clk_disable_unprepare(pcm->cclk); -err1:  	return ret;  }  static int s3c_pcm_dev_remove(struct platform_device *pdev)  {  	struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id]; -	struct resource *mem_res;  	pm_runtime_disable(&pdev->dev); - -	iounmap(pcm->regs); - -	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	release_mem_region(mem_res->start, resource_size(mem_res)); -  	clk_disable_unprepare(pcm->cclk);  	clk_disable_unprepare(pcm->pclk); diff --git a/sound/soc/samsung/regs-ac97.h b/sound/soc/samsung/regs-ac97.h deleted file mode 100644 index a71be45bbffc..000000000000 --- a/sound/soc/samsung/regs-ac97.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2006 Simtec Electronics <linux@simtec.co.uk> - *		http://www.simtec.co.uk/products/SWLINUX/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * S3C2440 AC97 Controller -*/ - -#ifndef __SAMSUNG_REGS_AC97_H__ -#define __SAMSUNG_REGS_AC97_H__ - -#define S3C_AC97_GLBCTRL				(0x00) - -#define S3C_AC97_GLBCTRL_CODECREADYIE			(1<<22) -#define S3C_AC97_GLBCTRL_PCMOUTURIE			(1<<21) -#define S3C_AC97_GLBCTRL_PCMINORIE			(1<<20) -#define S3C_AC97_GLBCTRL_MICINORIE			(1<<19) -#define S3C_AC97_GLBCTRL_PCMOUTTIE			(1<<18) -#define S3C_AC97_GLBCTRL_PCMINTIE			(1<<17) -#define S3C_AC97_GLBCTRL_MICINTIE			(1<<16) -#define S3C_AC97_GLBCTRL_PCMOUTTM_OFF			(0<<12) -#define S3C_AC97_GLBCTRL_PCMOUTTM_PIO			(1<<12) -#define S3C_AC97_GLBCTRL_PCMOUTTM_DMA			(2<<12) -#define S3C_AC97_GLBCTRL_PCMOUTTM_MASK			(3<<12) -#define S3C_AC97_GLBCTRL_PCMINTM_OFF			(0<<10) -#define S3C_AC97_GLBCTRL_PCMINTM_PIO			(1<<10) -#define S3C_AC97_GLBCTRL_PCMINTM_DMA			(2<<10) -#define S3C_AC97_GLBCTRL_PCMINTM_MASK			(3<<10) -#define S3C_AC97_GLBCTRL_MICINTM_OFF			(0<<8) -#define S3C_AC97_GLBCTRL_MICINTM_PIO			(1<<8) -#define S3C_AC97_GLBCTRL_MICINTM_DMA			(2<<8) -#define S3C_AC97_GLBCTRL_MICINTM_MASK			(3<<8) -#define S3C_AC97_GLBCTRL_TRANSFERDATAENABLE		(1<<3) -#define S3C_AC97_GLBCTRL_ACLINKON			(1<<2) -#define S3C_AC97_GLBCTRL_WARMRESET			(1<<1) -#define S3C_AC97_GLBCTRL_COLDRESET			(1<<0) - -#define S3C_AC97_GLBSTAT				(0x04) - -#define S3C_AC97_GLBSTAT_CODECREADY			(1<<22) -#define S3C_AC97_GLBSTAT_PCMOUTUR			(1<<21) -#define S3C_AC97_GLBSTAT_PCMINORI			(1<<20) -#define S3C_AC97_GLBSTAT_MICINORI			(1<<19) -#define S3C_AC97_GLBSTAT_PCMOUTTI			(1<<18) -#define S3C_AC97_GLBSTAT_PCMINTI			(1<<17) -#define S3C_AC97_GLBSTAT_MICINTI			(1<<16) -#define S3C_AC97_GLBSTAT_MAINSTATE_IDLE			(0<<0) -#define S3C_AC97_GLBSTAT_MAINSTATE_INIT			(1<<0) -#define S3C_AC97_GLBSTAT_MAINSTATE_READY		(2<<0) -#define S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE		(3<<0) -#define S3C_AC97_GLBSTAT_MAINSTATE_LP			(4<<0) -#define S3C_AC97_GLBSTAT_MAINSTATE_WARM			(5<<0) - -#define S3C_AC97_CODEC_CMD				(0x08) - -#define S3C_AC97_CODEC_CMD_READ				(1<<23) - -#define S3C_AC97_STAT					(0x0c) -#define S3C_AC97_PCM_ADDR				(0x10) -#define S3C_AC97_PCM_DATA				(0x18) -#define S3C_AC97_MIC_DATA				(0x1C) - -#endif /* __SAMSUNG_REGS_AC97_H__ */ diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 0a4718207e6e..6d0b8897fa6c 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -35,12 +35,10 @@  #include <linux/platform_data/asoc-s3c.h>  static struct snd_dmaengine_dai_dma_data s3c2412_i2s_pcm_stereo_out = { -	.chan_name	= "tx",  	.addr_width	= 4,  };  static struct snd_dmaengine_dai_dma_data s3c2412_i2s_pcm_stereo_in = { -	.chan_name	= "rx",  	.addr_width	= 4,  }; diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 9052f6a7073e..07f5091b33e8 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -30,15 +30,11 @@  #include "dma.h"  #include "s3c24xx-i2s.h" -#include <linux/platform_data/asoc-s3c.h> -  static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_out = { -	.chan_name	= "tx",  	.addr_width	= 2,  };  static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_in = { -	.chan_name	= "rx",  	.addr_width	= 2,  }; @@ -58,8 +54,6 @@ static void s3c24xx_snd_txctrl(int on)  	u32 iiscon;  	u32 iismod; -	pr_debug("Entered %s\n", __func__); -  	iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);  	iiscon  = readl(s3c24xx_i2s.regs + S3C2410_IISCON);  	iismod  = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); @@ -103,8 +97,6 @@ static void s3c24xx_snd_rxctrl(int on)  	u32 iiscon;  	u32 iismod; -	pr_debug("Entered %s\n", __func__); -  	iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);  	iiscon  = readl(s3c24xx_i2s.regs + S3C2410_IISCON);  	iismod  = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); @@ -151,8 +143,6 @@ static int s3c24xx_snd_lrsync(void)  	u32 iiscon;  	int timeout = 50; /* 5ms */ -	pr_debug("Entered %s\n", __func__); -  	while (1) {  		iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);  		if (iiscon & S3C2410_IISCON_LRINDEX) @@ -171,8 +161,6 @@ static int s3c24xx_snd_lrsync(void)   */  static inline int s3c24xx_snd_is_clkmaster(void)  { -	pr_debug("Entered %s\n", __func__); -  	return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1;  } @@ -184,8 +172,6 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,  {  	u32 iismod; -	pr_debug("Entered %s\n", __func__); -  	iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);  	pr_debug("hw_params r: IISMOD: %x \n", iismod); @@ -213,6 +199,7 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,  	writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);  	pr_debug("hw_params w: IISMOD: %x \n", iismod); +  	return 0;  } @@ -223,8 +210,6 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,  	struct snd_dmaengine_dai_dma_data *dma_data;  	u32 iismod; -	pr_debug("Entered %s\n", __func__); -  	dma_data = snd_soc_dai_get_dma_data(dai, substream);  	/* Working copies of register */ @@ -246,6 +231,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,  	writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);  	pr_debug("hw_params w: IISMOD: %x\n", iismod); +  	return 0;  } @@ -254,8 +240,6 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,  {  	int ret = 0; -	pr_debug("Entered %s\n", __func__); -  	switch (cmd) {  	case SNDRV_PCM_TRIGGER_START:  	case SNDRV_PCM_TRIGGER_RESUME: @@ -297,8 +281,6 @@ static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,  {  	u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); -	pr_debug("Entered %s\n", __func__); -  	iismod &= ~S3C2440_IISMOD_MPLL;  	switch (clk_id) { @@ -323,8 +305,6 @@ static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,  {  	u32 reg; -	pr_debug("Entered %s\n", __func__); -  	switch (div_id) {  	case S3C24XX_DIV_BCLK:  		reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK; @@ -358,8 +338,6 @@ EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);  static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)  { -	pr_debug("Entered %s\n", __func__); -  	snd_soc_dai_init_dma_data(dai, &s3c24xx_i2s_pcm_stereo_out,  					&s3c24xx_i2s_pcm_stereo_in); @@ -385,8 +363,6 @@ static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)  #ifdef CONFIG_PM  static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)  { -	pr_debug("Entered %s\n", __func__); -  	s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);  	s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);  	s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); @@ -399,7 +375,6 @@ static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)  static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)  { -	pr_debug("Entered %s\n", __func__);  	clk_prepare_enable(s3c24xx_i2s.iis_clk);  	writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); @@ -414,7 +389,6 @@ static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)  #define s3c24xx_i2s_resume NULL  #endif -  #define S3C24XX_I2S_RATES \  	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \  	SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ @@ -451,41 +425,28 @@ static const struct snd_soc_component_driver s3c24xx_i2s_component = {  static int s3c24xx_iis_dev_probe(struct platform_device *pdev)  { -	int ret = 0;  	struct resource *res; -	struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev); - -	if (!pdata) { -		dev_err(&pdev->dev, "missing platform data"); -		return -ENXIO; -	} +	int ret;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) { -		dev_err(&pdev->dev, "Can't get IO resource.\n"); -		return -ENOENT; -	}  	s3c24xx_i2s.regs = devm_ioremap_resource(&pdev->dev, res);  	if (IS_ERR(s3c24xx_i2s.regs))  		return PTR_ERR(s3c24xx_i2s.regs);  	s3c24xx_i2s_pcm_stereo_out.addr = res->start + S3C2410_IISFIFO; -	s3c24xx_i2s_pcm_stereo_out.filter_data = pdata->dma_playback;  	s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO; -	s3c24xx_i2s_pcm_stereo_in.filter_data = pdata->dma_capture; -	ret = samsung_asoc_dma_platform_register(&pdev->dev, -						 pdata->dma_filter, +	ret = samsung_asoc_dma_platform_register(&pdev->dev, NULL,  						 NULL, NULL);  	if (ret) { -		pr_err("failed to register the dma: %d\n", ret); +		dev_err(&pdev->dev, "Failed to register the DMA: %d\n", ret);  		return ret;  	}  	ret = devm_snd_soc_register_component(&pdev->dev,  			&s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1);  	if (ret) -		pr_err("failed to register the dai\n"); +		dev_err(&pdev->dev, "Failed to register the DAI\n");  	return ret;  } diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c index 7853fbe6ccc9..81a78940967c 100644 --- a/sound/soc/samsung/s3c24xx_uda134x.c +++ b/sound/soc/samsung/s3c24xx_uda134x.c @@ -19,9 +19,15 @@  #include <sound/s3c24xx_uda134x.h>  #include "regs-iis.h" -  #include "s3c24xx-i2s.h" +struct s3c24xx_uda134x { +	struct clk *xtal; +	struct clk *pclk; +	struct mutex clk_lock; +	int clk_users; +}; +  /* #define ENFORCE_RATES 1 */  /*    Unfortunately the S3C24XX in master mode has a limited capacity of @@ -36,15 +42,6 @@    possible an error will be returned.  */ -static struct clk *xtal; -static struct clk *pclk; -/* this is need because we don't have a place where to keep the - * pointers to the clocks in each substream. We get the clocks only - * when we are actually using them so we don't block stuff like - * frequency change or oscillator power-off */ -static int clk_users; -static DEFINE_MUTEX(clk_lock); -  static unsigned int rates[33 * 2];  #ifdef ENFORCE_RATES  static struct snd_pcm_hw_constraint_list hw_constraints_rates = { @@ -57,26 +54,24 @@ static struct snd_pcm_hw_constraint_list hw_constraints_rates = {  static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)  {  	struct snd_soc_pcm_runtime *rtd = substream->private_data; +	struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);  	struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -#ifdef ENFORCE_RATES -	struct snd_pcm_runtime *runtime = substream->runtime; -#endif  	int ret = 0; -	mutex_lock(&clk_lock); +	mutex_lock(&priv->clk_lock); -	if (clk_users == 0) { -		xtal = clk_get(rtd->dev, "xtal"); -		if (IS_ERR(xtal)) { +	if (priv->clk_users == 0) { +		priv->xtal = clk_get(rtd->dev, "xtal"); +		if (IS_ERR(priv->xtal)) {  			dev_err(rtd->dev, "%s cannot get xtal\n", __func__); -			ret = PTR_ERR(xtal); +			ret = PTR_ERR(priv->xtal);  		} else { -			pclk = clk_get(cpu_dai->dev, "iis"); -			if (IS_ERR(pclk)) { +			priv->pclk = clk_get(cpu_dai->dev, "iis"); +			if (IS_ERR(priv->pclk)) {  				dev_err(rtd->dev, "%s cannot get pclk\n",  					__func__); -				clk_put(xtal); -				ret = PTR_ERR(pclk); +				clk_put(priv->xtal); +				ret = PTR_ERR(priv->pclk);  			}  		}  		if (!ret) { @@ -85,18 +80,19 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)  			for (i = 0; i < 2; i++) {  				int fs = i ? 256 : 384; -				rates[i*33] = clk_get_rate(xtal) / fs; +				rates[i*33] = clk_get_rate(priv->xtal) / fs;  				for (j = 1; j < 33; j++) -					rates[i*33 + j] = clk_get_rate(pclk) / +					rates[i*33 + j] = clk_get_rate(priv->pclk) /  						(j * fs);  			}  		}  	} -	clk_users += 1; -	mutex_unlock(&clk_lock); +	priv->clk_users += 1; +	mutex_unlock(&priv->clk_lock); +  	if (!ret) {  #ifdef ENFORCE_RATES -		ret = snd_pcm_hw_constraint_list(runtime, 0, +		ret = snd_pcm_hw_constraint_list(substream->runtime, 0,  						 SNDRV_PCM_HW_PARAM_RATE,  						 &hw_constraints_rates);  		if (ret < 0) @@ -109,15 +105,18 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)  static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)  { -	mutex_lock(&clk_lock); -	clk_users -= 1; -	if (clk_users == 0) { -		clk_put(xtal); -		xtal = NULL; -		clk_put(pclk); -		pclk = NULL; +	struct snd_soc_pcm_runtime *rtd = substream->private_data; +	struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card); + +	mutex_lock(&priv->clk_lock); +	priv->clk_users -= 1; +	if (priv->clk_users == 0) { +		clk_put(priv->xtal); +		priv->xtal = NULL; +		clk_put(priv->pclk); +		priv->pclk = NULL;  	} -	mutex_unlock(&clk_lock); +	mutex_unlock(&priv->clk_lock);  }  static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream, @@ -228,10 +227,18 @@ static struct snd_soc_card snd_soc_s3c24xx_uda134x = {  static int s3c24xx_uda134x_probe(struct platform_device *pdev)  {  	struct snd_soc_card *card = &snd_soc_s3c24xx_uda134x; +	struct s3c24xx_uda134x *priv;  	int ret; -	platform_set_drvdata(pdev, card); +	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	mutex_init(&priv->clk_lock); +  	card->dev = &pdev->dev; +	platform_set_drvdata(pdev, card); +	snd_soc_card_set_drvdata(card, priv);  	ret = devm_snd_soc_register_card(&pdev->dev, card);  	if (ret) diff --git a/sound/soc/samsung/smdk2443_wm9710.c b/sound/soc/samsung/smdk2443_wm9710.c deleted file mode 100644 index c390aad68cfb..000000000000 --- a/sound/soc/samsung/smdk2443_wm9710.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * smdk2443_wm9710.c  --  SoC audio for smdk2443 - * - * Copyright 2007 Wolfson Microelectronics PLC. - * Author: Graeme Gregory - *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com - * - *  This program is free software; you can redistribute  it and/or modify it - *  under  the terms of  the GNU General  Public License as published by the - *  Free Software Foundation;  either version 2 of the  License, or (at your - *  option) any later version. - * - */ - -#include <linux/module.h> -#include <sound/soc.h> - -static struct snd_soc_card smdk2443; - -static struct snd_soc_dai_link smdk2443_dai[] = { -{ -	.name = "AC97", -	.stream_name = "AC97 HiFi", -	.cpu_dai_name = "samsung-ac97", -	.codec_dai_name = "ac97-hifi", -	.codec_name = "ac97-codec", -	.platform_name = "samsung-ac97", -}, -}; - -static struct snd_soc_card smdk2443 = { -	.name = "SMDK2443", -	.owner = THIS_MODULE, -	.dai_link = smdk2443_dai, -	.num_links = ARRAY_SIZE(smdk2443_dai), -}; - -static struct platform_device *smdk2443_snd_ac97_device; - -static int __init smdk2443_init(void) -{ -	int ret; - -	smdk2443_snd_ac97_device = platform_device_alloc("soc-audio", -1); -	if (!smdk2443_snd_ac97_device) -		return -ENOMEM; - -	platform_set_drvdata(smdk2443_snd_ac97_device, &smdk2443); -	ret = platform_device_add(smdk2443_snd_ac97_device); - -	if (ret) -		platform_device_put(smdk2443_snd_ac97_device); - -	return ret; -} - -static void __exit smdk2443_exit(void) -{ -	platform_device_unregister(smdk2443_snd_ac97_device); -} - -module_init(smdk2443_init); -module_exit(smdk2443_exit); - -/* Module information */ -MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com"); -MODULE_DESCRIPTION("ALSA SoC WM9710 SMDK2443"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c index 548bfd993788..de724ce7b955 100644 --- a/sound/soc/samsung/smdk_wm8580.c +++ b/sound/soc/samsung/smdk_wm8580.c @@ -14,8 +14,6 @@  #include <sound/soc.h>  #include <sound/pcm_params.h> -#include <asm/mach-types.h> -  #include "../codecs/wm8580.h"  #include "i2s.h" @@ -147,7 +145,6 @@ static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)  enum {  	PRI_PLAYBACK = 0,  	PRI_CAPTURE, -	SEC_PLAYBACK,  };  #define SMDK_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \ @@ -157,7 +154,7 @@ static struct snd_soc_dai_link smdk_dai[] = {  	[PRI_PLAYBACK] = { /* Primary Playback i/f */  		.name = "WM8580 PAIF RX",  		.stream_name = "Playback", -		.cpu_dai_name = "samsung-i2s.0", +		.cpu_dai_name = "samsung-i2s.2",  		.codec_dai_name = "wm8580-hifi-playback",  		.platform_name = "samsung-i2s.0",  		.codec_name = "wm8580.0-001b", @@ -167,7 +164,7 @@ static struct snd_soc_dai_link smdk_dai[] = {  	[PRI_CAPTURE] = { /* Primary Capture i/f */  		.name = "WM8580 PAIF TX",  		.stream_name = "Capture", -		.cpu_dai_name = "samsung-i2s.0", +		.cpu_dai_name = "samsung-i2s.2",  		.codec_dai_name = "wm8580-hifi-capture",  		.platform_name = "samsung-i2s.0",  		.codec_name = "wm8580.0-001b", @@ -175,23 +172,13 @@ static struct snd_soc_dai_link smdk_dai[] = {  		.init = smdk_wm8580_init_paiftx,  		.ops = &smdk_ops,  	}, -	[SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */ -		.name = "Sec_FIFO TX", -		.stream_name = "Playback", -		.cpu_dai_name = "samsung-i2s-sec", -		.codec_dai_name = "wm8580-hifi-playback", -		.platform_name = "samsung-i2s-sec", -		.codec_name = "wm8580.0-001b", -		.dai_fmt = SMDK_DAI_FMT, -		.ops = &smdk_ops, -	},  };  static struct snd_soc_card smdk = {  	.name = "SMDK-I2S",  	.owner = THIS_MODULE,  	.dai_link = smdk_dai, -	.num_links = 2, +	.num_links = ARRAY_SIZE(smdk_dai),  	.dapm_widgets = smdk_wm8580_dapm_widgets,  	.num_dapm_widgets = ARRAY_SIZE(smdk_wm8580_dapm_widgets), @@ -204,17 +191,6 @@ static struct platform_device *smdk_snd_device;  static int __init smdk_audio_init(void)  {  	int ret; -	char *str; - -	if (machine_is_smdkc100() -			|| machine_is_smdkv210() || machine_is_smdkc110()) { -		smdk.num_links = 3; -	} else if (machine_is_smdk6410()) { -		str = (char *)smdk_dai[PRI_PLAYBACK].cpu_dai_name; -		str[strlen(str) - 1] = '2'; -		str = (char *)smdk_dai[PRI_CAPTURE].cpu_dai_name; -		str[strlen(str) - 1] = '2'; -	}  	smdk_snd_device = platform_device_alloc("soc-audio", -1);  	if (!smdk_snd_device) diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c deleted file mode 100644 index a6d223310c67..000000000000 --- a/sound/soc/samsung/smdk_wm8580pcm.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - *  sound/soc/samsung/smdk_wm8580pcm.c - * - *  Copyright (c) 2011 Samsung Electronics Co. Ltd - * - *  This program is free software; you can redistribute  it and/or  modify it - *  under  the terms of  the GNU General  Public License as published by the - *  Free Software Foundation;  either version 2 of the  License, or (at your - *  option) any later version. - */ -#include <linux/module.h> -#include <sound/soc.h> -#include <sound/pcm_params.h> -#include <sound/pcm.h> - -#include <asm/mach-types.h> - -#include "../codecs/wm8580.h" -#include "pcm.h" - -/* - * Board Settings: - *  o '1' means 'ON' - *  o '0' means 'OFF' - *  o 'X' means 'Don't care' - * - * SMDK6410 Base B/D: CFG1-0000, CFG2-1111 - * SMDKC110, SMDKV210: CFGB11-100100, CFGB12-0000 - */ - -#define SMDK_WM8580_EXT_OSC 12000000 -#define SMDK_WM8580_EXT_MCLK 4096000 -#define SMDK_WM8580_EXT_VOICE 2048000 - -static unsigned long mclk_freq; -static unsigned long xtal_freq; - -/* - * If MCLK clock directly gets from XTAL, we don't have to use PLL - * to make MCLK, but if XTAL clock source connects with other codec - * pin (like XTI), we should have to set codec's PLL to make MCLK. - * Because Samsung SoC does not support pcmcdclk output like I2S. - */ - -static int smdk_wm8580_pcm_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; -	struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -	int rfs, ret; - -	switch (params_rate(params)) { -	case 8000: -		break; -	default: -		printk(KERN_ERR "%s:%d Sampling Rate %u not supported!\n", -		__func__, __LINE__, params_rate(params)); -		return -EINVAL; -	} - -	rfs = mclk_freq / params_rate(params) / 2; - -	if (mclk_freq == xtal_freq) { -		ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_MCLK, -						mclk_freq, SND_SOC_CLOCK_IN); -		if (ret < 0) -			return ret; - -		ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, -						WM8580_CLKSRC_MCLK); -		if (ret < 0) -			return ret; -	} else { -		ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA, -						mclk_freq, SND_SOC_CLOCK_IN); -		if (ret < 0) -			return ret; - -		ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, -						WM8580_CLKSRC_PLLA); -		if (ret < 0) -			return ret; - -		ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0, -						xtal_freq, mclk_freq); -		if (ret < 0) -			return ret; -	} - -	/* Set PCM source clock on CPU */ -	ret = snd_soc_dai_set_sysclk(cpu_dai, S3C_PCM_CLKSRC_MUX, -					mclk_freq, SND_SOC_CLOCK_IN); -	if (ret < 0) -		return ret; - -	/* Set SCLK_DIV for making bclk */ -	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_PCM_SCLK_PER_FS, rfs); -	if (ret < 0) -		return ret; - -	return 0; -} - -static struct snd_soc_ops smdk_wm8580_pcm_ops = { -	.hw_params = smdk_wm8580_pcm_hw_params, -}; - -#define SMDK_DAI_FMT (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | \ -	SND_SOC_DAIFMT_CBS_CFS) - -static struct snd_soc_dai_link smdk_dai[] = { -	{ -		.name = "WM8580 PAIF PCM RX", -		.stream_name = "Playback", -		.cpu_dai_name = "samsung-pcm.0", -		.codec_dai_name = "wm8580-hifi-playback", -		.platform_name = "samsung-audio", -		.codec_name = "wm8580.0-001b", -		.dai_fmt = SMDK_DAI_FMT, -		.ops = &smdk_wm8580_pcm_ops, -	}, { -		.name = "WM8580 PAIF PCM TX", -		.stream_name = "Capture", -		.cpu_dai_name = "samsung-pcm.0", -		.codec_dai_name = "wm8580-hifi-capture", -		.platform_name = "samsung-pcm.0", -		.codec_name = "wm8580.0-001b", -		.dai_fmt = SMDK_DAI_FMT, -		.ops = &smdk_wm8580_pcm_ops, -	}, -}; - -static struct snd_soc_card smdk_pcm = { -	.name = "SMDK-PCM", -	.owner = THIS_MODULE, -	.dai_link = smdk_dai, -	.num_links = 2, -}; - -/* - * After SMDKC110 Base Board's Rev is '0.1', 12MHz External OSC(X1) - * is absent (or not connected), so we connect EXT_VOICE_CLK(OSC4), - * 2.0484Mhz, directly with MCLK both Codec and SoC. - */ -static int snd_smdk_probe(struct platform_device *pdev) -{ -	int ret = 0; - -	xtal_freq = SMDK_WM8580_EXT_OSC; -	mclk_freq = SMDK_WM8580_EXT_MCLK; - -	if (machine_is_smdkc110() || machine_is_smdkv210()) -		xtal_freq = mclk_freq = SMDK_WM8580_EXT_VOICE; - -	smdk_pcm.dev = &pdev->dev; -	ret = devm_snd_soc_register_card(&pdev->dev, &smdk_pcm); -	if (ret) -		dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); - -	return ret; -} - -static struct platform_driver snd_smdk_driver = { -	.driver = { -		.name = "samsung-smdk-pcm", -	}, -	.probe = snd_smdk_probe, -}; - -module_platform_driver(snd_smdk_driver); - -MODULE_AUTHOR("Sangbeom Kim, <sbkim73@samsung.com>"); -MODULE_DESCRIPTION("ALSA SoC SMDK WM8580 for PCM"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/smdk_wm9713.c b/sound/soc/samsung/smdk_wm9713.c deleted file mode 100644 index 0d20e4ed27aa..000000000000 --- a/sound/soc/samsung/smdk_wm9713.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * smdk_wm9713.c  --  SoC audio for SMDK - * - * Copyright 2010 Samsung Electronics Co. Ltd. - * Author: Jaswinder Singh Brar <jassisinghbrar@gmail.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - */ - -#include <linux/module.h> -#include <sound/soc.h> - -static struct snd_soc_card smdk; - -/* - * Default CFG switch settings to use this driver: - * - *   SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off - *   SMDKC100: Set CFG6 1-3 On, CFG7 1   On - *   SMDKC110: Set CFGB10 1-2 Off, CFGB12 1-3 On - *   SMDKV210: Set CFGB10 1-2 Off, CFGB12 1-3 On - *   SMDKV310: Set CFG2 1-2 Off, CFG4 All On, CFG7 All Off, CFG8 1-On - */ - -/* - Playback (HeadPhone):- -	$ amixer sset 'Headphone' unmute -	$ amixer sset 'Right Headphone Out Mux' 'Headphone' -	$ amixer sset 'Left Headphone Out Mux' 'Headphone' -	$ amixer sset 'Right HP Mixer PCM' unmute -	$ amixer sset 'Left HP Mixer PCM' unmute - - Capture (LineIn):- -	$ amixer sset 'Right Capture Source' 'Line' -	$ amixer sset 'Left Capture Source' 'Line' -*/ - -static struct snd_soc_dai_link smdk_dai = { -	.name = "AC97", -	.stream_name = "AC97 PCM", -	.platform_name = "samsung-ac97", -	.cpu_dai_name = "samsung-ac97", -	.codec_dai_name = "wm9713-hifi", -	.codec_name = "wm9713-codec", -}; - -static struct snd_soc_card smdk = { -	.name = "SMDK WM9713", -	.owner = THIS_MODULE, -	.dai_link = &smdk_dai, -	.num_links = 1, -}; - -static struct platform_device *smdk_snd_wm9713_device; -static struct platform_device *smdk_snd_ac97_device; - -static int __init smdk_init(void) -{ -	int ret; - -	smdk_snd_wm9713_device = platform_device_alloc("wm9713-codec", -1); -	if (!smdk_snd_wm9713_device) -		return -ENOMEM; - -	ret = platform_device_add(smdk_snd_wm9713_device); -	if (ret) -		goto err1; - -	smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1); -	if (!smdk_snd_ac97_device) { -		ret = -ENOMEM; -		goto err2; -	} - -	platform_set_drvdata(smdk_snd_ac97_device, &smdk); - -	ret = platform_device_add(smdk_snd_ac97_device); -	if (ret) -		goto err3; - -	return 0; - -err3: -	platform_device_put(smdk_snd_ac97_device); -err2: -	platform_device_del(smdk_snd_wm9713_device); -err1: -	platform_device_put(smdk_snd_wm9713_device); -	return ret; -} - -static void __exit smdk_exit(void) -{ -	platform_device_unregister(smdk_snd_ac97_device); -	platform_device_unregister(smdk_snd_wm9713_device); -} - -module_init(smdk_init); -module_exit(smdk_exit); - -/* Module information */ -MODULE_AUTHOR("Jaswinder Singh Brar, jassisinghbrar@gmail.com"); -MODULE_DESCRIPTION("ALSA SoC SMDK+WM9713"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c new file mode 100644 index 000000000000..5cdf7d19b87f --- /dev/null +++ b/sound/soc/samsung/tm2_wm5110.c @@ -0,0 +1,552 @@ +/* + * Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd. + * + * Authors: Inha Song <ideal.song@samsung.com> + *          Sylwester Nawrocki <s.nawrocki@samsung.com> + * + * This program is free software; you can redistribute  it and/or modify it + * under  the terms of  the GNU General  Public License as published by the + * Free Software Foundation;  either version 2 of the  License, or (at your + * option) any later version. + */ + +#include <linux/clk.h> +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "i2s.h" +#include "../codecs/wm5110.h" + +/* + * The source clock is XCLKOUT with its mux set to the external fixed rate + * oscillator (XXTI). + */ +#define MCLK_RATE	24000000U + +#define TM2_DAI_AIF1	0 +#define TM2_DAI_AIF2	1 + +struct tm2_machine_priv { +	struct snd_soc_codec *codec; +	unsigned int sysclk_rate; +	struct gpio_desc *gpio_mic_bias; +}; + +static int tm2_start_sysclk(struct snd_soc_card *card) +{ +	struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); +	struct snd_soc_codec *codec = priv->codec; +	int ret; + +	ret = snd_soc_codec_set_pll(codec, WM5110_FLL1_REFCLK, +				    ARIZONA_FLL_SRC_MCLK1, +				    MCLK_RATE, +				    priv->sysclk_rate); +	if (ret < 0) { +		dev_err(codec->dev, "Failed to set FLL1 source: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_codec_set_pll(codec, WM5110_FLL1, +				    ARIZONA_FLL_SRC_MCLK1, +				    MCLK_RATE, +				    priv->sysclk_rate); +	if (ret < 0) { +		dev_err(codec->dev, "Failed to start FLL1: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, +				       ARIZONA_CLK_SRC_FLL1, +				       priv->sysclk_rate, +				       SND_SOC_CLOCK_IN); +	if (ret < 0) { +		dev_err(codec->dev, "Failed to set SYSCLK source: %d\n", ret); +		return ret; +	} + +	return 0; +} + +static int tm2_stop_sysclk(struct snd_soc_card *card) +{ +	struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); +	struct snd_soc_codec *codec = priv->codec; +	int ret; + +	ret = snd_soc_codec_set_pll(codec, WM5110_FLL1, 0, 0, 0); +	if (ret < 0) { +		dev_err(codec->dev, "Failed to stop FLL1: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, +				       ARIZONA_CLK_SRC_FLL1, 0, 0); +	if (ret < 0) { +		dev_err(codec->dev, "Failed to stop SYSCLK: %d\n", ret); +		return ret; +	} + +	return 0; +} + +static int tm2_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_codec *codec = rtd->codec; +	struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(rtd->card); + +	switch (params_rate(params)) { +	case 4000: +	case 8000: +	case 12000: +	case 16000: +	case 24000: +	case 32000: +	case 48000: +	case 96000: +	case 192000: +		/* Highest possible SYSCLK frequency: 147.456MHz */ +		priv->sysclk_rate = 147456000U; +		break; +	case 11025: +	case 22050: +	case 44100: +	case 88200: +	case 176400: +		/* Highest possible SYSCLK frequency: 135.4752 MHz */ +		priv->sysclk_rate = 135475200U; +		break; +	default: +		dev_err(codec->dev, "Not supported sample rate: %d\n", +			params_rate(params)); +		return -EINVAL; +	} + +	return tm2_start_sysclk(rtd->card); +} + +static struct snd_soc_ops tm2_aif1_ops = { +	.hw_params = tm2_aif1_hw_params, +}; + +static int tm2_aif2_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_codec *codec = rtd->codec; +	unsigned int asyncclk_rate; +	int ret; + +	switch (params_rate(params)) { +	case 8000: +	case 12000: +	case 16000: +		/* Highest possible ASYNCCLK frequency: 49.152MHz */ +		asyncclk_rate = 49152000U; +		break; +	case 11025: +		/* Highest possible ASYNCCLK frequency: 45.1584 MHz */ +		asyncclk_rate = 45158400U; +		break; +	default: +		dev_err(codec->dev, "Not supported sample rate: %d\n", +			params_rate(params)); +		return -EINVAL; +	} + +	ret = snd_soc_codec_set_pll(codec, WM5110_FLL2_REFCLK, +				    ARIZONA_FLL_SRC_MCLK1, +				    MCLK_RATE, +				    asyncclk_rate); +	if (ret < 0) { +		dev_err(codec->dev, "Failed to set FLL2 source: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_codec_set_pll(codec, WM5110_FLL2, +				    ARIZONA_FLL_SRC_MCLK1, +				    MCLK_RATE, +				    asyncclk_rate); +	if (ret < 0) { +		dev_err(codec->dev, "Failed to start FLL2: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK, +				       ARIZONA_CLK_SRC_FLL2, +				       asyncclk_rate, +				       SND_SOC_CLOCK_IN); +	if (ret < 0) { +		dev_err(codec->dev, "Failed to set ASYNCCLK source: %d\n", ret); +		return ret; +	} + +	return 0; +} + +static int tm2_aif2_hw_free(struct snd_pcm_substream *substream) +{ +	struct snd_soc_pcm_runtime *rtd = substream->private_data; +	struct snd_soc_codec *codec = rtd->codec; +	int ret; + +	/* disable FLL2 */ +	ret = snd_soc_codec_set_pll(codec, WM5110_FLL2, ARIZONA_FLL_SRC_MCLK1, +				    0, 0); +	if (ret < 0) +		dev_err(codec->dev, "Failed to stop FLL2: %d\n", ret); + +	return ret; +} + +static struct snd_soc_ops tm2_aif2_ops = { +	.hw_params = tm2_aif2_hw_params, +	.hw_free = tm2_aif2_hw_free, +}; + +static int tm2_mic_bias(struct snd_soc_dapm_widget *w, +				struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_card *card = w->dapm->card; +	struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); + +	switch (event) { +	case SND_SOC_DAPM_PRE_PMU: +		gpiod_set_value_cansleep(priv->gpio_mic_bias,  1); +		break; +	case SND_SOC_DAPM_POST_PMD: +		gpiod_set_value_cansleep(priv->gpio_mic_bias,  0); +		break; +	} + +	return 0; +} + +static int tm2_set_bias_level(struct snd_soc_card *card, +				struct snd_soc_dapm_context *dapm, +				enum snd_soc_bias_level level) +{ +	struct snd_soc_pcm_runtime *rtd; + +	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + +	if (dapm->dev != rtd->codec_dai->dev) +		return 0; + +	switch (level) { +	case SND_SOC_BIAS_STANDBY: +		if (card->dapm.bias_level == SND_SOC_BIAS_OFF) +			tm2_start_sysclk(card); +		break; +	case SND_SOC_BIAS_OFF: +		tm2_stop_sysclk(card); +		break; +	default: +		break; +	} + +	return 0; +} + +static struct snd_soc_aux_dev tm2_speaker_amp_dev; + +static int tm2_late_probe(struct snd_soc_card *card) +{ +	struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); +	struct snd_soc_dai_link_component dlc = { 0 }; +	unsigned int ch_map[] = { 0, 1 }; +	struct snd_soc_dai *amp_pdm_dai; +	struct snd_soc_pcm_runtime *rtd; +	struct snd_soc_dai *aif1_dai; +	struct snd_soc_dai *aif2_dai; +	int ret; + +	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF1].name); +	aif1_dai = rtd->codec_dai; +	priv->codec = rtd->codec; + +	ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0); +	if (ret < 0) { +		dev_err(aif1_dai->dev, "Failed to set SYSCLK: %d\n", ret); +		return ret; +	} + +	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF2].name); +	aif2_dai = rtd->codec_dai; + +	ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0); +	if (ret < 0) { +		dev_err(aif2_dai->dev, "Failed to set ASYNCCLK: %d\n", ret); +		return ret; +	} + +	dlc.of_node = tm2_speaker_amp_dev.codec_of_node; +	amp_pdm_dai = snd_soc_find_dai(&dlc); +	if (!amp_pdm_dai) +		return -ENODEV; + +	/* Set the MAX98504 V/I sense PDM Tx DAI channel mapping */ +	ret = snd_soc_dai_set_channel_map(amp_pdm_dai, ARRAY_SIZE(ch_map), +					  ch_map, 0, NULL); +	if (ret < 0) +		return ret; + +	ret = snd_soc_dai_set_tdm_slot(amp_pdm_dai, 0x3, 0x0, 2, 16); +	if (ret < 0) +		return ret; + +	return 0; +} + +static const struct snd_kcontrol_new tm2_controls[] = { +	SOC_DAPM_PIN_SWITCH("HP"), +	SOC_DAPM_PIN_SWITCH("SPK"), +	SOC_DAPM_PIN_SWITCH("RCV"), +	SOC_DAPM_PIN_SWITCH("VPS"), +	SOC_DAPM_PIN_SWITCH("HDMI"), + +	SOC_DAPM_PIN_SWITCH("Main Mic"), +	SOC_DAPM_PIN_SWITCH("Sub Mic"), +	SOC_DAPM_PIN_SWITCH("Third Mic"), + +	SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +const struct snd_soc_dapm_widget tm2_dapm_widgets[] = { +	SND_SOC_DAPM_HP("HP", NULL), +	SND_SOC_DAPM_SPK("SPK", NULL), +	SND_SOC_DAPM_SPK("RCV", NULL), +	SND_SOC_DAPM_LINE("VPS", NULL), +	SND_SOC_DAPM_LINE("HDMI", NULL), + +	SND_SOC_DAPM_MIC("Main Mic", tm2_mic_bias), +	SND_SOC_DAPM_MIC("Sub Mic", NULL), +	SND_SOC_DAPM_MIC("Third Mic", NULL), + +	SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_component_driver tm2_component = { +	.name	= "tm2-audio", +}; + +static struct snd_soc_dai_driver tm2_ext_dai[] = { +	{ +		.name = "Voice call", +		.playback = { +			.channels_min = 1, +			.channels_max = 4, +			.rate_min = 8000, +			.rate_max = 48000, +			.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | +					SNDRV_PCM_RATE_48000), +			.formats = SNDRV_PCM_FMTBIT_S16_LE, +		}, +		.capture = { +			.channels_min = 1, +			.channels_max = 4, +			.rate_min = 8000, +			.rate_max = 48000, +			.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | +					SNDRV_PCM_RATE_48000), +			.formats = SNDRV_PCM_FMTBIT_S16_LE, +		}, +	}, +	{ +		.name = "Bluetooth", +		.playback = { +			.channels_min = 1, +			.channels_max = 4, +			.rate_min = 8000, +			.rate_max = 16000, +			.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000), +			.formats = SNDRV_PCM_FMTBIT_S16_LE, +		}, +		.capture = { +			.channels_min = 1, +			.channels_max = 2, +			.rate_min = 8000, +			.rate_max = 16000, +			.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000), +			.formats = SNDRV_PCM_FMTBIT_S16_LE, +		}, +	}, +}; + +static struct snd_soc_dai_link tm2_dai_links[] = { +	{ +		.name		= "WM5110 AIF1", +		.stream_name	= "HiFi Primary", +		.codec_dai_name = "wm5110-aif1", +		.ops		= &tm2_aif1_ops, +		.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | +				  SND_SOC_DAIFMT_CBM_CFM, +	}, { +		.name		= "WM5110 Voice", +		.stream_name	= "Voice call", +		.codec_dai_name = "wm5110-aif2", +		.ops		= &tm2_aif2_ops, +		.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | +				  SND_SOC_DAIFMT_CBM_CFM, +		.ignore_suspend = 1, +	}, { +		.name		= "WM5110 BT", +		.stream_name	= "Bluetooth", +		.codec_dai_name = "wm5110-aif3", +		.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | +				  SND_SOC_DAIFMT_CBM_CFM, +		.ignore_suspend = 1, +	} +}; + +static struct snd_soc_card tm2_card = { +	.owner			= THIS_MODULE, + +	.dai_link		= tm2_dai_links, +	.num_links		= ARRAY_SIZE(tm2_dai_links), +	.controls		= tm2_controls, +	.num_controls		= ARRAY_SIZE(tm2_controls), +	.dapm_widgets		= tm2_dapm_widgets, +	.num_dapm_widgets	= ARRAY_SIZE(tm2_dapm_widgets), +	.aux_dev		= &tm2_speaker_amp_dev, +	.num_aux_devs		= 1, + +	.late_probe		= tm2_late_probe, +	.set_bias_level		= tm2_set_bias_level, +}; + +static int tm2_probe(struct platform_device *pdev) +{ +	struct device *dev = &pdev->dev; +	struct snd_soc_card *card = &tm2_card; +	struct tm2_machine_priv *priv; +	struct device_node *cpu_dai_node, *codec_dai_node; +	int ret, i; + +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	snd_soc_card_set_drvdata(card, priv); +	card->dev = dev; + +	priv->gpio_mic_bias = devm_gpiod_get(dev, "mic-bias", +						GPIOF_OUT_INIT_LOW); +	if (IS_ERR(priv->gpio_mic_bias)) { +		dev_err(dev, "Failed to get mic bias gpio\n"); +		return PTR_ERR(priv->gpio_mic_bias); +	} + +	ret = snd_soc_of_parse_card_name(card, "model"); +	if (ret < 0) { +		dev_err(dev, "Card name is not specified\n"); +		return ret; +	} + +	ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); +	if (ret < 0) { +		dev_err(dev, "Audio routing is not specified or invalid\n"); +		return ret; +	} + +	card->aux_dev[0].codec_of_node = of_parse_phandle(dev->of_node, +							"audio-amplifier", 0); +	if (!card->aux_dev[0].codec_of_node) { +		dev_err(dev, "audio-amplifier property invalid or missing\n"); +		return -EINVAL; +	} + +	cpu_dai_node = of_parse_phandle(dev->of_node, "i2s-controller", 0); +	if (!cpu_dai_node) { +		dev_err(dev, "i2s-controllers property invalid or missing\n"); +		ret = -EINVAL; +		goto amp_node_put; +	} + +	codec_dai_node = of_parse_phandle(dev->of_node, "audio-codec", 0); +	if (!codec_dai_node) { +		dev_err(dev, "audio-codec property invalid or missing\n"); +		ret = -EINVAL; +		goto cpu_dai_node_put; +	} + +	for (i = 0; i < card->num_links; i++) { +		card->dai_link[i].cpu_dai_name = NULL; +		card->dai_link[i].cpu_name = NULL; +		card->dai_link[i].platform_name = NULL; +		card->dai_link[i].codec_of_node = codec_dai_node; +		card->dai_link[i].cpu_of_node = cpu_dai_node; +		card->dai_link[i].platform_of_node = cpu_dai_node; +	} + +	ret = devm_snd_soc_register_component(dev, &tm2_component, +				tm2_ext_dai, ARRAY_SIZE(tm2_ext_dai)); +	if (ret < 0) { +		dev_err(dev, "Failed to register component: %d\n", ret); +		goto codec_dai_node_put; +	} + +	ret = devm_snd_soc_register_card(dev, card); +	if (ret < 0) { +		dev_err(dev, "Failed to register card: %d\n", ret); +		goto codec_dai_node_put; +	} + +codec_dai_node_put: +	of_node_put(codec_dai_node); +cpu_dai_node_put: +	of_node_put(cpu_dai_node); +amp_node_put: +	of_node_put(card->aux_dev[0].codec_of_node); +	return ret; +} + +static int tm2_pm_prepare(struct device *dev) +{ +	struct snd_soc_card *card = dev_get_drvdata(dev); + +	return tm2_stop_sysclk(card); +} + +static void tm2_pm_complete(struct device *dev) +{ +	struct snd_soc_card *card = dev_get_drvdata(dev); + +	tm2_start_sysclk(card); +} + +const struct dev_pm_ops tm2_pm_ops = { +	.prepare	= tm2_pm_prepare, +	.suspend	= snd_soc_suspend, +	.resume		= snd_soc_resume, +	.complete	= tm2_pm_complete, +	.freeze		= snd_soc_suspend, +	.thaw		= snd_soc_resume, +	.poweroff	= snd_soc_poweroff, +	.restore	= snd_soc_resume, +}; + +static const struct of_device_id tm2_of_match[] = { +	{ .compatible = "samsung,tm2-audio" }, +	{ }, +}; +MODULE_DEVICE_TABLE(of, tm2_of_match); + +static struct platform_driver tm2_driver = { +	.driver = { +		.name		= "tm2-audio", +		.pm		= &tm2_pm_ops, +		.of_match_table	= tm2_of_match, +	}, +	.probe	= tm2_probe, +}; +module_platform_driver(tm2_driver); + +MODULE_AUTHOR("Inha Song <ideal.song@samsung.com>"); +MODULE_DESCRIPTION("ALSA SoC Exynos TM2 Audio Support"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 6db6405d952f..147ebecfed94 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -1,5 +1,5 @@  menu "SoC Audio support for SuperH" -	depends on SUPERH || ARCH_SHMOBILE +	depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST  config SND_SOC_PCM_SH7760  	tristate "SoC Audio support for Renesas SH7760" @@ -37,6 +37,7 @@ config SND_SOC_SH4_SIU  config SND_SOC_RCAR  	tristate "R-Car series SRU/SCU/SSIU/SSI support"  	depends on COMMON_CLK +	depends on OF || COMPILE_TEST  	select SND_SIMPLE_CARD  	select REGMAP_MMIO  	help diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 2145957d0229..85a33ac0a5c4 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -34,6 +34,9 @@ struct rsnd_adg {  	struct clk_onecell_data onecell;  	struct rsnd_mod mod;  	u32 flags; +	u32 ckr; +	u32 rbga; +	u32 rbgb;  	int rbga_rate_for_441khz; /* RBGA */  	int rbgb_rate_for_48khz;  /* RBGB */ @@ -316,9 +319,11 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)  	struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);  	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);  	struct device *dev = rsnd_priv_to_dev(priv); +	struct rsnd_mod *adg_mod = rsnd_mod_get(adg);  	struct clk *clk;  	int i;  	u32 data; +	u32 ckr = 0;  	int sel_table[] = {  		[CLKA] = 0x1,  		[CLKB] = 0x2, @@ -360,15 +365,14 @@ found_clock:  	rsnd_adg_set_ssi_clk(ssi_mod, data);  	if (!(adg_mode_flags(adg) & LRCLK_ASYNC)) { -		struct rsnd_mod *adg_mod = rsnd_mod_get(adg); -		u32 ckr = 0; -  		if (0 == (rate % 8000))  			ckr = 0x80000000; - -		rsnd_mod_bset(adg_mod, SSICKR, 0x80000000, ckr);  	} +	rsnd_mod_bset(adg_mod, BRGCKR, 0x80FF0000, adg->ckr | ckr); +	rsnd_mod_write(adg_mod, BRRA,  adg->rbga); +	rsnd_mod_write(adg_mod, BRRB,  adg->rbgb); +  	dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n",  		rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod),  		data, rate); @@ -376,6 +380,25 @@ found_clock:  	return 0;  } +void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) +{ +	struct rsnd_adg *adg = rsnd_priv_to_adg(priv); +	struct device *dev = rsnd_priv_to_dev(priv); +	struct clk *clk; +	int i, ret; + +	for_each_rsnd_clk(clk, adg, i) { +		ret = 0; +		if (enable) +			ret = clk_prepare_enable(clk); +		else +			clk_disable_unprepare(clk); + +		if (ret < 0) +			dev_warn(dev, "can't use clk %d\n", i); +	} +} +  static void rsnd_adg_get_clkin(struct rsnd_priv *priv,  			       struct rsnd_adg *adg)  { @@ -387,27 +410,21 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv,  		[CLKC]	= "clk_c",  		[CLKI]	= "clk_i",  	}; -	int i, ret; +	int i;  	for (i = 0; i < CLKMAX; i++) {  		clk = devm_clk_get(dev, clk_name[i]);  		adg->clk[i] = IS_ERR(clk) ? NULL : clk;  	} -	for_each_rsnd_clk(clk, adg, i) { -		ret = clk_prepare_enable(clk); -		if (ret < 0) -			dev_warn(dev, "can't use clk %d\n", i); - +	for_each_rsnd_clk(clk, adg, i)  		dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk)); -	}  }  static void rsnd_adg_get_clkout(struct rsnd_priv *priv,  				struct rsnd_adg *adg)  {  	struct clk *clk; -	struct rsnd_mod *adg_mod = rsnd_mod_get(adg);  	struct device *dev = rsnd_priv_to_dev(priv);  	struct device_node *np = dev->of_node;  	u32 ckr, rbgx, rbga, rbgb; @@ -532,13 +549,13 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,  		}  	} -	rsnd_mod_bset(adg_mod, SSICKR, 0x80FF0000, ckr); -	rsnd_mod_write(adg_mod, BRRA,  rbga); -	rsnd_mod_write(adg_mod, BRRB,  rbgb); +	adg->ckr = ckr; +	adg->rbga = rbga; +	adg->rbgb = rbgb;  	for_each_rsnd_clkout(clk, adg, i)  		dev_dbg(dev, "clkout %d : %p : %ld\n", i, clk, clk_get_rate(clk)); -	dev_dbg(dev, "SSICKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n", +	dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",  		ckr, rbga, rbgb);  } @@ -565,16 +582,12 @@ int rsnd_adg_probe(struct rsnd_priv *priv)  	priv->adg = adg; +	rsnd_adg_clk_enable(priv); +  	return 0;  }  void rsnd_adg_remove(struct rsnd_priv *priv)  { -	struct rsnd_adg *adg = rsnd_priv_to_adg(priv); -	struct clk *clk; -	int i; - -	for_each_rsnd_clk(clk, adg, i) { -		clk_disable_unprepare(clk); -	} +	rsnd_adg_clk_disable(priv);  } diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f18141098b50..4bd68de76130 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -306,7 +306,7 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)   */  u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)  { -	struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); +	struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);  	struct rsnd_mod *target;  	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);  	u32 val = 0x76543210; @@ -315,11 +315,11 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)  	if (rsnd_io_is_play(io)) {  		struct rsnd_mod *src = rsnd_io_to_mod_src(io); -		target = src ? src : ssi; +		target = src ? src : ssiu;  	} else {  		struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io); -		target = cmd ? cmd : ssi; +		target = cmd ? cmd : ssiu;  	}  	mask <<= runtime->channels * 4; @@ -348,32 +348,28 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)  /*   *	rsnd_dai functions   */ -#define rsnd_mod_call(idx, io, func, param...)			\ -({								\ -	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);		\ -	struct rsnd_mod *mod = (io)->mod[idx];			\ -	struct device *dev = rsnd_priv_to_dev(priv);		\ -	u32 *status = mod->get_status(io, mod, idx);			\ -	u32 mask = 0xF << __rsnd_mod_shift_##func;			\ -	u8 val  = (*status >> __rsnd_mod_shift_##func) & 0xF;		\ -	u8 add  = ((val + __rsnd_mod_add_##func) & 0xF);		\ -	int ret = 0;							\ -	int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func;	\ -	if (add == 0xF)							\ -		call = 0;						\ -	else								\ -		*status = (*status & ~mask) +				\ -			(add << __rsnd_mod_shift_##func);		\ -	dev_dbg(dev, "%s[%d]\t0x%08x %s\n",				\ -		rsnd_mod_name(mod), rsnd_mod_id(mod),			\ -		*status, call ? #func : "");				\ -	if (call)							\ -		ret = (mod)->ops->func(mod, io, param);			\ -	if (ret)							\ -		dev_dbg(dev, "%s[%d] : rsnd_mod_call error %d\n",	\ -			rsnd_mod_name(mod), rsnd_mod_id(mod), ret);	\ -	ret;								\ -}) +struct rsnd_mod *rsnd_mod_next(int *iterator, +			       struct rsnd_dai_stream *io, +			       enum rsnd_mod_type *array, +			       int array_size) +{ +	struct rsnd_mod *mod; +	enum rsnd_mod_type type; +	int max = array ? array_size : RSND_MOD_MAX; + +	for (; *iterator < max; (*iterator)++) { +		type = (array) ? array[*iterator] : *iterator; +		mod = io->mod[type]; +		if (!mod) +			continue; + +		(*iterator)++; + +		return mod; +	} + +	return NULL; +}  static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = {  	{ @@ -409,19 +405,49 @@ static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = {  	},  }; -#define rsnd_dai_call(fn, io, param...)				\ -({								\ -	struct rsnd_mod *mod;					\ -	int type, is_play = rsnd_io_is_play(io);		\ -	int ret = 0, i;						\ -	for (i = 0; i < RSND_MOD_MAX; i++) {			\ -		type = rsnd_mod_sequence[is_play][i];		\ -		mod = (io)->mod[type];				\ -		if (!mod)					\ -			continue;				\ -		ret |= rsnd_mod_call(type, io, fn, param);	\ -	}							\ -	ret;							\ +static int rsnd_status_update(u32 *status, +			      int shift, int add, int timing) +{ +	u32 mask	= 0xF << shift; +	u8 val		= (*status >> shift) & 0xF; +	u8 next_val	= (val + add) & 0xF; +	int func_call	= (val == timing); + +	if (next_val == 0xF) /* underflow case */ +		func_call = 0; +	else +		*status = (*status & ~mask) + (next_val << shift); + +	return func_call; +} + +#define rsnd_dai_call(fn, io, param...)					\ +({									\ +	struct rsnd_priv *priv = rsnd_io_to_priv(io);			\ +	struct device *dev = rsnd_priv_to_dev(priv);			\ +	struct rsnd_mod *mod;						\ +	int is_play = rsnd_io_is_play(io);				\ +	int ret = 0, i;							\ +	enum rsnd_mod_type *types = rsnd_mod_sequence[is_play];		\ +	for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) {	\ +		int tmp = 0;						\ +		u32 *status = mod->get_status(io, mod, types[i]);	\ +		int func_call = rsnd_status_update(status,		\ +						__rsnd_mod_shift_##fn,	\ +						__rsnd_mod_add_##fn,	\ +						__rsnd_mod_call_##fn);	\ +		dev_dbg(dev, "%s[%d]\t0x%08x %s\n",			\ +			rsnd_mod_name(mod), rsnd_mod_id(mod), *status,	\ +			(func_call && (mod)->ops->fn) ? #fn : "");	\ +		if (func_call && (mod)->ops->fn)			\ +			tmp = (mod)->ops->fn(mod, io, param);		\ +		if (tmp)						\ +			dev_err(dev, "%s[%d] : %s error %d\n",		\ +				rsnd_mod_name(mod), rsnd_mod_id(mod),	\ +						     #fn, tmp);		\ +		ret |= tmp;						\ +	}								\ +	ret;								\  })  int rsnd_dai_connect(struct rsnd_mod *mod, @@ -690,7 +716,33 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,  	return 0;  } +static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, +				struct snd_soc_dai *dai) +{ +	struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); +	struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + +	/* +	 * call rsnd_dai_call without spinlock +	 */ +	return rsnd_dai_call(nolock_start, io, priv); +} + +static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, +				  struct snd_soc_dai *dai) +{ +	struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); +	struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + +	/* +	 * call rsnd_dai_call without spinlock +	 */ +	rsnd_dai_call(nolock_stop, io, priv); +} +  static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { +	.startup	= rsnd_soc_dai_startup, +	.shutdown	= rsnd_soc_dai_shutdown,  	.trigger	= rsnd_soc_dai_trigger,  	.set_fmt	= rsnd_soc_dai_set_fmt,  	.set_tdm_slot	= rsnd_soc_set_dai_tdm_slot, @@ -993,7 +1045,11 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod,  void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg)  { -	snd_ctl_remove(cfg->card, cfg->kctrl); +	if (cfg->card && cfg->kctrl) +		snd_ctl_remove(cfg->card, cfg->kctrl); + +	cfg->card = NULL; +	cfg->kctrl = NULL;  }  int rsnd_kctrl_new_m(struct rsnd_mod *mod, @@ -1070,8 +1126,8 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)  	return snd_pcm_lib_preallocate_pages_for_all(  		rtd->pcm, -		SNDRV_DMA_TYPE_DEV, -		rtd->card->snd_card->dev, +		SNDRV_DMA_TYPE_CONTINUOUS, +		snd_dma_continuous_data(GFP_KERNEL),  		PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);  } @@ -1092,6 +1148,7 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,  	ret = rsnd_dai_call(probe, io, priv);  	if (ret == -EAGAIN) {  		struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); +		struct rsnd_mod *mod;  		int i;  		/* @@ -1111,8 +1168,8 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,  		 * remove all mod from io  		 * and, re connect ssi  		 */ -		for (i = 0; i < RSND_MOD_MAX; i++) -			rsnd_dai_disconnect((io)->mod[i], io, i); +		for_each_rsnd_mod(i, mod, io) +			rsnd_dai_disconnect(mod, io, i);  		rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI);  		/* @@ -1251,9 +1308,33 @@ static int rsnd_remove(struct platform_device *pdev)  	return ret;  } +static int rsnd_suspend(struct device *dev) +{ +	struct rsnd_priv *priv = dev_get_drvdata(dev); + +	rsnd_adg_clk_disable(priv); + +	return 0; +} + +static int rsnd_resume(struct device *dev) +{ +	struct rsnd_priv *priv = dev_get_drvdata(dev); + +	rsnd_adg_clk_enable(priv); + +	return 0; +} + +static struct dev_pm_ops rsnd_pm_ops = { +	.suspend		= rsnd_suspend, +	.resume			= rsnd_resume, +}; +  static struct platform_driver rsnd_driver = {  	.driver	= {  		.name	= "rcar_sound", +		.pm	= &rsnd_pm_ops,  		.of_match_table = rsnd_of_match,  	},  	.probe		= rsnd_probe, diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 6bc93cbb3049..1f405c833867 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -25,6 +25,10 @@  struct rsnd_dmaen {  	struct dma_chan		*chan; +	dma_addr_t		dma_buf; +	unsigned int		dma_len; +	unsigned int		dma_period; +	unsigned int		dma_cnt;  };  struct rsnd_dmapp { @@ -34,6 +38,8 @@ struct rsnd_dmapp {  struct rsnd_dma {  	struct rsnd_mod		mod; +	struct rsnd_mod		*mod_from; +	struct rsnd_mod		*mod_to;  	dma_addr_t		src_addr;  	dma_addr_t		dst_addr;  	union { @@ -56,10 +62,38 @@ struct rsnd_dma_ctrl {  /*   *		Audio DMAC   */ +#define rsnd_dmaen_sync(dmaen, io, i)	__rsnd_dmaen_sync(dmaen, io, i, 1) +#define rsnd_dmaen_unsync(dmaen, io, i)	__rsnd_dmaen_sync(dmaen, io, i, 0) +static void __rsnd_dmaen_sync(struct rsnd_dmaen *dmaen, struct rsnd_dai_stream *io, +			      int i, int sync) +{ +	struct device *dev = dmaen->chan->device->dev; +	enum dma_data_direction dir; +	int is_play = rsnd_io_is_play(io); +	dma_addr_t buf; +	int len, max; +	size_t period; + +	len	= dmaen->dma_len; +	period	= dmaen->dma_period; +	max	= len / period; +	i	= i % max; +	buf	= dmaen->dma_buf + (period * i); + +	dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + +	if (sync) +		dma_sync_single_for_device(dev, buf, period, dir); +	else +		dma_sync_single_for_cpu(dev, buf, period, dir); +} +  static void __rsnd_dmaen_complete(struct rsnd_mod *mod,  				  struct rsnd_dai_stream *io)  {  	struct rsnd_priv *priv = rsnd_mod_to_priv(mod); +	struct rsnd_dma *dma = rsnd_mod_to_dma(mod); +	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);  	bool elapsed = false;  	unsigned long flags; @@ -76,9 +110,22 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod,  	 */  	spin_lock_irqsave(&priv->lock, flags); -	if (rsnd_io_is_working(io)) +	if (rsnd_io_is_working(io)) { +		rsnd_dmaen_unsync(dmaen, io, dmaen->dma_cnt); + +		/* +		 * Next period is already started. +		 * Let's sync Next Next period +		 * see +		 *	rsnd_dmaen_start() +		 */ +		rsnd_dmaen_sync(dmaen, io, dmaen->dma_cnt + 2); +  		elapsed = rsnd_dai_pointer_update(io, io->byte_per_period); +		dmaen->dma_cnt++; +	} +  	spin_unlock_irqrestore(&priv->lock, flags);  	if (elapsed) @@ -92,6 +139,20 @@ static void rsnd_dmaen_complete(void *data)  	rsnd_mod_interrupt(mod, __rsnd_dmaen_complete);  } +static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, +						   struct rsnd_mod *mod_from, +						   struct rsnd_mod *mod_to) +{ +	if ((!mod_from && !mod_to) || +	    (mod_from && mod_to)) +		return NULL; + +	if (mod_from) +		return rsnd_mod_dma_req(io, mod_from); +	else +		return rsnd_mod_dma_req(io, mod_to); +} +  static int rsnd_dmaen_stop(struct rsnd_mod *mod,  			   struct rsnd_dai_stream *io,  			   struct rsnd_priv *priv) @@ -99,7 +160,66 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod,  	struct rsnd_dma *dma = rsnd_mod_to_dma(mod);  	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); -	dmaengine_terminate_all(dmaen->chan); +	if (dmaen->chan) { +		int is_play = rsnd_io_is_play(io); + +		dmaengine_terminate_all(dmaen->chan); +		dma_unmap_single(dmaen->chan->device->dev, +				 dmaen->dma_buf, dmaen->dma_len, +				 is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE); +	} + +	return 0; +} + +static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod, +				   struct rsnd_dai_stream *io, +				   struct rsnd_priv *priv) +{ +	struct rsnd_dma *dma = rsnd_mod_to_dma(mod); +	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); + +	/* +	 * DMAEngine release uses mutex lock. +	 * Thus, it shouldn't be called under spinlock. +	 * Let's call it under nolock_start +	 */ +	if (dmaen->chan) +		dma_release_channel(dmaen->chan); + +	dmaen->chan = NULL; + +	return 0; +} + +static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod, +			    struct rsnd_dai_stream *io, +			    struct rsnd_priv *priv) +{ +	struct rsnd_dma *dma = rsnd_mod_to_dma(mod); +	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); +	struct device *dev = rsnd_priv_to_dev(priv); + +	if (dmaen->chan) { +		dev_err(dev, "it already has dma channel\n"); +		return -EIO; +	} + +	/* +	 * DMAEngine request uses mutex lock. +	 * Thus, it shouldn't be called under spinlock. +	 * Let's call it under nolock_start +	 */ +	dmaen->chan = rsnd_dmaen_request_channel(io, +						 dma->mod_from, +						 dma->mod_to); +	if (IS_ERR_OR_NULL(dmaen->chan)) { +		int ret = PTR_ERR(dmaen->chan); + +		dmaen->chan = NULL; +		dev_err(dev, "can't get dma channel\n"); +		return ret; +	}  	return 0;  } @@ -113,12 +233,41 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,  	struct snd_pcm_substream *substream = io->substream;  	struct device *dev = rsnd_priv_to_dev(priv);  	struct dma_async_tx_descriptor *desc; +	struct dma_slave_config cfg = {}; +	dma_addr_t buf; +	size_t len; +	size_t period;  	int is_play = rsnd_io_is_play(io); +	int i; +	int ret; + +	cfg.direction	= is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; +	cfg.src_addr	= dma->src_addr; +	cfg.dst_addr	= dma->dst_addr; +	cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +	cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + +	dev_dbg(dev, "%s[%d] %pad -> %pad\n", +		rsnd_mod_name(mod), rsnd_mod_id(mod), +		&cfg.src_addr, &cfg.dst_addr); + +	ret = dmaengine_slave_config(dmaen->chan, &cfg); +	if (ret < 0) +		return ret; + +	len	= snd_pcm_lib_buffer_bytes(substream); +	period	= snd_pcm_lib_period_bytes(substream); +	buf	= dma_map_single(dmaen->chan->device->dev, +				 substream->runtime->dma_area, +				 len, +				 is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE); +	if (dma_mapping_error(dmaen->chan->device->dev, buf)) { +		dev_err(dev, "dma map failed\n"); +		return -EIO; +	}  	desc = dmaengine_prep_dma_cyclic(dmaen->chan, -					 substream->runtime->dma_addr, -					 snd_pcm_lib_buffer_bytes(substream), -					 snd_pcm_lib_period_bytes(substream), +					 buf, len, period,  					 is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,  					 DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -130,6 +279,19 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,  	desc->callback		= rsnd_dmaen_complete;  	desc->callback_param	= rsnd_mod_get(dma); +	dmaen->dma_buf		= buf; +	dmaen->dma_len		= len; +	dmaen->dma_period	= period; +	dmaen->dma_cnt		= 0; + +	/* +	 * synchronize this and next period +	 * see +	 *	__rsnd_dmaen_complete() +	 */ +	for (i = 0; i < 2; i++) +		rsnd_dmaen_sync(dmaen, io, i); +  	if (dmaengine_submit(desc) < 0) {  		dev_err(dev, "dmaengine_submit() fail\n");  		return -EIO; @@ -143,124 +305,55 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,  struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,  					  struct rsnd_mod *mod, char *name)  { -	struct dma_chan *chan; +	struct dma_chan *chan = NULL;  	struct device_node *np;  	int i = 0;  	for_each_child_of_node(of_node, np) { -		if (i == rsnd_mod_id(mod)) -			break; +		if (i == rsnd_mod_id(mod) && (!chan)) +			chan = of_dma_request_slave_channel(np, name);  		i++;  	} -	chan = of_dma_request_slave_channel(np, name); - -	of_node_put(np); +	/* It should call of_node_put(), since, it is rsnd_xxx_of_node() */  	of_node_put(of_node);  	return chan;  } -static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, -						   struct rsnd_mod *mod_from, -						   struct rsnd_mod *mod_to) -{ -	if ((!mod_from && !mod_to) || -	    (mod_from && mod_to)) -		return NULL; - -	if (mod_from) -		return rsnd_mod_dma_req(io, mod_from); -	else -		return rsnd_mod_dma_req(io, mod_to); -} - -static int rsnd_dmaen_remove(struct rsnd_mod *mod, -			      struct rsnd_dai_stream *io, -			      struct rsnd_priv *priv) -{ -	struct rsnd_dma *dma = rsnd_mod_to_dma(mod); -	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - -	if (dmaen->chan) -		dma_release_channel(dmaen->chan); - -	dmaen->chan = NULL; - -	return 0; -} -  static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, -			   struct rsnd_dma *dma, int id, +			   struct rsnd_dma *dma,  			   struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)  { -	struct rsnd_mod *mod = rsnd_mod_get(dma); -	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);  	struct rsnd_priv *priv = rsnd_io_to_priv(io);  	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); -	struct device *dev = rsnd_priv_to_dev(priv); -	struct dma_slave_config cfg = {}; -	int is_play = rsnd_io_is_play(io); -	int ret; - -	if (dmaen->chan) { -		dev_err(dev, "it already has dma channel\n"); -		return -EIO; -	} - -	if (dev->of_node) { -		dmaen->chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); -	} else { -		dma_cap_mask_t mask; - -		dma_cap_zero(mask); -		dma_cap_set(DMA_SLAVE, mask); +	struct dma_chan *chan; -		dmaen->chan = dma_request_channel(mask, shdma_chan_filter, -						  (void *)(uintptr_t)id); -	} -	if (IS_ERR_OR_NULL(dmaen->chan)) { -		dmaen->chan = NULL; -		dev_err(dev, "can't get dma channel\n"); -		goto rsnd_dma_channel_err; +	/* try to get DMAEngine channel */ +	chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); +	if (IS_ERR_OR_NULL(chan)) { +		/* +		 * DMA failed. try to PIO mode +		 * see +		 *	rsnd_ssi_fallback() +		 *	rsnd_rdai_continuance_probe() +		 */ +		return -EAGAIN;  	} -	cfg.direction	= is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; -	cfg.src_addr	= dma->src_addr; -	cfg.dst_addr	= dma->dst_addr; -	cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; -	cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - -	dev_dbg(dev, "%s[%d] %pad -> %pad\n", -		rsnd_mod_name(mod), rsnd_mod_id(mod), -		&cfg.src_addr, &cfg.dst_addr); - -	ret = dmaengine_slave_config(dmaen->chan, &cfg); -	if (ret < 0) -		goto rsnd_dma_attach_err; +	dma_release_channel(chan);  	dmac->dmaen_num++;  	return 0; - -rsnd_dma_attach_err: -	rsnd_dmaen_remove(mod, io, priv); -rsnd_dma_channel_err: - -	/* -	 * DMA failed. try to PIO mode -	 * see -	 *	rsnd_ssi_fallback() -	 *	rsnd_rdai_continuance_probe() -	 */ -	return -EAGAIN;  }  static struct rsnd_mod_ops rsnd_dmaen_ops = {  	.name	= "audmac", +	.nolock_start = rsnd_dmaen_nolock_start, +	.nolock_stop  = rsnd_dmaen_nolock_stop,  	.start	= rsnd_dmaen_start,  	.stop	= rsnd_dmaen_stop, -	.remove	= rsnd_dmaen_remove,  };  /* @@ -394,7 +487,7 @@ static int rsnd_dmapp_start(struct rsnd_mod *mod,  }  static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, -			     struct rsnd_dma *dma, int id, +			     struct rsnd_dma *dma,  			     struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)  {  	struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); @@ -627,7 +720,7 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,  }  int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, -		    struct rsnd_mod **dma_mod, int id) +		    struct rsnd_mod **dma_mod)  {  	struct rsnd_mod *mod_from = NULL;  	struct rsnd_mod *mod_to = NULL; @@ -636,7 +729,7 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,  	struct device *dev = rsnd_priv_to_dev(priv);  	struct rsnd_mod_ops *ops;  	enum rsnd_mod_type type; -	int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, +	int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma,  		      struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);  	int is_play = rsnd_io_is_play(io);  	int ret, dma_id; @@ -682,9 +775,6 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,  		*dma_mod = rsnd_mod_get(dma); -		dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); -		dma->dst_addr = rsnd_dma_addr(io, mod_to,   is_play, 0); -  		ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,  				    rsnd_mod_get_status, type, dma_id);  		if (ret < 0) @@ -695,9 +785,14 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,  			rsnd_mod_name(mod_from), rsnd_mod_id(mod_from),  			rsnd_mod_name(mod_to),   rsnd_mod_id(mod_to)); -		ret = attach(io, dma, id, mod_from, mod_to); +		ret = attach(io, dma, mod_from, mod_to);  		if (ret < 0)  			return ret; + +		dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); +		dma->dst_addr = rsnd_dma_addr(io, mod_to,   is_play, 0); +		dma->mod_from = mod_from; +		dma->mod_to   = mod_to;  	}  	ret = rsnd_dai_connect(*dma_mod, io, type); diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 02d971f69eff..cf8f59cdd8d7 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -48,8 +48,6 @@ struct rsnd_dvc {  #define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)  #define rsnd_dvc_nr(priv) ((priv)->dvc_nr) -#define rsnd_dvc_of_node(priv) \ -	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")  #define rsnd_mod_to_dvc(_mod)	\  	container_of((_mod), struct rsnd_dvc, mod) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 7d2fdf8dd188..63b6d3c28021 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -211,6 +211,14 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)  		RSND_GEN_S_REG(SSI_MODE1,	0x804),  		RSND_GEN_S_REG(SSI_MODE2,	0x808),  		RSND_GEN_S_REG(SSI_CONTROL,	0x810), +		RSND_GEN_S_REG(SSI_SYS_STATUS0,	0x840), +		RSND_GEN_S_REG(SSI_SYS_STATUS1,	0x844), +		RSND_GEN_S_REG(SSI_SYS_STATUS2,	0x848), +		RSND_GEN_S_REG(SSI_SYS_STATUS3,	0x84c), +		RSND_GEN_S_REG(SSI_SYS_STATUS4,	0x880), +		RSND_GEN_S_REG(SSI_SYS_STATUS5,	0x884), +		RSND_GEN_S_REG(SSI_SYS_STATUS6,	0x888), +		RSND_GEN_S_REG(SSI_SYS_STATUS7,	0x88c),  		/* FIXME: it needs SSI_MODE2/3 in the future */  		RSND_GEN_M_REG(SSI_BUSIF_MODE,	0x0,	0x80), @@ -311,7 +319,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)  	static const struct rsnd_regmap_field_conf conf_adg[] = {  		RSND_GEN_S_REG(BRRA,		0x00),  		RSND_GEN_S_REG(BRRB,		0x04), -		RSND_GEN_S_REG(SSICKR,		0x08), +		RSND_GEN_S_REG(BRGCKR,		0x08),  		RSND_GEN_S_REG(AUDIO_CLK_SEL0,	0x0c),  		RSND_GEN_S_REG(AUDIO_CLK_SEL1,	0x10),  		RSND_GEN_S_REG(AUDIO_CLK_SEL2,	0x14), @@ -362,7 +370,7 @@ static int rsnd_gen1_probe(struct rsnd_priv *priv)  	static const struct rsnd_regmap_field_conf conf_adg[] = {  		RSND_GEN_S_REG(BRRA,		0x00),  		RSND_GEN_S_REG(BRRB,		0x04), -		RSND_GEN_S_REG(SSICKR,		0x08), +		RSND_GEN_S_REG(BRGCKR,		0x08),  		RSND_GEN_S_REG(AUDIO_CLK_SEL0,	0x0c),  		RSND_GEN_S_REG(AUDIO_CLK_SEL1,	0x10),  	}; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index a8f61d79333b..b90df77662df 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -43,17 +43,7 @@   * see gen1/gen2 for detail   */  enum rsnd_reg { -	/* SCU (SRC/SSIU/MIX/CTU/DVC) */ -	RSND_REG_SSI_MODE,		/* Gen2 only */ -	RSND_REG_SSI_MODE0, -	RSND_REG_SSI_MODE1, -	RSND_REG_SSI_MODE2, -	RSND_REG_SSI_CONTROL, -	RSND_REG_SSI_CTRL,		/* Gen2 only */ -	RSND_REG_SSI_BUSIF_MODE,	/* Gen2 only */ -	RSND_REG_SSI_BUSIF_ADINR,	/* Gen2 only */ -	RSND_REG_SSI_BUSIF_DALIGN,	/* Gen2 only */ -	RSND_REG_SSI_INT_ENABLE,	/* Gen2 only */ +	/* SCU (MIX/CTU/DVC) */  	RSND_REG_SRC_I_BUSIF_MODE,  	RSND_REG_SRC_O_BUSIF_MODE,  	RSND_REG_SRC_ROUTE_MODE0, @@ -63,29 +53,29 @@ enum rsnd_reg {  	RSND_REG_SRC_IFSCR,  	RSND_REG_SRC_IFSVR,  	RSND_REG_SRC_SRCCR, -	RSND_REG_SRC_CTRL,		/* Gen2 only */ -	RSND_REG_SRC_BSDSR,		/* Gen2 only */ -	RSND_REG_SRC_BSISR,		/* Gen2 only */ -	RSND_REG_SRC_INT_ENABLE0,	/* Gen2 only */ -	RSND_REG_SRC_BUSIF_DALIGN,	/* Gen2 only */ -	RSND_REG_SRCIN_TIMSEL0,		/* Gen2 only */ -	RSND_REG_SRCIN_TIMSEL1,		/* Gen2 only */ -	RSND_REG_SRCIN_TIMSEL2,		/* Gen2 only */ -	RSND_REG_SRCIN_TIMSEL3,		/* Gen2 only */ -	RSND_REG_SRCIN_TIMSEL4,		/* Gen2 only */ -	RSND_REG_SRCOUT_TIMSEL0,	/* Gen2 only */ -	RSND_REG_SRCOUT_TIMSEL1,	/* Gen2 only */ -	RSND_REG_SRCOUT_TIMSEL2,	/* Gen2 only */ -	RSND_REG_SRCOUT_TIMSEL3,	/* Gen2 only */ -	RSND_REG_SRCOUT_TIMSEL4,	/* Gen2 only */ +	RSND_REG_SRC_CTRL, +	RSND_REG_SRC_BSDSR, +	RSND_REG_SRC_BSISR, +	RSND_REG_SRC_INT_ENABLE0, +	RSND_REG_SRC_BUSIF_DALIGN, +	RSND_REG_SRCIN_TIMSEL0, +	RSND_REG_SRCIN_TIMSEL1, +	RSND_REG_SRCIN_TIMSEL2, +	RSND_REG_SRCIN_TIMSEL3, +	RSND_REG_SRCIN_TIMSEL4, +	RSND_REG_SRCOUT_TIMSEL0, +	RSND_REG_SRCOUT_TIMSEL1, +	RSND_REG_SRCOUT_TIMSEL2, +	RSND_REG_SRCOUT_TIMSEL3, +	RSND_REG_SRCOUT_TIMSEL4,  	RSND_REG_SCU_SYS_STATUS0, -	RSND_REG_SCU_SYS_STATUS1,	/* Gen2 only */ +	RSND_REG_SCU_SYS_STATUS1,  	RSND_REG_SCU_SYS_INT_EN0, -	RSND_REG_SCU_SYS_INT_EN1,	/* Gen2 only */ -	RSND_REG_CMD_CTRL,		/* Gen2 only */ -	RSND_REG_CMD_BUSIF_DALIGN,	/* Gen2 only */ +	RSND_REG_SCU_SYS_INT_EN1, +	RSND_REG_CMD_CTRL, +	RSND_REG_CMD_BUSIF_DALIGN,  	RSND_REG_CMD_ROUTE_SLCT, -	RSND_REG_CMDOUT_TIMSEL,		/* Gen2 only */ +	RSND_REG_CMDOUT_TIMSEL,  	RSND_REG_CTU_SWRSR,  	RSND_REG_CTU_CTUIR,  	RSND_REG_CTU_ADINR, @@ -147,18 +137,38 @@ enum rsnd_reg {  	RSND_REG_DVC_VOL6R,  	RSND_REG_DVC_VOL7R,  	RSND_REG_DVC_DVUER, -	RSND_REG_DVC_VRCTR,		/* Gen2 only */ -	RSND_REG_DVC_VRPDR,		/* Gen2 only */ -	RSND_REG_DVC_VRDBR,		/* Gen2 only */ +	RSND_REG_DVC_VRCTR, +	RSND_REG_DVC_VRPDR, +	RSND_REG_DVC_VRDBR,  	/* ADG */  	RSND_REG_BRRA,  	RSND_REG_BRRB, -	RSND_REG_SSICKR, -	RSND_REG_DIV_EN,		/* Gen2 only */ +	RSND_REG_BRGCKR, +	RSND_REG_DIV_EN,  	RSND_REG_AUDIO_CLK_SEL0,  	RSND_REG_AUDIO_CLK_SEL1, -	RSND_REG_AUDIO_CLK_SEL2,	/* Gen2 only */ +	RSND_REG_AUDIO_CLK_SEL2, + +	/* SSIU */ +	RSND_REG_SSI_MODE, +	RSND_REG_SSI_MODE0, +	RSND_REG_SSI_MODE1, +	RSND_REG_SSI_MODE2, +	RSND_REG_SSI_CONTROL, +	RSND_REG_SSI_CTRL, +	RSND_REG_SSI_BUSIF_MODE, +	RSND_REG_SSI_BUSIF_ADINR, +	RSND_REG_SSI_BUSIF_DALIGN, +	RSND_REG_SSI_INT_ENABLE, +	RSND_REG_SSI_SYS_STATUS0, +	RSND_REG_SSI_SYS_STATUS1, +	RSND_REG_SSI_SYS_STATUS2, +	RSND_REG_SSI_SYS_STATUS3, +	RSND_REG_SSI_SYS_STATUS4, +	RSND_REG_SSI_SYS_STATUS5, +	RSND_REG_SSI_SYS_STATUS6, +	RSND_REG_SSI_SYS_STATUS7,  	/* SSI */  	RSND_REG_SSICR, @@ -199,7 +209,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);   *	R-Car DMA   */  int rsnd_dma_attach(struct rsnd_dai_stream *io, -		    struct rsnd_mod *mod, struct rsnd_mod **dma_mod, int id); +		    struct rsnd_mod *mod, struct rsnd_mod **dma_mod);  int rsnd_dma_probe(struct rsnd_priv *priv);  struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,  					  struct rsnd_mod *mod, char *name); @@ -259,6 +269,12 @@ struct rsnd_mod_ops {  	int (*fallback)(struct rsnd_mod *mod,  			struct rsnd_dai_stream *io,  			struct rsnd_priv *priv); +	int (*nolock_start)(struct rsnd_mod *mod, +		    struct rsnd_dai_stream *io, +		    struct rsnd_priv *priv); +	int (*nolock_stop)(struct rsnd_mod *mod, +		    struct rsnd_dai_stream *io, +		    struct rsnd_priv *priv);  };  struct rsnd_dai_stream; @@ -278,7 +294,7 @@ struct rsnd_mod {   *   * 0xH0000CBA   * - * A	0: probe	1: remove + * A	0: nolock_start	1: nolock_stop   * B	0: init		1: quit   * C	0: start	1: stop   * @@ -288,19 +304,23 @@ struct rsnd_mod {   * H	0: fallback   * H	0: hw_params   */ -#define __rsnd_mod_shift_probe		0 -#define __rsnd_mod_shift_remove		0 +#define __rsnd_mod_shift_nolock_start	0 +#define __rsnd_mod_shift_nolock_stop	0  #define __rsnd_mod_shift_init		4  #define __rsnd_mod_shift_quit		4  #define __rsnd_mod_shift_start		8  #define __rsnd_mod_shift_stop		8 +#define __rsnd_mod_shift_probe		28 /* always called */ +#define __rsnd_mod_shift_remove		28 /* always called */  #define __rsnd_mod_shift_irq		28 /* always called */  #define __rsnd_mod_shift_pcm_new	28 /* always called */  #define __rsnd_mod_shift_fallback	28 /* always called */  #define __rsnd_mod_shift_hw_params	28 /* always called */ -#define __rsnd_mod_add_probe		 1 -#define __rsnd_mod_add_remove		-1 +#define __rsnd_mod_add_probe		0 +#define __rsnd_mod_add_remove		0 +#define __rsnd_mod_add_nolock_start	 1 +#define __rsnd_mod_add_nolock_stop	-1  #define __rsnd_mod_add_init		 1  #define __rsnd_mod_add_quit		-1  #define __rsnd_mod_add_start		 1 @@ -311,7 +331,7 @@ struct rsnd_mod {  #define __rsnd_mod_add_hw_params	0  #define __rsnd_mod_call_probe		0 -#define __rsnd_mod_call_remove		1 +#define __rsnd_mod_call_remove		0  #define __rsnd_mod_call_init		0  #define __rsnd_mod_call_quit		1  #define __rsnd_mod_call_start		0 @@ -320,6 +340,8 @@ struct rsnd_mod {  #define __rsnd_mod_call_pcm_new		0  #define __rsnd_mod_call_fallback	0  #define __rsnd_mod_call_hw_params	0 +#define __rsnd_mod_call_nolock_start	0 +#define __rsnd_mod_call_nolock_stop	1  #define rsnd_mod_to_priv(mod) ((mod)->priv)  #define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1) @@ -346,6 +368,18 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod,  u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,  			 struct rsnd_mod *mod,  			 enum rsnd_mod_type type); +struct rsnd_mod *rsnd_mod_next(int *iterator, +			       struct rsnd_dai_stream *io, +			       enum rsnd_mod_type *array, +			       int array_size); +#define for_each_rsnd_mod(iterator, pos, io)				\ +	for (iterator = 0;						\ +	     (pos = rsnd_mod_next(&iterator, io, NULL, 0));) +#define for_each_rsnd_mod_arrays(iterator, pos, io, array, size)	\ +	for (iterator = 0;						\ +	     (pos = rsnd_mod_next(&iterator, io, array, size));) +#define for_each_rsnd_mod_array(iterator, pos, io, array)		\ +	for_each_rsnd_mod_arrays(iterator, pos, io, array, ARRAY_SIZE(array))  void rsnd_parse_connect_common(struct rsnd_dai *rdai,  		struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), @@ -365,6 +399,18 @@ int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io);  int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io);  /* + * DT + */ +#define rsnd_parse_of_node(priv, node)					\ +	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node) +#define RSND_NODE_DAI	"rcar_sound,dai" +#define RSND_NODE_SSI	"rcar_sound,ssi" +#define RSND_NODE_SRC	"rcar_sound,src" +#define RSND_NODE_CTU	"rcar_sound,ctu" +#define RSND_NODE_MIX	"rcar_sound,mix" +#define RSND_NODE_DVC	"rcar_sound,dvc" + +/*   *	R-Car sound DAI   */  #define RSND_DAI_NAME_SIZE	16 @@ -382,6 +428,7 @@ struct rsnd_dai_stream {  };  #define rsnd_io_to_mod(io, i)	((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)  #define rsnd_io_to_mod_ssi(io)	rsnd_io_to_mod((io), RSND_MOD_SSI) +#define rsnd_io_to_mod_ssiu(io)	rsnd_io_to_mod((io), RSND_MOD_SSIU)  #define rsnd_io_to_mod_ssip(io)	rsnd_io_to_mod((io), RSND_MOD_SSIP)  #define rsnd_io_to_mod_src(io)	rsnd_io_to_mod((io), RSND_MOD_SRC)  #define rsnd_io_to_mod_ctu(io)	rsnd_io_to_mod((io), RSND_MOD_CTU) @@ -428,8 +475,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);  int rsnd_dai_connect(struct rsnd_mod *mod,  		     struct rsnd_dai_stream *io,  		     enum rsnd_mod_type type); -#define rsnd_dai_of_node(priv)						\ -	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dai") +#define rsnd_dai_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DAI)  /*   *	R-Car Gen1/Gen2 @@ -453,6 +499,9 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,  				  unsigned int out_rate);  int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,  				 struct rsnd_dai_stream *io); +#define rsnd_adg_clk_enable(priv)	rsnd_adg_clk_control(priv, 1) +#define rsnd_adg_clk_disable(priv)	rsnd_adg_clk_control(priv, 0) +void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable);  /*   *	R-Car sound priv @@ -606,8 +655,7 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io);  	__rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))  int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); -#define rsnd_ssi_of_node(priv)						\ -	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") +#define rsnd_ssi_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSI)  void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,  			    struct device_node *playback,  			    struct device_node *capture); @@ -633,8 +681,7 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,  			       struct rsnd_dai_stream *io,  			       int is_in); -#define rsnd_src_of_node(priv)						\ -	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") +#define rsnd_src_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SRC)  #define rsnd_parse_connect_src(rdai, playback, capture)			\  	rsnd_parse_connect_common(rdai, rsnd_src_mod_get,		\  				  rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \ @@ -647,8 +694,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv);  void rsnd_ctu_remove(struct rsnd_priv *priv);  int rsnd_ctu_converted_channel(struct rsnd_mod *mod);  struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_ctu_of_node(priv)						\ -	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu") +#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU)  #define rsnd_parse_connect_ctu(rdai, playback, capture)			\  	rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get,		\  				  rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \ @@ -660,8 +706,7 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);  int rsnd_mix_probe(struct rsnd_priv *priv);  void rsnd_mix_remove(struct rsnd_priv *priv);  struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_mix_of_node(priv)						\ -	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix") +#define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX)  #define rsnd_parse_connect_mix(rdai, playback, capture)			\  	rsnd_parse_connect_common(rdai, rsnd_mix_mod_get,		\  				  rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \ @@ -673,8 +718,7 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);  int rsnd_dvc_probe(struct rsnd_priv *priv);  void rsnd_dvc_remove(struct rsnd_priv *priv);  struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_dvc_of_node(priv)						\ -	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") +#define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC)  #define rsnd_parse_connect_dvc(rdai, playback, capture)			\  	rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get,		\  				  rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \ diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 969a5169de25..3a8f65bd1bf9 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -189,6 +189,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,  	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);  	struct device *dev = rsnd_priv_to_dev(priv);  	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); +	int use_src = 0;  	u32 fin, fout;  	u32 ifscr, fsrate, adinr;  	u32 cr, route; @@ -214,6 +215,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,  		return;  	} +	use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod); +  	/*  	 *	SRC_ADINR  	 */ @@ -225,7 +228,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,  	 */  	ifscr = 0;  	fsrate = 0; -	if (fin != fout) { +	if (use_src) {  		u64 n;  		ifscr = 1; @@ -239,7 +242,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,  	 */  	cr	= 0x00011110;  	route	= 0x0; -	if (fin != fout) { +	if (use_src) {  		route	= 0x1;  		if (rsnd_src_sync_is_enabled(mod)) { @@ -327,8 +330,8 @@ static void rsnd_src_status_clear(struct rsnd_mod *mod)  {  	u32 val = OUF_SRC(rsnd_mod_id(mod)); -	rsnd_mod_bset(mod, SCU_SYS_STATUS0, val, val); -	rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val); +	rsnd_mod_write(mod, SCU_SYS_STATUS0, val); +	rsnd_mod_write(mod, SCU_SYS_STATUS1, val);  }  static bool rsnd_src_error_occurred(struct rsnd_mod *mod) @@ -475,7 +478,7 @@ static int rsnd_src_probe_(struct rsnd_mod *mod,  			return ret;  	} -	ret = rsnd_dma_attach(io, mod, &src->dma, 0); +	ret = rsnd_dma_attach(io, mod, &src->dma);  	return ret;  } diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 6cb6db005fc4..411bda2387ad 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -417,11 +417,14 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,  	int chan = params_channels(params);  	/* -	 * Already working. -	 * It will happen if SSI has parent/child connection. +	 * snd_pcm_ops::hw_params will be called *before* +	 * snd_soc_dai_ops::trigger. Thus, ssi->usrcnt is 0 +	 * in 1st call.  	 */ -	if (ssi->usrcnt > 1) { +	if (ssi->usrcnt) {  		/* +		 * Already working. +		 * It will happen if SSI has parent/child connection.  		 * it is error if child <-> parent SSI uses  		 * different channels.  		 */ @@ -644,10 +647,14 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,  	if (ret < 0)  		return ret; -	ret = devm_request_irq(dev, ssi->irq, -			       rsnd_ssi_interrupt, -			       IRQF_SHARED, -			       dev_name(dev), mod); +	/* +	 * SSI might be called again as PIO fallback +	 * It is easy to manual handling for IRQ request/free +	 */ +	ret = request_irq(ssi->irq, +			  rsnd_ssi_interrupt, +			  IRQF_SHARED, +			  dev_name(dev), mod);  	return ret;  } @@ -669,7 +676,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,  			      struct rsnd_priv *priv)  {  	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); -	int dma_id = 0; /* not needed */  	int ret;  	/* @@ -684,7 +690,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,  		return ret;  	/* SSI probe might be called many times in MUX multi path */ -	ret = rsnd_dma_attach(io, mod, &ssi->dma, dma_id); +	ret = rsnd_dma_attach(io, mod, &ssi->dma);  	return ret;  } @@ -694,11 +700,9 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,  			       struct rsnd_priv *priv)  {  	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); -	struct device *dev = rsnd_priv_to_dev(priv); -	int irq = ssi->irq;  	/* PIO will request IRQ again */ -	devm_free_irq(dev, irq, mod); +	free_irq(ssi->irq, mod);  	return 0;  } diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 6f9b388ec5a8..4e817c8a18c0 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -33,6 +33,26 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,  	u32 mask1, val1;  	u32 mask2, val2; +	/* clear status */ +	switch (id) { +	case 0: +	case 1: +	case 2: +	case 3: +	case 4: +		rsnd_mod_write(mod, SSI_SYS_STATUS0, 0xf << (id * 4)); +		rsnd_mod_write(mod, SSI_SYS_STATUS2, 0xf << (id * 4)); +		rsnd_mod_write(mod, SSI_SYS_STATUS4, 0xf << (id * 4)); +		rsnd_mod_write(mod, SSI_SYS_STATUS6, 0xf << (id * 4)); +		break; +	case 9: +		rsnd_mod_write(mod, SSI_SYS_STATUS1, 0xf << 4); +		rsnd_mod_write(mod, SSI_SYS_STATUS3, 0xf << 4); +		rsnd_mod_write(mod, SSI_SYS_STATUS5, 0xf << 4); +		rsnd_mod_write(mod, SSI_SYS_STATUS7, 0xf << 4); +		break; +	} +  	/*  	 * SSI_MODE0  	 */ diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index bf7b52fce597..bfd71b873ca2 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -30,16 +30,26 @@ static int soc_compr_open(struct snd_compr_stream *cstream)  {  	struct snd_soc_pcm_runtime *rtd = cstream->private_data;  	struct snd_soc_platform *platform = rtd->platform; +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;  	int ret = 0;  	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); +	if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) { +		ret = cpu_dai->driver->cops->startup(cstream, cpu_dai); +		if (ret < 0) { +			dev_err(cpu_dai->dev, "Compress ASoC: can't open interface %s: %d\n", +				cpu_dai->name, ret); +			goto out; +		} +	} +  	if (platform->driver->compr_ops && platform->driver->compr_ops->open) {  		ret = platform->driver->compr_ops->open(cstream);  		if (ret < 0) {  			pr_err("compress asoc: can't open platform %s\n",  				platform->component.name); -			goto out; +			goto plat_err;  		}  	} @@ -60,6 +70,9 @@ static int soc_compr_open(struct snd_compr_stream *cstream)  machine_err:  	if (platform->driver->compr_ops && platform->driver->compr_ops->free)  		platform->driver->compr_ops->free(cstream); +plat_err: +	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) +		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);  out:  	mutex_unlock(&rtd->pcm_mutex);  	return ret; @@ -70,6 +83,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)  	struct snd_soc_pcm_runtime *fe = cstream->private_data;  	struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;  	struct snd_soc_platform *platform = fe->platform; +	struct snd_soc_dai *cpu_dai = fe->cpu_dai;  	struct snd_soc_dpcm *dpcm;  	struct snd_soc_dapm_widget_list *list;  	int stream; @@ -82,12 +96,22 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)  	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); +	if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) { +		ret = cpu_dai->driver->cops->startup(cstream, cpu_dai); +		if (ret < 0) { +			dev_err(cpu_dai->dev, "Compress ASoC: can't open interface %s: %d\n", +				cpu_dai->name, ret); +			goto out; +		} +	} + +  	if (platform->driver->compr_ops && platform->driver->compr_ops->open) {  		ret = platform->driver->compr_ops->open(cstream);  		if (ret < 0) {  			pr_err("compress asoc: can't open platform %s\n",  				platform->component.name); -			goto out; +			goto plat_err;  		}  	} @@ -144,6 +168,9 @@ fe_err:  machine_err:  	if (platform->driver->compr_ops && platform->driver->compr_ops->free)  		platform->driver->compr_ops->free(cstream); +plat_err: +	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) +		cpu_dai->driver->cops->shutdown(cstream, cpu_dai);  out:  	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;  	mutex_unlock(&fe->card->mutex); @@ -210,6 +237,9 @@ static int soc_compr_free(struct snd_compr_stream *cstream)  	if (platform->driver->compr_ops && platform->driver->compr_ops->free)  		platform->driver->compr_ops->free(cstream); +	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) +		cpu_dai->driver->cops->shutdown(cstream, cpu_dai); +  	if (cstream->direction == SND_COMPRESS_PLAYBACK) {  		if (snd_soc_runtime_ignore_pmdown_time(rtd)) {  			snd_soc_dapm_stream_event(rtd, @@ -236,6 +266,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)  {  	struct snd_soc_pcm_runtime *fe = cstream->private_data;  	struct snd_soc_platform *platform = fe->platform; +	struct snd_soc_dai *cpu_dai = fe->cpu_dai;  	struct snd_soc_dpcm *dpcm;  	int stream, ret; @@ -275,6 +306,9 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)  	if (platform->driver->compr_ops && platform->driver->compr_ops->free)  		platform->driver->compr_ops->free(cstream); +	if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) +		cpu_dai->driver->cops->shutdown(cstream, cpu_dai); +  	mutex_unlock(&fe->card->mutex);  	return 0;  } @@ -285,6 +319,7 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)  	struct snd_soc_pcm_runtime *rtd = cstream->private_data;  	struct snd_soc_platform *platform = rtd->platform;  	struct snd_soc_dai *codec_dai = rtd->codec_dai; +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;  	int ret = 0;  	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -295,6 +330,10 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)  			goto out;  	} +	if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) +		cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai); + +  	switch (cmd) {  	case SNDRV_PCM_TRIGGER_START:  		snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction); @@ -313,6 +352,7 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)  {  	struct snd_soc_pcm_runtime *fe = cstream->private_data;  	struct snd_soc_platform *platform = fe->platform; +	struct snd_soc_dai *cpu_dai = fe->cpu_dai;  	int ret = 0, stream;  	if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || @@ -332,6 +372,12 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)  	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); +	if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) { +		ret = cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai); +		if (ret < 0) +			goto out; +	} +  	if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {  		ret = platform->driver->compr_ops->trigger(cstream, cmd);  		if (ret < 0) @@ -368,6 +414,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,  {  	struct snd_soc_pcm_runtime *rtd = cstream->private_data;  	struct snd_soc_platform *platform = rtd->platform; +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;  	int ret = 0;  	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -378,6 +425,12 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,  	 * expectation is that platform and machine will configure everything  	 * for this compress path, like configuring pcm port for codec  	 */ +	if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) { +		ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai); +		if (ret < 0) +			goto err; +	} +  	if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {  		ret = platform->driver->compr_ops->set_params(cstream, params);  		if (ret < 0) @@ -416,6 +469,7 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,  	struct snd_soc_pcm_runtime *fe = cstream->private_data;  	struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;  	struct snd_soc_platform *platform = fe->platform; +	struct snd_soc_dai *cpu_dai = fe->cpu_dai;  	int ret = 0, stream;  	if (cstream->direction == SND_COMPRESS_PLAYBACK) @@ -425,6 +479,12 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,  	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); +	if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) { +		ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai); +		if (ret < 0) +			goto out; +	} +  	if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {  		ret = platform->driver->compr_ops->set_params(cstream, params);  		if (ret < 0) @@ -469,13 +529,21 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream,  {  	struct snd_soc_pcm_runtime *rtd = cstream->private_data;  	struct snd_soc_platform *platform = rtd->platform; +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;  	int ret = 0;  	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); +	if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_params) { +		ret = cpu_dai->driver->cops->get_params(cstream, params, cpu_dai); +		if (ret < 0) +			goto err; +	} +  	if (platform->driver->compr_ops && platform->driver->compr_ops->get_params)  		ret = platform->driver->compr_ops->get_params(cstream, params); +err:  	mutex_unlock(&rtd->pcm_mutex);  	return ret;  } @@ -516,13 +584,21 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)  {  	struct snd_soc_pcm_runtime *rtd = cstream->private_data;  	struct snd_soc_platform *platform = rtd->platform; +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;  	int ret = 0;  	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); +	if (cpu_dai->driver->cops && cpu_dai->driver->cops->ack) { +		ret = cpu_dai->driver->cops->ack(cstream, bytes, cpu_dai); +		if (ret < 0) +			goto err; +	} +  	if (platform->driver->compr_ops && platform->driver->compr_ops->ack)  		ret = platform->driver->compr_ops->ack(cstream, bytes); +err:  	mutex_unlock(&rtd->pcm_mutex);  	return ret;  } @@ -533,9 +609,13 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream,  	struct snd_soc_pcm_runtime *rtd = cstream->private_data;  	struct snd_soc_platform *platform = rtd->platform;  	int ret = 0; +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;  	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); +	if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer) +		cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai); +  	if (platform->driver->compr_ops && platform->driver->compr_ops->pointer)  		ret = platform->driver->compr_ops->pointer(cstream, tstamp); @@ -564,8 +644,15 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream,  {  	struct snd_soc_pcm_runtime *rtd = cstream->private_data;  	struct snd_soc_platform *platform = rtd->platform; +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;  	int ret = 0; +	if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_metadata) { +		ret = cpu_dai->driver->cops->set_metadata(cstream, metadata, cpu_dai); +		if (ret < 0) +			return ret; +	} +  	if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata)  		ret = platform->driver->compr_ops->set_metadata(cstream, metadata); @@ -577,8 +664,15 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream,  {  	struct snd_soc_pcm_runtime *rtd = cstream->private_data;  	struct snd_soc_platform *platform = rtd->platform; +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;  	int ret = 0; +	if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_metadata) { +		ret = cpu_dai->driver->cops->get_metadata(cstream, metadata, cpu_dai); +		if (ret < 0) +			return ret; +	} +  	if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata)  		ret = platform->driver->compr_ops->get_metadata(cstream, metadata); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c0bbcd903261..f1901bb1466e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -626,7 +626,7 @@ static void codec2codec_close_delayed_work(struct work_struct *work)  int snd_soc_suspend(struct device *dev)  {  	struct snd_soc_card *card = dev_get_drvdata(dev); -	struct snd_soc_codec *codec; +	struct snd_soc_component *component;  	struct snd_soc_pcm_runtime *rtd;  	int i; @@ -702,39 +702,39 @@ int snd_soc_suspend(struct device *dev)  	dapm_mark_endpoints_dirty(card);  	snd_soc_dapm_sync(&card->dapm); -	/* suspend all CODECs */ -	list_for_each_entry(codec, &card->codec_dev_list, card_list) { -		struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); +	/* suspend all COMPONENTs */ +	list_for_each_entry(component, &card->component_dev_list, card_list) { +		struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); -		/* If there are paths active then the CODEC will be held with +		/* If there are paths active then the COMPONENT will be held with  		 * bias _ON and should not be suspended. */ -		if (!codec->suspended) { +		if (!component->suspended) {  			switch (snd_soc_dapm_get_bias_level(dapm)) {  			case SND_SOC_BIAS_STANDBY:  				/* -				 * If the CODEC is capable of idle +				 * If the COMPONENT is capable of idle  				 * bias off then being in STANDBY  				 * means it's doing something,  				 * otherwise fall through.  				 */  				if (dapm->idle_bias_off) { -					dev_dbg(codec->dev, +					dev_dbg(component->dev,  						"ASoC: idle_bias_off CODEC on over suspend\n");  					break;  				}  			case SND_SOC_BIAS_OFF: -				if (codec->driver->suspend) -					codec->driver->suspend(codec); -				codec->suspended = 1; -				if (codec->component.regmap) -					regcache_mark_dirty(codec->component.regmap); +				if (component->suspend) +					component->suspend(component); +				component->suspended = 1; +				if (component->regmap) +					regcache_mark_dirty(component->regmap);  				/* deactivate pins to sleep state */ -				pinctrl_pm_select_sleep_state(codec->dev); +				pinctrl_pm_select_sleep_state(component->dev);  				break;  			default: -				dev_dbg(codec->dev, -					"ASoC: CODEC is on over suspend\n"); +				dev_dbg(component->dev, +					"ASoC: COMPONENT is on over suspend\n");  				break;  			}  		} @@ -768,7 +768,7 @@ static void soc_resume_deferred(struct work_struct *work)  	struct snd_soc_card *card =  			container_of(work, struct snd_soc_card, deferred_resume_work);  	struct snd_soc_pcm_runtime *rtd; -	struct snd_soc_codec *codec; +	struct snd_soc_component *component;  	int i;  	/* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, @@ -794,11 +794,11 @@ static void soc_resume_deferred(struct work_struct *work)  			cpu_dai->driver->resume(cpu_dai);  	} -	list_for_each_entry(codec, &card->codec_dev_list, card_list) { -		if (codec->suspended) { -			if (codec->driver->resume) -				codec->driver->resume(codec); -			codec->suspended = 0; +	list_for_each_entry(component, &card->component_dev_list, card_list) { +		if (component->suspended) { +			if (component->resume) +				component->resume(component); +			component->suspended = 0;  		}  	} @@ -972,6 +972,48 @@ struct snd_soc_dai *snd_soc_find_dai(  }  EXPORT_SYMBOL_GPL(snd_soc_find_dai); + +/** + * snd_soc_find_dai_link - Find a DAI link + * + * @card: soc card + * @id: DAI link ID to match + * @name: DAI link name to match, optional + * @stream name: DAI link stream name to match, optional + * + * This function will search all existing DAI links of the soc card to + * find the link of the same ID. Since DAI links may not have their + * unique ID, so name and stream name should also match if being + * specified. + * + * Return: pointer of DAI link, or NULL if not found. + */ +struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, +					       int id, const char *name, +					       const char *stream_name) +{ +	struct snd_soc_dai_link *link, *_link; + +	lockdep_assert_held(&client_mutex); + +	list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { +		if (link->id != id) +			continue; + +		if (name && (!link->name || strcmp(name, link->name))) +			continue; + +		if (stream_name && (!link->stream_name +			|| strcmp(stream_name, link->stream_name))) +			continue; + +		return link; +	} + +	return NULL; +} +EXPORT_SYMBOL_GPL(snd_soc_find_dai_link); +  static bool soc_is_dai_link_bound(struct snd_soc_card *card,  		struct snd_soc_dai_link *dai_link)  { @@ -993,6 +1035,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card,  	struct snd_soc_dai_link_component cpu_dai_component;  	struct snd_soc_dai **codec_dais;  	struct snd_soc_platform *platform; +	struct device_node *platform_of_node;  	const char *platform_name;  	int i; @@ -1042,9 +1085,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card,  	/* find one from the set of registered platforms */  	list_for_each_entry(platform, &platform_list, list) { +		platform_of_node = platform->dev->of_node; +		if (!platform_of_node && platform->dev->parent->of_node) +			platform_of_node = platform->dev->parent->of_node; +  		if (dai_link->platform_of_node) { -			if (platform->dev->of_node != -			    dai_link->platform_of_node) +			if (platform_of_node != dai_link->platform_of_node)  				continue;  		} else {  			if (strcmp(platform->component.name, platform_name)) @@ -1072,9 +1118,7 @@ static void soc_remove_component(struct snd_soc_component *component)  	if (!component->card)  		return; -	/* This is a HACK and will be removed soon */ -	if (component->codec) -		list_del(&component->codec->card_list); +	list_del(&component->card_list);  	if (component->remove)  		component->remove(component); @@ -1443,10 +1487,7 @@ static int soc_probe_component(struct snd_soc_card *card,  					component->num_dapm_routes);  	list_add(&dapm->list, &card->dapm_list); - -	/* This is a HACK and will be removed soon */ -	if (component->codec) -		list_add(&component->codec->card_list, &card->codec_dev_list); +	list_add(&component->card_list, &card->component_dev_list);  	return 0; @@ -1706,7 +1747,8 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num)  	}  	component->init = aux_dev->init; -	list_add(&component->list_aux, &card->aux_comp_list); +	component->auxiliary = 1; +  	return 0;  err_defer: @@ -1722,7 +1764,10 @@ static int soc_probe_aux_devices(struct snd_soc_card *card)  	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;  		order++) { -		list_for_each_entry(comp, &card->aux_comp_list, list_aux) { +		list_for_each_entry(comp, &card->component_dev_list, card_list) { +			if (!comp->auxiliary) +				continue; +  			if (comp->driver->probe_order == order) {  				ret = soc_probe_component(card,	comp);  				if (ret < 0) { @@ -1746,11 +1791,14 @@ static void soc_remove_aux_devices(struct snd_soc_card *card)  	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;  		order++) {  		list_for_each_entry_safe(comp, _comp, -			&card->aux_comp_list, list_aux) { +			&card->component_dev_list, card_list) { + +			if (!comp->auxiliary) +				continue; +  			if (comp->driver->remove_order == order) {  				soc_remove_component(comp); -				/* remove it from the card's aux_comp_list */ -				list_del(&comp->list_aux); +				comp->auxiliary = 0;  			}  		}  	} @@ -2926,6 +2974,8 @@ static int snd_soc_component_initialize(struct snd_soc_component *component,  	component->driver = driver;  	component->probe = component->driver->probe;  	component->remove = component->driver->remove; +	component->suspend = component->driver->suspend; +	component->resume = component->driver->resume;  	dapm = &component->dapm;  	dapm->dev = dev; @@ -3275,6 +3325,20 @@ static void snd_soc_codec_drv_remove(struct snd_soc_component *component)  	codec->driver->remove(codec);  } +static int snd_soc_codec_drv_suspend(struct snd_soc_component *component) +{ +	struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + +	return codec->driver->suspend(codec); +} + +static int snd_soc_codec_drv_resume(struct snd_soc_component *component) +{ +	struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + +	return codec->driver->resume(codec); +} +  static int snd_soc_codec_drv_write(struct snd_soc_component *component,  	unsigned int reg, unsigned int val)  { @@ -3336,6 +3400,10 @@ int snd_soc_register_codec(struct device *dev,  		codec->component.probe = snd_soc_codec_drv_probe;  	if (codec_drv->remove)  		codec->component.remove = snd_soc_codec_drv_remove; +	if (codec_drv->suspend) +		codec->component.suspend = snd_soc_codec_drv_suspend; +	if (codec_drv->resume) +		codec->component.resume = snd_soc_codec_drv_resume;  	if (codec_drv->write)  		codec->component.write = snd_soc_codec_drv_write;  	if (codec_drv->read) @@ -3424,10 +3492,10 @@ found:  EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);  /* Retrieve a card's name from device tree */ -int snd_soc_of_parse_card_name(struct snd_soc_card *card, -			       const char *propname) +int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card, +					 struct device_node *np, +					 const char *propname)  { -	struct device_node *np;  	int ret;  	if (!card->dev) { @@ -3435,7 +3503,8 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card,  		return -EINVAL;  	} -	np = card->dev->of_node; +	if (!np) +		np = card->dev->of_node;  	ret = of_property_read_string_index(np, propname, 0, &card->name);  	/* @@ -3452,7 +3521,7 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card,  	return 0;  } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name_from_node);  static const struct snd_soc_dapm_widget simple_widgets[] = {  	SND_SOC_DAPM_MIC("Microphone", NULL), @@ -3461,14 +3530,17 @@ static const struct snd_soc_dapm_widget simple_widgets[] = {  	SND_SOC_DAPM_SPK("Speaker", NULL),  }; -int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, +int snd_soc_of_parse_audio_simple_widgets_from_node(struct snd_soc_card *card, +					  struct device_node *np,  					  const char *propname)  { -	struct device_node *np = card->dev->of_node;  	struct snd_soc_dapm_widget *widgets;  	const char *template, *wname;  	int i, j, num_widgets, ret; +	if (!np) +		np = card->dev->of_node; +  	num_widgets = of_property_count_strings(np, propname);  	if (num_widgets < 0) {  		dev_err(card->dev, @@ -3539,7 +3611,7 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,  	return 0;  } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets_from_node);  static int snd_soc_of_get_slot_mask(struct device_node *np,  				    const char *prop_name, @@ -3595,15 +3667,18 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,  }  EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); -void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, +void snd_soc_of_parse_audio_prefix_from_node(struct snd_soc_card *card, +				   struct device_node *np,  				   struct snd_soc_codec_conf *codec_conf,  				   struct device_node *of_node,  				   const char *propname)  { -	struct device_node *np = card->dev->of_node;  	const char *str;  	int ret; +	if (!np) +		np = card->dev->of_node; +  	ret = of_property_read_string(np, propname, &str);  	if (ret < 0) {  		/* no prefix is not error */ @@ -3613,16 +3688,19 @@ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,  	codec_conf->of_node	= of_node;  	codec_conf->name_prefix	= str;  } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix_from_node); -int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, +int snd_soc_of_parse_audio_routing_from_node(struct snd_soc_card *card, +				   struct device_node *np,  				   const char *propname)  { -	struct device_node *np = card->dev->of_node;  	int num_routes;  	struct snd_soc_dapm_route *routes;  	int i, ret; +	if (!np) +		np = card->dev->of_node; +  	num_routes = of_property_count_strings(np, propname);  	if (num_routes < 0 || num_routes & 1) {  		dev_err(card->dev, @@ -3669,7 +3747,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,  	return 0;  } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing_from_node);  unsigned int snd_soc_of_parse_daifmt(struct device_node *np,  				     const char *prefix, @@ -3784,7 +3862,7 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,  }  EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); -static int snd_soc_get_dai_name(struct of_phandle_args *args, +int snd_soc_get_dai_name(struct of_phandle_args *args,  				const char **dai_name)  {  	struct snd_soc_component *pos; @@ -3836,6 +3914,7 @@ static int snd_soc_get_dai_name(struct of_phandle_args *args,  	mutex_unlock(&client_mutex);  	return ret;  } +EXPORT_SYMBOL_GPL(snd_soc_get_dai_name);  int snd_soc_of_get_dai_name(struct device_node *of_node,  			    const char **dai_name) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 3bbe32ee4630..27dd02e57b31 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -330,6 +330,11 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,  	case snd_soc_dapm_mixer_named_ctl:  		mc = (struct soc_mixer_control *)kcontrol->private_value; +		if (mc->autodisable && snd_soc_volsw_is_stereo(mc)) +			dev_warn(widget->dapm->dev, +				 "ASoC: Unsupported stereo autodisable control '%s'\n", +				 ctrl_name); +  		if (mc->autodisable) {  			struct snd_soc_dapm_widget template; @@ -723,7 +728,8 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,  }  /* set up initial codec paths */ -static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i) +static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i, +				       int nth_path)  {  	struct soc_mixer_control *mc = (struct soc_mixer_control *)  		p->sink->kcontrol_news[i].private_value; @@ -736,7 +742,25 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i)  	if (reg != SND_SOC_NOPM) {  		soc_dapm_read(p->sink->dapm, reg, &val); -		val = (val >> shift) & mask; +		/* +		 * The nth_path argument allows this function to know +		 * which path of a kcontrol it is setting the initial +		 * status for. Ideally this would support any number +		 * of paths and channels. But since kcontrols only come +		 * in mono and stereo variants, we are limited to 2 +		 * channels. +		 * +		 * The following code assumes for stereo controls the +		 * first path is the left channel, and all remaining +		 * paths are the right channel. +		 */ +		if (snd_soc_volsw_is_stereo(mc) && nth_path > 0) { +			if (reg != mc->rreg) +				soc_dapm_read(p->sink->dapm, mc->rreg, &val); +			val = (val >> mc->rshift) & mask; +		} else { +			val = (val >> shift) & mask; +		}  		if (invert)  			val = max - val;  		p->connect = !!val; @@ -749,13 +773,13 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i)  static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,  	struct snd_soc_dapm_path *path, const char *control_name)  { -	int i; +	int i, nth_path = 0;  	/* search for mixer kcontrol */  	for (i = 0; i < path->sink->num_kcontrols; i++) {  		if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {  			path->name = path->sink->kcontrol_news[i].name; -			dapm_set_mixer_path_status(path, i); +			dapm_set_mixer_path_status(path, i, nth_path++);  			return 0;  		}  	} @@ -1626,6 +1650,15 @@ static void dapm_widget_update(struct snd_soc_card *card)  		dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",  			w->name, ret); +	if (update->has_second_set) { +		ret = soc_dapm_update_bits(w->dapm, update->reg2, +					   update->mask2, update->val2); +		if (ret < 0) +			dev_err(w->dapm->dev, +				"ASoC: %s DAPM update failed: %d\n", +				w->name, ret); +	} +  	for (wi = 0; wi < wlist->num_widgets; wi++) {  		w = wlist->widgets[wi]; @@ -2177,7 +2210,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);  /* test and update the power status of a mixer or switch widget */  static int soc_dapm_mixer_update_power(struct snd_soc_card *card, -				   struct snd_kcontrol *kcontrol, int connect) +				       struct snd_kcontrol *kcontrol, +				       int connect, int rconnect)  {  	struct snd_soc_dapm_path *path;  	int found = 0; @@ -2186,8 +2220,33 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card,  	/* find dapm widget path assoc with kcontrol */  	dapm_kcontrol_for_each_path(path, kcontrol) { +		/* +		 * Ideally this function should support any number of +		 * paths and channels. But since kcontrols only come +		 * in mono and stereo variants, we are limited to 2 +		 * channels. +		 * +		 * The following code assumes for stereo controls the +		 * first path (when 'found == 0') is the left channel, +		 * and all remaining paths (when 'found == 1') are the +		 * right channel. +		 * +		 * A stereo control is signified by a valid 'rconnect' +		 * value, either 0 for unconnected, or >= 0 for connected. +		 * This is chosen instead of using snd_soc_volsw_is_stereo, +		 * so that the behavior of snd_soc_dapm_mixer_update_power +		 * doesn't change even when the kcontrol passed in is +		 * stereo. +		 * +		 * It passes 'connect' as the path connect status for +		 * the left channel, and 'rconnect' for the right +		 * channel. +		 */ +		if (found && rconnect >= 0) +			soc_dapm_connect_path(path, rconnect, "mixer update"); +		else +			soc_dapm_connect_path(path, connect, "mixer update");  		found = 1; -		soc_dapm_connect_path(path, connect, "mixer update");  	}  	if (found) @@ -2205,7 +2264,7 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,  	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);  	card->update = update; -	ret = soc_dapm_mixer_update_power(card, kcontrol, connect); +	ret = soc_dapm_mixer_update_power(card, kcontrol, connect, -1);  	card->update = NULL;  	mutex_unlock(&card->dapm_mutex);  	if (ret > 0) @@ -3030,22 +3089,28 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,  	int reg = mc->reg;  	unsigned int shift = mc->shift;  	int max = mc->max; +	unsigned int width = fls(max);  	unsigned int mask = (1 << fls(max)) - 1;  	unsigned int invert = mc->invert; -	unsigned int val; +	unsigned int reg_val, val, rval = 0;  	int ret = 0; -	if (snd_soc_volsw_is_stereo(mc)) -		dev_warn(dapm->dev, -			 "ASoC: Control '%s' is stereo, which is not supported\n", -			 kcontrol->id.name); -  	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);  	if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) { -		ret = soc_dapm_read(dapm, reg, &val); -		val = (val >> shift) & mask; +		ret = soc_dapm_read(dapm, reg, ®_val); +		val = (reg_val >> shift) & mask; + +		if (ret == 0 && reg != mc->rreg) +			ret = soc_dapm_read(dapm, mc->rreg, ®_val); + +		if (snd_soc_volsw_is_stereo(mc)) +			rval = (reg_val >> mc->rshift) & mask;  	} else { -		val = dapm_kcontrol_get_value(kcontrol); +		reg_val = dapm_kcontrol_get_value(kcontrol); +		val = reg_val & mask; + +		if (snd_soc_volsw_is_stereo(mc)) +			rval = (reg_val >> width) & mask;  	}  	mutex_unlock(&card->dapm_mutex); @@ -3057,6 +3122,13 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,  	else  		ucontrol->value.integer.value[0] = val; +	if (snd_soc_volsw_is_stereo(mc)) { +		if (invert) +			ucontrol->value.integer.value[1] = max - rval; +		else +			ucontrol->value.integer.value[1] = rval; +	} +  	return ret;  }  EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); @@ -3080,46 +3152,66 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,  	int reg = mc->reg;  	unsigned int shift = mc->shift;  	int max = mc->max; -	unsigned int mask = (1 << fls(max)) - 1; +	unsigned int width = fls(max); +	unsigned int mask = (1 << width) - 1;  	unsigned int invert = mc->invert; -	unsigned int val; -	int connect, change, reg_change = 0; -	struct snd_soc_dapm_update update; +	unsigned int val, rval = 0; +	int connect, rconnect = -1, change, reg_change = 0; +	struct snd_soc_dapm_update update = { NULL };  	int ret = 0; -	if (snd_soc_volsw_is_stereo(mc)) -		dev_warn(dapm->dev, -			 "ASoC: Control '%s' is stereo, which is not supported\n", -			 kcontrol->id.name); -  	val = (ucontrol->value.integer.value[0] & mask);  	connect = !!val;  	if (invert)  		val = max - val; +	if (snd_soc_volsw_is_stereo(mc)) { +		rval = (ucontrol->value.integer.value[1] & mask); +		rconnect = !!rval; +		if (invert) +			rval = max - rval; +	} +  	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); -	change = dapm_kcontrol_set_value(kcontrol, val); +	/* This assumes field width < (bits in unsigned int / 2) */ +	if (width > sizeof(unsigned int) * 8 / 2) +		dev_warn(dapm->dev, +			 "ASoC: control %s field width limit exceeded\n", +			 kcontrol->id.name); +	change = dapm_kcontrol_set_value(kcontrol, val | (rval << width));  	if (reg != SND_SOC_NOPM) { -		mask = mask << shift;  		val = val << shift; +		rval = rval << mc->rshift; + +		reg_change = soc_dapm_test_bits(dapm, reg, mask << shift, val); -		reg_change = soc_dapm_test_bits(dapm, reg, mask, val); +		if (snd_soc_volsw_is_stereo(mc)) +			reg_change |= soc_dapm_test_bits(dapm, mc->rreg, +							 mask << mc->rshift, +							 rval);  	}  	if (change || reg_change) {  		if (reg_change) { +			if (snd_soc_volsw_is_stereo(mc)) { +				update.has_second_set = true; +				update.reg2 = mc->rreg; +				update.mask2 = mask << mc->rshift; +				update.val2 = rval; +			}  			update.kcontrol = kcontrol;  			update.reg = reg; -			update.mask = mask; +			update.mask = mask << shift;  			update.val = val;  			card->update = &update;  		}  		change |= reg_change; -		ret = soc_dapm_mixer_update_power(card, kcontrol, connect); +		ret = soc_dapm_mixer_update_power(card, kcontrol, connect, +						  rconnect);  		card->update = NULL;  	} @@ -3192,7 +3284,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,  	unsigned int *item = ucontrol->value.enumerated.item;  	unsigned int val, change, reg_change = 0;  	unsigned int mask; -	struct snd_soc_dapm_update update; +	struct snd_soc_dapm_update update = { NULL };  	int ret = 0;  	if (item[0] >= e->items) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 6cef3977507a..17eb14935577 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -263,7 +263,6 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)  	struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);  	const struct snd_dmaengine_pcm_config *config = pcm->config;  	struct device *dev = rtd->platform->dev; -	struct snd_dmaengine_dai_dma_data *dma_data;  	struct snd_pcm_substream *substream;  	size_t prealloc_buffer_size;  	size_t max_buffer_size; @@ -278,19 +277,11 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)  		max_buffer_size = SIZE_MAX;  	} -  	for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {  		substream = rtd->pcm->streams[i].substream;  		if (!substream)  			continue; -		dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - -		if (!pcm->chan[i] && -		    (pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) -			pcm->chan[i] = dma_request_slave_channel(dev, -				dma_data->chan_name); -  		if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) {  			pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd,  				substream); @@ -359,9 +350,7 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm,  	const char *name;  	struct dma_chan *chan; -	if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT | -			   SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) || -	    !dev->of_node) +	if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_DT) || !dev->of_node)  		return 0;  	if (config && config->dma_dev) { diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index d56a16a0f6fa..e7a1eaa2772f 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2882,7 +2882,7 @@ int snd_soc_platform_trigger(struct snd_pcm_substream *substream,  EXPORT_SYMBOL_GPL(snd_soc_platform_trigger);  #ifdef CONFIG_DEBUG_FS -static char *dpcm_state_string(enum snd_soc_dpcm_state state) +static const char *dpcm_state_string(enum snd_soc_dpcm_state state)  {  	switch (state) {  	case SND_SOC_DPCM_STATE_NEW: diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 6b05047a4134..65670b2b408c 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -49,10 +49,68 @@  #define SOC_TPLG_PASS_GRAPH		5  #define SOC_TPLG_PASS_PINS		6  #define SOC_TPLG_PASS_BE_DAI		7 +#define SOC_TPLG_PASS_LINK		8  #define SOC_TPLG_PASS_START	SOC_TPLG_PASS_MANIFEST -#define SOC_TPLG_PASS_END	SOC_TPLG_PASS_BE_DAI +#define SOC_TPLG_PASS_END	SOC_TPLG_PASS_LINK +/* + * Old version of ABI structs, supported for backward compatibility. + */ + +/* Manifest v4 */ +struct snd_soc_tplg_manifest_v4 { +	__le32 size;		/* in bytes of this structure */ +	__le32 control_elems;	/* number of control elements */ +	__le32 widget_elems;	/* number of widget elements */ +	__le32 graph_elems;	/* number of graph elements */ +	__le32 pcm_elems;	/* number of PCM elements */ +	__le32 dai_link_elems;	/* number of DAI link elements */ +	struct snd_soc_tplg_private priv; +} __packed; + +/* Stream Capabilities v4 */ +struct snd_soc_tplg_stream_caps_v4 { +	__le32 size;		/* in bytes of this structure */ +	char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; +	__le64 formats;	/* supported formats SNDRV_PCM_FMTBIT_* */ +	__le32 rates;		/* supported rates SNDRV_PCM_RATE_* */ +	__le32 rate_min;	/* min rate */ +	__le32 rate_max;	/* max rate */ +	__le32 channels_min;	/* min channels */ +	__le32 channels_max;	/* max channels */ +	__le32 periods_min;	/* min number of periods */ +	__le32 periods_max;	/* max number of periods */ +	__le32 period_size_min;	/* min period size bytes */ +	__le32 period_size_max;	/* max period size bytes */ +	__le32 buffer_size_min;	/* min buffer size bytes */ +	__le32 buffer_size_max;	/* max buffer size bytes */ +} __packed; + +/* PCM v4 */ +struct snd_soc_tplg_pcm_v4 { +	__le32 size;		/* in bytes of this structure */ +	char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; +	char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; +	__le32 pcm_id;		/* unique ID - used to match with DAI link */ +	__le32 dai_id;		/* unique ID - used to match */ +	__le32 playback;	/* supports playback mode */ +	__le32 capture;		/* supports capture mode */ +	__le32 compress;	/* 1 = compressed; 0 = PCM */ +	struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* for DAI link */ +	__le32 num_streams;	/* number of streams */ +	struct snd_soc_tplg_stream_caps_v4 caps[2]; /* playback and capture for DAI */ +} __packed; + +/* Physical link config v4 */ +struct snd_soc_tplg_link_config_v4 { +	__le32 size;            /* in bytes of this structure */ +	__le32 id;              /* unique ID - used to match */ +	struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* supported configs playback and captrure */ +	__le32 num_streams;     /* number of streams */ +} __packed; + +/* topology context */  struct soc_tplg {  	const struct firmware *fw; @@ -428,33 +486,41 @@ static void remove_widget(struct snd_soc_component *comp,  		dobj->ops->widget_unload(comp, dobj);  	/* -	 * Dynamic Widgets either have 1 enum kcontrol or 1..N mixers. +	 * Dynamic Widgets either have 1..N enum kcontrols or mixers.  	 * The enum may either have an array of values or strings.  	 */ -	if (dobj->widget.kcontrol_enum) { +	if (dobj->widget.kcontrol_type == SND_SOC_TPLG_TYPE_ENUM) {  		/* enumerated widget mixer */ -		struct soc_enum *se = -			(struct soc_enum *)w->kcontrols[0]->private_value; +		for (i = 0; i < w->num_kcontrols; i++) { +			struct snd_kcontrol *kcontrol = w->kcontrols[i]; +			struct soc_enum *se = +				(struct soc_enum *)kcontrol->private_value; -		snd_ctl_remove(card, w->kcontrols[0]); +			snd_ctl_remove(card, kcontrol); -		kfree(se->dobj.control.dvalues); -		for (i = 0; i < se->items; i++) -			kfree(se->dobj.control.dtexts[i]); +			kfree(se->dobj.control.dvalues); +			for (i = 0; i < se->items; i++) +				kfree(se->dobj.control.dtexts[i]); -		kfree(se); +			kfree(se); +		}  		kfree(w->kcontrol_news);  	} else { -		/* non enumerated widget mixer */ +		/* volume mixer or bytes controls */  		for (i = 0; i < w->num_kcontrols; i++) {  			struct snd_kcontrol *kcontrol = w->kcontrols[i]; -			struct soc_mixer_control *sm = -			(struct soc_mixer_control *) kcontrol->private_value; -			kfree(w->kcontrols[i]->tlv.p); +			if (dobj->widget.kcontrol_type +			    == SND_SOC_TPLG_TYPE_MIXER) +				kfree(kcontrol->tlv.p); -			snd_ctl_remove(card, w->kcontrols[i]); -			kfree(sm); +			snd_ctl_remove(card, kcontrol); + +			/* Private value is used as struct soc_mixer_control +			 * for volume mixers or soc_bytes_ext for bytes +			 * controls. +			 */ +			kfree((void *)kcontrol->private_value);  		}  		kfree(w->kcontrol_news);  	} @@ -474,6 +540,7 @@ static void remove_dai(struct snd_soc_component *comp,  	if (dobj->ops && dobj->ops->dai_unload)  		dobj->ops->dai_unload(comp, dobj); +	kfree(dai_drv->name);  	list_del(&dobj->list);  	kfree(dai_drv);  } @@ -491,6 +558,10 @@ static void remove_link(struct snd_soc_component *comp,  	if (dobj->ops && dobj->ops->link_unload)  		dobj->ops->link_unload(comp, dobj); +	kfree(link->name); +	kfree(link->stream_name); +	kfree(link->cpu_dai_name); +  	list_del(&dobj->list);  	snd_soc_remove_dai_link(comp->card, link);  	kfree(link); @@ -1193,98 +1264,105 @@ err:  }  static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( -	struct soc_tplg *tplg) +	struct soc_tplg *tplg, int num_kcontrols)  {  	struct snd_kcontrol_new *kc;  	struct snd_soc_tplg_enum_control *ec;  	struct soc_enum *se; -	int i, err; - -	ec = (struct snd_soc_tplg_enum_control *)tplg->pos; -	tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + -		ec->priv.size); +	int i, j, err; -	/* validate kcontrol */ -	if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == -		SNDRV_CTL_ELEM_ID_NAME_MAXLEN) -		return NULL; - -	kc = kzalloc(sizeof(*kc), GFP_KERNEL); +	kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL);  	if (kc == NULL)  		return NULL; -	se = kzalloc(sizeof(*se), GFP_KERNEL); -	if (se == NULL) -		goto err; +	for (i = 0; i < num_kcontrols; i++) { +		ec = (struct snd_soc_tplg_enum_control *)tplg->pos; +		/* validate kcontrol */ +		if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == +			    SNDRV_CTL_ELEM_ID_NAME_MAXLEN) +			return NULL; -	dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n", -		ec->hdr.name); +		se = kzalloc(sizeof(*se), GFP_KERNEL); +		if (se == NULL) +			goto err; -	kc->name = ec->hdr.name; -	kc->private_value = (long)se; -	kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; -	kc->access = ec->hdr.access; +		dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n", +			ec->hdr.name); + +		kc[i].name = ec->hdr.name; +		kc[i].private_value = (long)se; +		kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; +		kc[i].access = ec->hdr.access; -	/* we only support FL/FR channel mapping atm */ -	se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); -	se->shift_l = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FL); -	se->shift_r = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FR); +		/* we only support FL/FR channel mapping atm */ +		se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); +		se->shift_l = tplc_chan_get_shift(tplg, ec->channel, +						  SNDRV_CHMAP_FL); +		se->shift_r = tplc_chan_get_shift(tplg, ec->channel, +						  SNDRV_CHMAP_FR); -	se->items = ec->items; -	se->mask = ec->mask; -	se->dobj.index = tplg->index; +		se->items = ec->items; +		se->mask = ec->mask; +		se->dobj.index = tplg->index; -	switch (ec->hdr.ops.info) { -	case SND_SOC_TPLG_CTL_ENUM_VALUE: -	case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: -		err = soc_tplg_denum_create_values(se, ec); -		if (err < 0) { -			dev_err(tplg->dev, "ASoC: could not create values for %s\n", -				ec->hdr.name); +		switch (ec->hdr.ops.info) { +		case SND_SOC_TPLG_CTL_ENUM_VALUE: +		case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: +			err = soc_tplg_denum_create_values(se, ec); +			if (err < 0) { +				dev_err(tplg->dev, "ASoC: could not create values for %s\n", +					ec->hdr.name); +				goto err_se; +			} +			/* fall through to create texts */ +		case SND_SOC_TPLG_CTL_ENUM: +		case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: +		case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: +			err = soc_tplg_denum_create_texts(se, ec); +			if (err < 0) { +				dev_err(tplg->dev, "ASoC: could not create texts for %s\n", +					ec->hdr.name); +				goto err_se; +			} +			break; +		default: +			dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n", +				ec->hdr.ops.info, ec->hdr.name);  			goto err_se;  		} -		/* fall through to create texts */ -	case SND_SOC_TPLG_CTL_ENUM: -	case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: -	case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: -		err = soc_tplg_denum_create_texts(se, ec); + +		/* map io handlers */ +		err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc[i], tplg); +		if (err) { +			soc_control_err(tplg, &ec->hdr, ec->hdr.name); +			goto err_se; +		} + +		/* pass control to driver for optional further init */ +		err = soc_tplg_init_kcontrol(tplg, &kc[i], +			(struct snd_soc_tplg_ctl_hdr *)ec);  		if (err < 0) { -			dev_err(tplg->dev, "ASoC: could not create texts for %s\n", +			dev_err(tplg->dev, "ASoC: failed to init %s\n",  				ec->hdr.name);  			goto err_se;  		} -		break; -	default: -		dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n", -			ec->hdr.ops.info, ec->hdr.name); -		goto err_se; -	} -	/* map io handlers */ -	err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg); -	if (err) { -		soc_control_err(tplg, &ec->hdr, ec->hdr.name); -		goto err_se; -	} - -	/* pass control to driver for optional further init */ -	err = soc_tplg_init_kcontrol(tplg, kc, -		(struct snd_soc_tplg_ctl_hdr *)ec); -	if (err < 0) { -		dev_err(tplg->dev, "ASoC: failed to init %s\n", -			ec->hdr.name); -		goto err_se; +		tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + +				ec->priv.size);  	}  	return kc;  err_se: -	/* free values and texts */ -	kfree(se->dobj.control.dvalues); -	for (i = 0; i < ec->items; i++) -		kfree(se->dobj.control.dtexts[i]); +	for (; i >= 0; i--) { +		/* free values and texts */ +		se = (struct soc_enum *)kc[i].private_value; +		kfree(se->dobj.control.dvalues); +		for (j = 0; j < ec->items; j++) +			kfree(se->dobj.control.dtexts[j]); -	kfree(se); +		kfree(se); +	}  err:  	kfree(kc); @@ -1366,6 +1444,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,  	struct snd_soc_dapm_widget template, *widget;  	struct snd_soc_tplg_ctl_hdr *control_hdr;  	struct snd_soc_card *card = tplg->comp->card; +	unsigned int kcontrol_type;  	int ret = 0;  	if (strnlen(w->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == @@ -1406,6 +1485,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,  	tplg->pos +=  		(sizeof(struct snd_soc_tplg_dapm_widget) + w->priv.size);  	if (w->num_kcontrols == 0) { +		kcontrol_type = 0;  		template.num_kcontrols = 0;  		goto widget;  	} @@ -1421,6 +1501,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,  	case SND_SOC_TPLG_CTL_VOLSW_XR_SX:  	case SND_SOC_TPLG_CTL_RANGE:  	case SND_SOC_TPLG_DAPM_CTL_VOLSW: +		kcontrol_type = SND_SOC_TPLG_TYPE_MIXER;  /* volume mixer */  		template.num_kcontrols = w->num_kcontrols;  		template.kcontrol_news =  			soc_tplg_dapm_widget_dmixer_create(tplg, @@ -1435,16 +1516,18 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,  	case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:  	case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:  	case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: -		template.dobj.widget.kcontrol_enum = 1; -		template.num_kcontrols = 1; +		kcontrol_type = SND_SOC_TPLG_TYPE_ENUM;	/* enumerated mixer */ +		template.num_kcontrols = w->num_kcontrols;  		template.kcontrol_news = -			soc_tplg_dapm_widget_denum_create(tplg); +			soc_tplg_dapm_widget_denum_create(tplg, +			template.num_kcontrols);  		if (!template.kcontrol_news) {  			ret = -ENOMEM;  			goto hdr_err;  		}  		break;  	case SND_SOC_TPLG_CTL_BYTES: +		kcontrol_type = SND_SOC_TPLG_TYPE_BYTES; /* bytes control */  		template.num_kcontrols = w->num_kcontrols;  		template.kcontrol_news =  			soc_tplg_dapm_widget_dbytes_create(tplg, @@ -1481,6 +1564,7 @@ widget:  	}  	widget->dobj.type = SND_SOC_DOBJ_WIDGET; +	widget->dobj.widget.kcontrol_type = kcontrol_type;  	widget->dobj.ops = tplg->ops;  	widget->dobj.index = tplg->index;  	kfree(template.sname); @@ -1589,7 +1673,8 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,  	if (dai_drv == NULL)  		return -ENOMEM; -	dai_drv->name = pcm->dai_name; +	if (strlen(pcm->dai_name)) +		dai_drv->name = kstrdup(pcm->dai_name, GFP_KERNEL);  	dai_drv->id = pcm->dai_id;  	if (pcm->playback) { @@ -1621,8 +1706,31 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,  	return snd_soc_register_dai(tplg->comp, dai_drv);  } +static void set_link_flags(struct snd_soc_dai_link *link, +		unsigned int flag_mask, unsigned int flags) +{ +	if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES) +		link->symmetric_rates = +			flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES ? 1 : 0; + +	if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS) +		link->symmetric_channels = +			flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS ? +			1 : 0; + +	if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS) +		link->symmetric_samplebits = +			flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS ? +			1 : 0; + +	if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP) +		link->ignore_suspend = +		flags & SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP ? +		1 : 0; +} +  /* create the FE DAI link */ -static int soc_tplg_link_create(struct soc_tplg *tplg, +static int soc_tplg_fe_link_create(struct soc_tplg *tplg,  	struct snd_soc_tplg_pcm *pcm)  {  	struct snd_soc_dai_link *link; @@ -1632,11 +1740,15 @@ static int soc_tplg_link_create(struct soc_tplg *tplg,  	if (link == NULL)  		return -ENOMEM; -	link->name = pcm->pcm_name; -	link->stream_name = pcm->pcm_name; +	if (strlen(pcm->pcm_name)) { +		link->name = kstrdup(pcm->pcm_name, GFP_KERNEL); +		link->stream_name = kstrdup(pcm->pcm_name, GFP_KERNEL); +	}  	link->id = pcm->pcm_id; -	link->cpu_dai_name = pcm->dai_name; +	if (strlen(pcm->dai_name)) +		link->cpu_dai_name = kstrdup(pcm->dai_name, GFP_KERNEL); +  	link->codec_name = "snd-soc-dummy";  	link->codec_dai_name = "snd-soc-dummy-dai"; @@ -1644,6 +1756,8 @@ static int soc_tplg_link_create(struct soc_tplg *tplg,  	link->dynamic = 1;  	link->dpcm_playback = pcm->playback;  	link->dpcm_capture = pcm->capture; +	if (pcm->flag_mask) +		set_link_flags(link, pcm->flag_mask, pcm->flags);  	/* pass control to component driver for optional further init */  	ret = soc_tplg_dai_link_load(tplg, link); @@ -1672,55 +1786,351 @@ static int soc_tplg_pcm_create(struct soc_tplg *tplg,  	if (ret < 0)  		return ret; -	return  soc_tplg_link_create(tplg, pcm); +	return  soc_tplg_fe_link_create(tplg, pcm); +} + +/* copy stream caps from the old version 4 of source */ +static void stream_caps_new_ver(struct snd_soc_tplg_stream_caps *dest, +				struct snd_soc_tplg_stream_caps_v4 *src) +{ +	dest->size = sizeof(*dest); +	memcpy(dest->name, src->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); +	dest->formats = src->formats; +	dest->rates = src->rates; +	dest->rate_min = src->rate_min; +	dest->rate_max = src->rate_max; +	dest->channels_min = src->channels_min; +	dest->channels_max = src->channels_max; +	dest->periods_min = src->periods_min; +	dest->periods_max = src->periods_max; +	dest->period_size_min = src->period_size_min; +	dest->period_size_max = src->period_size_max; +	dest->buffer_size_min = src->buffer_size_min; +	dest->buffer_size_max = src->buffer_size_max; +} + +/** + * pcm_new_ver - Create the new version of PCM from the old version. + * @tplg: topology context + * @src: older version of pcm as a source + * @pcm: latest version of pcm created from the source + * + * Support from vesion 4. User should free the returned pcm manually. + */ +static int pcm_new_ver(struct soc_tplg *tplg, +		       struct snd_soc_tplg_pcm *src, +		       struct snd_soc_tplg_pcm **pcm) +{ +	struct snd_soc_tplg_pcm *dest; +	struct snd_soc_tplg_pcm_v4 *src_v4; +	int i; + +	*pcm = NULL; + +	if (src->size != sizeof(*src_v4)) { +		dev_err(tplg->dev, "ASoC: invalid PCM size\n"); +		return -EINVAL; +	} + +	dev_warn(tplg->dev, "ASoC: old version of PCM\n"); +	src_v4 = (struct snd_soc_tplg_pcm_v4 *)src; +	dest = kzalloc(sizeof(*dest), GFP_KERNEL); +	if (!dest) +		return -ENOMEM; + +	dest->size = sizeof(*dest);	/* size of latest abi version */ +	memcpy(dest->pcm_name, src_v4->pcm_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); +	memcpy(dest->dai_name, src_v4->dai_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); +	dest->pcm_id = src_v4->pcm_id; +	dest->dai_id = src_v4->dai_id; +	dest->playback = src_v4->playback; +	dest->capture = src_v4->capture; +	dest->compress = src_v4->compress; +	dest->num_streams = src_v4->num_streams; +	for (i = 0; i < dest->num_streams; i++) +		memcpy(&dest->stream[i], &src_v4->stream[i], +		       sizeof(struct snd_soc_tplg_stream)); + +	for (i = 0; i < 2; i++) +		stream_caps_new_ver(&dest->caps[i], &src_v4->caps[i]); + +	*pcm = dest; +	return 0;  }  static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,  	struct snd_soc_tplg_hdr *hdr)  { -	struct snd_soc_tplg_pcm *pcm; +	struct snd_soc_tplg_pcm *pcm, *_pcm;  	int count = hdr->count; -	int i; +	int i, err; +	bool abi_match;  	if (tplg->pass != SOC_TPLG_PASS_PCM_DAI)  		return 0; +	/* check the element size and count */ +	pcm = (struct snd_soc_tplg_pcm *)tplg->pos; +	if (pcm->size > sizeof(struct snd_soc_tplg_pcm) +		|| pcm->size < sizeof(struct snd_soc_tplg_pcm_v4)) { +		dev_err(tplg->dev, "ASoC: invalid size %d for PCM elems\n", +			pcm->size); +		return -EINVAL; +	} +  	if (soc_tplg_check_elem_count(tplg, -		sizeof(struct snd_soc_tplg_pcm), count, +		pcm->size, count,  		hdr->payload_size, "PCM DAI")) {  		dev_err(tplg->dev, "ASoC: invalid count %d for PCM DAI elems\n",  			count);  		return -EINVAL;  	} -	/* create the FE DAIs and DAI links */ -	pcm = (struct snd_soc_tplg_pcm *)tplg->pos;  	for (i = 0; i < count; i++) { -		if (pcm->size != sizeof(*pcm)) { -			dev_err(tplg->dev, "ASoC: invalid pcm size\n"); -			return -EINVAL; +		pcm = (struct snd_soc_tplg_pcm *)tplg->pos; + +		/* check ABI version by size, create a new version of pcm +		 * if abi not match. +		 */ +		if (pcm->size == sizeof(*pcm)) { +			abi_match = true; +			_pcm = pcm; +		} else { +			abi_match = false; +			err = pcm_new_ver(tplg, pcm, &_pcm);  		} -		soc_tplg_pcm_create(tplg, pcm); -		pcm++; +		/* create the FE DAIs and DAI links */ +		soc_tplg_pcm_create(tplg, _pcm); + +		/* offset by version-specific struct size and +		 * real priv data size +		 */ +		tplg->pos += pcm->size + _pcm->priv.size; + +		if (!abi_match) +			kfree(_pcm); /* free the duplicated one */  	}  	dev_dbg(tplg->dev, "ASoC: adding %d PCM DAIs\n", count); -	tplg->pos += sizeof(struct snd_soc_tplg_pcm) * count;  	return 0;  } -/* * - * soc_tplg_be_dai_config - Find and configure an existing BE DAI. +/** + * set_link_hw_format - Set the HW audio format of the physical DAI link. + * @tplg: topology context + * @cfg: physical link configs. + * + * Topology context contains a list of supported HW formats (configs) and + * a default format ID for the physical link. This function will use this + * default ID to choose the HW format to set the link's DAI format for init. + */ +static void set_link_hw_format(struct snd_soc_dai_link *link, +			struct snd_soc_tplg_link_config *cfg) +{ +	struct snd_soc_tplg_hw_config *hw_config; +	unsigned char bclk_master, fsync_master; +	unsigned char invert_bclk, invert_fsync; +	int i; + +	for (i = 0; i < cfg->num_hw_configs; i++) { +		hw_config = &cfg->hw_config[i]; +		if (hw_config->id != cfg->default_hw_config_id) +			continue; + +		link->dai_fmt = hw_config->fmt & SND_SOC_DAIFMT_FORMAT_MASK; + +		/* clock signal polarity */ +		invert_bclk = hw_config->invert_bclk; +		invert_fsync = hw_config->invert_fsync; +		if (!invert_bclk && !invert_fsync) +			link->dai_fmt |= SND_SOC_DAIFMT_NB_NF; +		else if (!invert_bclk && invert_fsync) +			link->dai_fmt |= SND_SOC_DAIFMT_NB_IF; +		else if (invert_bclk && !invert_fsync) +			link->dai_fmt |= SND_SOC_DAIFMT_IB_NF; +		else +			link->dai_fmt |= SND_SOC_DAIFMT_IB_IF; + +		/* clock masters */ +		bclk_master = hw_config->bclk_master; +		fsync_master = hw_config->fsync_master; +		if (!bclk_master && !fsync_master) +			link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; +		else if (bclk_master && !fsync_master) +			link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFM; +		else if (!bclk_master && fsync_master) +			link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFS; +		else +			link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; +	} +} + +/** + * link_new_ver - Create a new physical link config from the old + * version of source. + * @toplogy: topology context + * @src: old version of phyical link config as a source + * @link: latest version of physical link config created from the source + * + * Support from vesion 4. User need free the returned link config manually. + */ +static int link_new_ver(struct soc_tplg *tplg, +			struct snd_soc_tplg_link_config *src, +			struct snd_soc_tplg_link_config **link) +{ +	struct snd_soc_tplg_link_config *dest; +	struct snd_soc_tplg_link_config_v4 *src_v4; +	int i; + +	*link = NULL; + +	if (src->size != sizeof(struct snd_soc_tplg_link_config_v4)) { +		dev_err(tplg->dev, "ASoC: invalid physical link config size\n"); +		return -EINVAL; +	} + +	dev_warn(tplg->dev, "ASoC: old version of physical link config\n"); + +	src_v4 = (struct snd_soc_tplg_link_config_v4 *)src; +	dest = kzalloc(sizeof(*dest), GFP_KERNEL); +	if (!dest) +		return -ENOMEM; + +	dest->size = sizeof(*dest); +	dest->id = src_v4->id; +	dest->num_streams = src_v4->num_streams; +	for (i = 0; i < dest->num_streams; i++) +		memcpy(&dest->stream[i], &src_v4->stream[i], +		       sizeof(struct snd_soc_tplg_stream)); + +	*link = dest; +	return 0; +} + +/* Find and configure an existing physical DAI link */ +static int soc_tplg_link_config(struct soc_tplg *tplg, +	struct snd_soc_tplg_link_config *cfg) +{ +	struct snd_soc_dai_link *link; +	const char *name, *stream_name; +	size_t len; +	int ret; + +	len = strnlen(cfg->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); +	if (len == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) +		return -EINVAL; +	else if (len) +		name = cfg->name; +	else +		name = NULL; + +	len = strnlen(cfg->stream_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); +	if (len == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) +		return -EINVAL; +	else if (len) +		stream_name = cfg->stream_name; +	else +		stream_name = NULL; + +	link = snd_soc_find_dai_link(tplg->comp->card, cfg->id, +				     name, stream_name); +	if (!link) { +		dev_err(tplg->dev, "ASoC: physical link %s (id %d) not exist\n", +			name, cfg->id); +		return -EINVAL; +	} + +	/* hw format */ +	if (cfg->num_hw_configs) +		set_link_hw_format(link, cfg); + +	/* flags */ +	if (cfg->flag_mask) +		set_link_flags(link, cfg->flag_mask, cfg->flags); + +	/* pass control to component driver for optional further init */ +	ret = soc_tplg_dai_link_load(tplg, link); +	if (ret < 0) { +		dev_err(tplg->dev, "ASoC: physical link loading failed\n"); +		return ret; +	} + +	return 0; +} + + +/* Load physical link config elements from the topology context */ +static int soc_tplg_link_elems_load(struct soc_tplg *tplg, +	struct snd_soc_tplg_hdr *hdr) +{ +	struct snd_soc_tplg_link_config *link, *_link; +	int count = hdr->count; +	int i, ret; +	bool abi_match; + +	if (tplg->pass != SOC_TPLG_PASS_LINK) { +		tplg->pos += hdr->size + hdr->payload_size; +		return 0; +	}; + +	/* check the element size and count */ +	link = (struct snd_soc_tplg_link_config *)tplg->pos; +	if (link->size > sizeof(struct snd_soc_tplg_link_config) +		|| link->size < sizeof(struct snd_soc_tplg_link_config_v4)) { +		dev_err(tplg->dev, "ASoC: invalid size %d for physical link elems\n", +			link->size); +		return -EINVAL; +	} + +	if (soc_tplg_check_elem_count(tplg, +		link->size, count, +		hdr->payload_size, "physical link config")) { +		dev_err(tplg->dev, "ASoC: invalid count %d for physical link elems\n", +			count); +		return -EINVAL; +	} + +	/* config physical DAI links */ +	for (i = 0; i < count; i++) { +		link = (struct snd_soc_tplg_link_config *)tplg->pos; +		if (link->size == sizeof(*link)) { +			abi_match = true; +			_link = link; +		} else { +			abi_match = false; +			ret = link_new_ver(tplg, link, &_link); +			if (ret < 0) +				return ret; +		} + +		ret = soc_tplg_link_config(tplg, _link); +		if (ret < 0) +			return ret; + +		/* offset by version-specific struct size and +		 * real priv data size +		 */ +		tplg->pos += link->size + _link->priv.size; + +		if (!abi_match) +			kfree(_link); /* free the duplicated one */ +	} + +	return 0; +} + +/** + * soc_tplg_dai_config - Find and configure an existing physical DAI.   * @tplg: topology context - * @be: topology BE DAI configs. + * @d: physical DAI configs.   * - * The BE dai should already be registered by the platform driver. The - * platform driver should specify the BE DAI name and ID for matching. + * The physical dai should already be registered by the platform driver. + * The platform driver should specify the DAI name and ID for matching.   */ -static int soc_tplg_be_dai_config(struct soc_tplg *tplg, -				  struct snd_soc_tplg_be_dai *be) +static int soc_tplg_dai_config(struct soc_tplg *tplg, +			       struct snd_soc_tplg_dai *d)  {  	struct snd_soc_dai_link_component dai_component = {0};  	struct snd_soc_dai *dai; @@ -1729,17 +2139,17 @@ static int soc_tplg_be_dai_config(struct soc_tplg *tplg,  	struct snd_soc_tplg_stream_caps *caps;  	int ret; -	dai_component.dai_name = be->dai_name; +	dai_component.dai_name = d->dai_name;  	dai = snd_soc_find_dai(&dai_component);  	if (!dai) { -		dev_err(tplg->dev, "ASoC: BE DAI %s not registered\n", -			be->dai_name); +		dev_err(tplg->dev, "ASoC: physical DAI %s not registered\n", +			d->dai_name);  		return -EINVAL;  	} -	if (be->dai_id != dai->id) { -		dev_err(tplg->dev, "ASoC: BE DAI %s id mismatch\n", -			be->dai_name); +	if (d->dai_id != dai->id) { +		dev_err(tplg->dev, "ASoC: physical DAI %s id mismatch\n", +			d->dai_name);  		return -EINVAL;  	} @@ -1747,20 +2157,20 @@ static int soc_tplg_be_dai_config(struct soc_tplg *tplg,  	if (!dai_drv)  		return -EINVAL; -	if (be->playback) { +	if (d->playback) {  		stream = &dai_drv->playback; -		caps = &be->caps[SND_SOC_TPLG_STREAM_PLAYBACK]; +		caps = &d->caps[SND_SOC_TPLG_STREAM_PLAYBACK];  		set_stream_info(stream, caps);  	} -	if (be->capture) { +	if (d->capture) {  		stream = &dai_drv->capture; -		caps = &be->caps[SND_SOC_TPLG_STREAM_CAPTURE]; +		caps = &d->caps[SND_SOC_TPLG_STREAM_CAPTURE];  		set_stream_info(stream, caps);  	} -	if (be->flag_mask) -		set_dai_flags(dai_drv, be->flag_mask, be->flags); +	if (d->flag_mask) +		set_dai_flags(dai_drv, d->flag_mask, d->flags);  	/* pass control to component driver for optional further init */  	ret = soc_tplg_dai_load(tplg, dai_drv); @@ -1772,10 +2182,11 @@ static int soc_tplg_be_dai_config(struct soc_tplg *tplg,  	return 0;  } -static int soc_tplg_be_dai_elems_load(struct soc_tplg *tplg, -				      struct snd_soc_tplg_hdr *hdr) +/* load physical DAI elements */ +static int soc_tplg_dai_elems_load(struct soc_tplg *tplg, +				   struct snd_soc_tplg_hdr *hdr)  { -	struct snd_soc_tplg_be_dai *be; +	struct snd_soc_tplg_dai *dai;  	int count = hdr->count;  	int i; @@ -1784,41 +2195,95 @@ static int soc_tplg_be_dai_elems_load(struct soc_tplg *tplg,  	/* config the existing BE DAIs */  	for (i = 0; i < count; i++) { -		be = (struct snd_soc_tplg_be_dai *)tplg->pos; -		if (be->size != sizeof(*be)) { -			dev_err(tplg->dev, "ASoC: invalid BE DAI size\n"); +		dai = (struct snd_soc_tplg_dai *)tplg->pos; +		if (dai->size != sizeof(*dai)) { +			dev_err(tplg->dev, "ASoC: invalid physical DAI size\n");  			return -EINVAL;  		} -		soc_tplg_be_dai_config(tplg, be); -		tplg->pos += (sizeof(*be) + be->priv.size); +		soc_tplg_dai_config(tplg, dai); +		tplg->pos += (sizeof(*dai) + dai->priv.size);  	}  	dev_dbg(tplg->dev, "ASoC: Configure %d BE DAIs\n", count);  	return 0;  } +/** + * manifest_new_ver - Create a new version of manifest from the old version + * of source. + * @toplogy: topology context + * @src: old version of manifest as a source + * @manifest: latest version of manifest created from the source + * + * Support from vesion 4. Users need free the returned manifest manually. + */ +static int manifest_new_ver(struct soc_tplg *tplg, +			    struct snd_soc_tplg_manifest *src, +			    struct snd_soc_tplg_manifest **manifest) +{ +	struct snd_soc_tplg_manifest *dest; +	struct snd_soc_tplg_manifest_v4 *src_v4; + +	*manifest = NULL; + +	if (src->size != sizeof(*src_v4)) { +		dev_err(tplg->dev, "ASoC: invalid manifest size\n"); +		return -EINVAL; +	} + +	dev_warn(tplg->dev, "ASoC: old version of manifest\n"); + +	src_v4 = (struct snd_soc_tplg_manifest_v4 *)src; +	dest = kzalloc(sizeof(*dest) + src_v4->priv.size, GFP_KERNEL); +	if (!dest) +		return -ENOMEM; + +	dest->size = sizeof(*dest);	/* size of latest abi version */ +	dest->control_elems = src_v4->control_elems; +	dest->widget_elems = src_v4->widget_elems; +	dest->graph_elems = src_v4->graph_elems; +	dest->pcm_elems = src_v4->pcm_elems; +	dest->dai_link_elems = src_v4->dai_link_elems; +	dest->priv.size = src_v4->priv.size; +	if (dest->priv.size) +		memcpy(dest->priv.data, src_v4->priv.data, +		       src_v4->priv.size); + +	*manifest = dest; +	return 0; +}  static int soc_tplg_manifest_load(struct soc_tplg *tplg,  				  struct snd_soc_tplg_hdr *hdr)  { -	struct snd_soc_tplg_manifest *manifest; +	struct snd_soc_tplg_manifest *manifest, *_manifest; +	bool abi_match; +	int err;  	if (tplg->pass != SOC_TPLG_PASS_MANIFEST)  		return 0;  	manifest = (struct snd_soc_tplg_manifest *)tplg->pos; -	if (manifest->size != sizeof(*manifest)) { -		dev_err(tplg->dev, "ASoC: invalid manifest size\n"); -		return -EINVAL; -	} -	tplg->pos += sizeof(struct snd_soc_tplg_manifest); +	/* check ABI version by size, create a new manifest if abi not match */ +	if (manifest->size == sizeof(*manifest)) { +		abi_match = true; +		_manifest = manifest; +	} else { +		abi_match = false; +		err = manifest_new_ver(tplg, manifest, &_manifest); +		if (err < 0) +			return err; +	} +	/* pass control to component driver for optional further init */  	if (tplg->comp && tplg->ops && tplg->ops->manifest) -		return tplg->ops->manifest(tplg->comp, manifest); +		return tplg->ops->manifest(tplg->comp, _manifest); + +	if (!abi_match)	/* free the duplicated one */ +		kfree(_manifest); -	dev_err(tplg->dev, "ASoC: Firmware manifest not supported\n");  	return 0;  } @@ -1854,7 +2319,9 @@ static int soc_valid_header(struct soc_tplg *tplg,  		return -EINVAL;  	} -	if (hdr->abi != SND_SOC_TPLG_ABI_VERSION) { +	/* Support ABI from version 4 */ +	if (hdr->abi > SND_SOC_TPLG_ABI_VERSION +		|| hdr->abi < SND_SOC_TPLG_ABI_VERSION_MIN) {  		dev_err(tplg->dev,  			"ASoC: pass %d invalid ABI version got 0x%x need 0x%x at offset 0x%lx size 0x%zx.\n",  			tplg->pass, hdr->abi, @@ -1902,8 +2369,12 @@ static int soc_tplg_load_header(struct soc_tplg *tplg,  		return soc_tplg_dapm_widget_elems_load(tplg, hdr);  	case SND_SOC_TPLG_TYPE_PCM:  		return soc_tplg_pcm_elems_load(tplg, hdr); -	case SND_SOC_TPLG_TYPE_BE_DAI: -		return soc_tplg_be_dai_elems_load(tplg, hdr); +	case SND_SOC_TPLG_TYPE_DAI: +		return soc_tplg_dai_elems_load(tplg, hdr); +	case SND_SOC_TPLG_TYPE_DAI_LINK: +	case SND_SOC_TPLG_TYPE_BACKEND_LINK: +		/* physical link configurations */ +		return soc_tplg_link_elems_load(tplg, hdr);  	case SND_SOC_TPLG_TYPE_MANIFEST:  		return soc_tplg_manifest_load(tplg, hdr);  	default: diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 393e8f0fe2cc..644d9a9ebfbc 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -58,6 +58,205 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params)  }  EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); +int snd_soc_component_enable_pin(struct snd_soc_component *component, +				 const char *pin) +{ +	struct snd_soc_dapm_context *dapm = +		snd_soc_component_get_dapm(component); +	char *full_name; +	int ret; + +	if (!component->name_prefix) +		return snd_soc_dapm_enable_pin(dapm, pin); + +	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); +	if (!full_name) +		return -ENOMEM; + +	ret = snd_soc_dapm_enable_pin(dapm, full_name); +	kfree(full_name); + +	return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin); + +int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component, +					  const char *pin) +{ +	struct snd_soc_dapm_context *dapm = +		snd_soc_component_get_dapm(component); +	char *full_name; +	int ret; + +	if (!component->name_prefix) +		return snd_soc_dapm_enable_pin_unlocked(dapm, pin); + +	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); +	if (!full_name) +		return -ENOMEM; + +	ret = snd_soc_dapm_enable_pin_unlocked(dapm, full_name); +	kfree(full_name); + +	return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin_unlocked); + +int snd_soc_component_disable_pin(struct snd_soc_component *component, +				  const char *pin) +{ +	struct snd_soc_dapm_context *dapm = +		snd_soc_component_get_dapm(component); +	char *full_name; +	int ret; + +	if (!component->name_prefix) +		return snd_soc_dapm_disable_pin(dapm, pin); + +	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); +	if (!full_name) +		return -ENOMEM; + +	ret = snd_soc_dapm_disable_pin(dapm, full_name); +	kfree(full_name); + +	return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin); + +int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component, +					   const char *pin) +{ +	struct snd_soc_dapm_context *dapm = +		snd_soc_component_get_dapm(component); +	char *full_name; +	int ret; + +	if (!component->name_prefix) +		return snd_soc_dapm_disable_pin_unlocked(dapm, pin); + +	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); +	if (!full_name) +		return -ENOMEM; + +	ret = snd_soc_dapm_disable_pin_unlocked(dapm, full_name); +	kfree(full_name); + +	return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin_unlocked); + +int snd_soc_component_nc_pin(struct snd_soc_component *component, +			     const char *pin) +{ +	struct snd_soc_dapm_context *dapm = +		snd_soc_component_get_dapm(component); +	char *full_name; +	int ret; + +	if (!component->name_prefix) +		return snd_soc_dapm_nc_pin(dapm, pin); + +	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); +	if (!full_name) +		return -ENOMEM; + +	ret = snd_soc_dapm_nc_pin(dapm, full_name); +	kfree(full_name); + +	return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin); + +int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component, +				      const char *pin) +{ +	struct snd_soc_dapm_context *dapm = +		snd_soc_component_get_dapm(component); +	char *full_name; +	int ret; + +	if (!component->name_prefix) +		return snd_soc_dapm_nc_pin_unlocked(dapm, pin); + +	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); +	if (!full_name) +		return -ENOMEM; + +	ret = snd_soc_dapm_nc_pin_unlocked(dapm, full_name); +	kfree(full_name); + +	return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin_unlocked); + +int snd_soc_component_get_pin_status(struct snd_soc_component *component, +				     const char *pin) +{ +	struct snd_soc_dapm_context *dapm = +		snd_soc_component_get_dapm(component); +	char *full_name; +	int ret; + +	if (!component->name_prefix) +		return snd_soc_dapm_get_pin_status(dapm, pin); + +	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); +	if (!full_name) +		return -ENOMEM; + +	ret = snd_soc_dapm_get_pin_status(dapm, full_name); +	kfree(full_name); + +	return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_get_pin_status); + +int snd_soc_component_force_enable_pin(struct snd_soc_component *component, +				       const char *pin) +{ +	struct snd_soc_dapm_context *dapm = +		snd_soc_component_get_dapm(component); +	char *full_name; +	int ret; + +	if (!component->name_prefix) +		return snd_soc_dapm_force_enable_pin(dapm, pin); + +	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); +	if (!full_name) +		return -ENOMEM; + +	ret = snd_soc_dapm_force_enable_pin(dapm, full_name); +	kfree(full_name); + +	return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin); + +int snd_soc_component_force_enable_pin_unlocked( +					struct snd_soc_component *component, +					const char *pin) +{ +	struct snd_soc_dapm_context *dapm = +		snd_soc_component_get_dapm(component); +	char *full_name; +	int ret; + +	if (!component->name_prefix) +		return snd_soc_dapm_force_enable_pin_unlocked(dapm, pin); + +	full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); +	if (!full_name) +		return -ENOMEM; + +	ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, full_name); +	kfree(full_name); + +	return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked); +  static const struct snd_pcm_hardware dummy_dma_hardware = {  	/* Random values to keep userspace happy when checking constraints */  	.info			= SNDRV_PCM_INFO_INTERLEAVED | diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 549fac349fa0..98eb205a0b62 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -7,6 +7,7 @@  #include <linux/module.h>  #include <linux/pinctrl/consumer.h> +#include <linux/delay.h>  #include "uniperif.h" @@ -97,6 +98,28 @@ static const struct of_device_id snd_soc_sti_match[] = {  	{},  }; +int  sti_uniperiph_reset(struct uniperif *uni) +{ +	int count = 10; + +	/* Reset uniperipheral uni */ +	SET_UNIPERIF_SOFT_RST_SOFT_RST(uni); + +	if (uni->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { +		while (GET_UNIPERIF_SOFT_RST_SOFT_RST(uni) && count) { +			udelay(5); +			count--; +		} +	} + +	if (!count) { +		dev_err(uni->dev, "Failed to reset uniperif\n"); +		return -EIO; +	} + +	return 0; +} +  int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,  			       unsigned int rx_mask, int slots,  			       int slot_width) @@ -293,7 +316,7 @@ static int sti_uniperiph_dai_suspend(struct snd_soc_dai *dai)  	/* The uniperipheral should be in stopped state */  	if (uni->state != UNIPERIF_STATE_STOPPED) { -		dev_err(uni->dev, "%s: invalid uni state( %d)", +		dev_err(uni->dev, "%s: invalid uni state( %d)\n",  			__func__, (int)uni->state);  		return -EBUSY;  	} @@ -301,7 +324,7 @@ static int sti_uniperiph_dai_suspend(struct snd_soc_dai *dai)  	/* Pinctrl: switch pinstate to sleep */  	ret = pinctrl_pm_select_sleep_state(uni->dev);  	if (ret) -		dev_err(uni->dev, "%s: failed to select pinctrl state", +		dev_err(uni->dev, "%s: failed to select pinctrl state\n",  			__func__);  	return ret; @@ -322,7 +345,7 @@ static int sti_uniperiph_dai_resume(struct snd_soc_dai *dai)  	/* pinctrl: switch pinstate to default */  	ret = pinctrl_pm_select_default_state(uni->dev);  	if (ret) -		dev_err(uni->dev, "%s: failed to select pinctrl state", +		dev_err(uni->dev, "%s: failed to select pinctrl state\n",  			__func__);  	return ret; @@ -366,11 +389,12 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node,  	const struct of_device_id *of_id;  	const struct sti_uniperiph_dev_data *dev_data;  	const char *mode; +	int ret;  	/* Populate data structure depending on compatibility */  	of_id = of_match_node(snd_soc_sti_match, node);  	if (!of_id->data) { -		dev_err(dev, "data associated to device is missing"); +		dev_err(dev, "data associated to device is missing\n");  		return -EINVAL;  	}  	dev_data = (struct sti_uniperiph_dev_data *)of_id->data; @@ -389,7 +413,7 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node,  	uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0);  	if (!uni->mem_region) { -		dev_err(dev, "Failed to get memory resource"); +		dev_err(dev, "Failed to get memory resource\n");  		return -ENODEV;  	} @@ -403,7 +427,7 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node,  	uni->irq = platform_get_irq(priv->pdev, 0);  	if (uni->irq < 0) { -		dev_err(dev, "Failed to get IRQ resource"); +		dev_err(dev, "Failed to get IRQ resource\n");  		return -ENXIO;  	} @@ -421,12 +445,15 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node,  	dai_data->stream = dev_data->stream;  	if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK) { -		uni_player_init(priv->pdev, uni); +		ret = uni_player_init(priv->pdev, uni);  		stream = &dai->playback;  	} else { -		uni_reader_init(priv->pdev, uni); +		ret = uni_reader_init(priv->pdev, uni);  		stream = &dai->capture;  	} +	if (ret < 0) +		return ret; +  	dai->ops = uni->dai_ops;  	stream->stream_name = dai->name; diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index 1993c655fb79..d487dd2ef016 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -1397,6 +1397,8 @@ static inline int sti_uniperiph_get_unip_tdm_frame_size(struct uniperif *uni)  	return (uni->tdm_slot.slots * uni->tdm_slot.slot_width / 8);  } +int  sti_uniperiph_reset(struct uniperif *uni); +  int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,  			       unsigned int rx_mask, int slots,  			       int slot_width); diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index ad54d4cf58ad..60ae31a303ab 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -6,8 +6,6 @@   */  #include <linux/clk.h> -#include <linux/delay.h> -#include <linux/io.h>  #include <linux/mfd/syscon.h>  #include <sound/asoundef.h> @@ -55,25 +53,6 @@ static const struct snd_pcm_hardware uni_player_pcm_hw = {  	.buffer_bytes_max = 256 * PAGE_SIZE  }; -static inline int reset_player(struct uniperif *player) -{ -	int count = 10; - -	if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { -		while (GET_UNIPERIF_SOFT_RST_SOFT_RST(player) && count) { -			udelay(5); -			count--; -		} -	} - -	if (!count) { -		dev_err(player->dev, "Failed to reset uniperif"); -		return -EIO; -	} - -	return 0; -} -  /*   * uni_player_irq_handler   * In case of error audio stream is stopped; stop action is protected via PCM @@ -97,7 +76,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)  	/* Check for fifo error (underrun) */  	if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(player))) { -		dev_err(player->dev, "FIFO underflow error detected"); +		dev_err(player->dev, "FIFO underflow error detected\n");  		/* Interrupt is just for information when underflow recovery */  		if (player->underflow_enabled) { @@ -119,7 +98,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)  	/* Check for dma error (overrun) */  	if (unlikely(status & UNIPERIF_ITS_DMA_ERROR_MASK(player))) { -		dev_err(player->dev, "DMA error detected"); +		dev_err(player->dev, "DMA error detected\n");  		/* Disable interrupt so doesn't continually fire */  		SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player); @@ -135,11 +114,14 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)  	/* Check for underflow recovery done */  	if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(player))) {  		if (!player->underflow_enabled) { -			dev_err(player->dev, "unexpected Underflow recovering"); +			dev_err(player->dev, +				"unexpected Underflow recovering\n");  			return -EPERM;  		}  		/* Read the underflow recovery duration */  		tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player); +		dev_dbg(player->dev, "Underflow recovered (%d LR clocks max)\n", +			tmp);  		/* Clear the underflow recovery duration */  		SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(player); @@ -153,7 +135,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)  	/* Check if underflow recovery failed */  	if (unlikely(status &  		     UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(player))) { -		dev_err(player->dev, "Underflow recovery failed"); +		dev_err(player->dev, "Underflow recovery failed\n");  		/* Stop the player */  		snd_pcm_stream_lock(player->substream); @@ -336,7 +318,7 @@ static int uni_player_prepare_iec958(struct uniperif *player,  	/* Oversampling must be multiple of 128 as iec958 frame is 32-bits */  	if ((clk_div % 128) || (clk_div <= 0)) { -		dev_err(player->dev, "%s: invalid clk_div %d", +		dev_err(player->dev, "%s: invalid clk_div %d\n",  			__func__, clk_div);  		return -EINVAL;  	} @@ -359,7 +341,7 @@ static int uni_player_prepare_iec958(struct uniperif *player,  		SET_UNIPERIF_I2S_FMT_DATA_SIZE_24(player);  		break;  	default: -		dev_err(player->dev, "format not supported"); +		dev_err(player->dev, "format not supported\n");  		return -EINVAL;  	} @@ -448,12 +430,12 @@ static int uni_player_prepare_pcm(struct uniperif *player,  	 * for 16 bits must be a multiple of 64  	 */  	if ((slot_width == 32) && (clk_div % 128)) { -		dev_err(player->dev, "%s: invalid clk_div", __func__); +		dev_err(player->dev, "%s: invalid clk_div\n", __func__);  		return -EINVAL;  	}  	if ((slot_width == 16) && (clk_div % 64)) { -		dev_err(player->dev, "%s: invalid clk_div", __func__); +		dev_err(player->dev, "%s: invalid clk_div\n", __func__);  		return -EINVAL;  	} @@ -471,7 +453,7 @@ static int uni_player_prepare_pcm(struct uniperif *player,  		SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player);  		break;  	default: -		dev_err(player->dev, "subframe format not supported"); +		dev_err(player->dev, "subframe format not supported\n");  		return -EINVAL;  	} @@ -491,7 +473,7 @@ static int uni_player_prepare_pcm(struct uniperif *player,  		break;  	default: -		dev_err(player->dev, "format not supported"); +		dev_err(player->dev, "format not supported\n");  		return -EINVAL;  	} @@ -504,7 +486,7 @@ static int uni_player_prepare_pcm(struct uniperif *player,  	/* Number of channelsmust be even*/  	if ((runtime->channels % 2) || (runtime->channels < 2) ||  	    (runtime->channels > 10)) { -		dev_err(player->dev, "%s: invalid nb of channels", __func__); +		dev_err(player->dev, "%s: invalid nb of channels\n", __func__);  		return -EINVAL;  	} @@ -762,7 +744,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream,  	/* The player should be stopped */  	if (player->state != UNIPERIF_STATE_STOPPED) { -		dev_err(player->dev, "%s: invalid player state %d", __func__, +		dev_err(player->dev, "%s: invalid player state %d\n", __func__,  			player->state);  		return -EINVAL;  	} @@ -791,7 +773,8 @@ static int uni_player_prepare(struct snd_pcm_substream *substream,  	/* Trigger limit must be an even number */  	if ((!trigger_limit % 2) || (trigger_limit != 1 && transfer_size % 2) ||  	    (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(player))) { -		dev_err(player->dev, "invalid trigger limit %d", trigger_limit); +		dev_err(player->dev, "invalid trigger limit %d\n", +			trigger_limit);  		return -EINVAL;  	} @@ -812,7 +795,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream,  		ret = uni_player_prepare_tdm(player, runtime);  		break;  	default: -		dev_err(player->dev, "invalid player type"); +		dev_err(player->dev, "invalid player type\n");  		return -EINVAL;  	} @@ -852,16 +835,14 @@ static int uni_player_prepare(struct snd_pcm_substream *substream,  		SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player);  		break;  	default: -		dev_err(player->dev, "format not supported"); +		dev_err(player->dev, "format not supported\n");  		return -EINVAL;  	}  	SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(player, 0); -	/* Reset uniperipheral player */ -	SET_UNIPERIF_SOFT_RST_SOFT_RST(player); -	return reset_player(player); +	return sti_uniperiph_reset(player);  }  static int uni_player_start(struct uniperif *player) @@ -870,13 +851,13 @@ static int uni_player_start(struct uniperif *player)  	/* The player should be stopped */  	if (player->state != UNIPERIF_STATE_STOPPED) { -		dev_err(player->dev, "%s: invalid player state", __func__); +		dev_err(player->dev, "%s: invalid player state\n", __func__);  		return -EINVAL;  	}  	ret = clk_prepare_enable(player->clk);  	if (ret) { -		dev_err(player->dev, "%s: Failed to enable clock", __func__); +		dev_err(player->dev, "%s: Failed to enable clock\n", __func__);  		return ret;  	} @@ -893,10 +874,7 @@ static int uni_player_start(struct uniperif *player)  		SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(player);  	} -	/* Reset uniperipheral player */ -	SET_UNIPERIF_SOFT_RST_SOFT_RST(player); - -	ret = reset_player(player); +	ret = sti_uniperiph_reset(player);  	if (ret < 0) {  		clk_disable_unprepare(player->clk);  		return ret; @@ -938,17 +916,14 @@ static int uni_player_stop(struct uniperif *player)  	/* The player should not be in stopped state */  	if (player->state == UNIPERIF_STATE_STOPPED) { -		dev_err(player->dev, "%s: invalid player state", __func__); +		dev_err(player->dev, "%s: invalid player state\n", __func__);  		return -EINVAL;  	}  	/* Turn the player off */  	SET_UNIPERIF_CTRL_OPERATION_OFF(player); -	/* Soft reset the player */ -	SET_UNIPERIF_SOFT_RST_SOFT_RST(player); - -	ret = reset_player(player); +	ret = sti_uniperiph_reset(player);  	if (ret < 0)  		return ret; @@ -973,7 +948,7 @@ int uni_player_resume(struct uniperif *player)  		ret = regmap_field_write(player->clk_sel, 1);  		if (ret) {  			dev_err(player->dev, -				"%s: Failed to select freq synth clock", +				"%s: Failed to select freq synth clock\n",  				__func__);  			return ret;  		} @@ -1070,7 +1045,7 @@ int uni_player_init(struct platform_device *pdev,  	ret = uni_player_parse_dt_audio_glue(pdev, player);  	if (ret < 0) { -		dev_err(player->dev, "Failed to parse DeviceTree"); +		dev_err(player->dev, "Failed to parse DeviceTree\n");  		return ret;  	} @@ -1085,15 +1060,17 @@ int uni_player_init(struct platform_device *pdev,  	/* Get uniperif resource */  	player->clk = of_clk_get(pdev->dev.of_node, 0); -	if (IS_ERR(player->clk)) +	if (IS_ERR(player->clk)) { +		dev_err(player->dev, "Failed to get clock\n");  		ret = PTR_ERR(player->clk); +	}  	/* Select the frequency synthesizer clock */  	if (player->clk_sel) {  		ret = regmap_field_write(player->clk_sel, 1);  		if (ret) {  			dev_err(player->dev, -				"%s: Failed to select freq synth clock", +				"%s: Failed to select freq synth clock\n",  				__func__);  			return ret;  		} @@ -1105,7 +1082,7 @@ int uni_player_init(struct platform_device *pdev,  		ret = regmap_field_write(player->valid_sel, player->id);  		if (ret) {  			dev_err(player->dev, -				"%s: unable to connect to tdm bus", __func__); +				"%s: unable to connect to tdm bus\n", __func__);  			return ret;  		}  	} @@ -1113,8 +1090,10 @@ int uni_player_init(struct platform_device *pdev,  	ret = devm_request_irq(&pdev->dev, player->irq,  			       uni_player_irq_handler, IRQF_SHARED,  			       dev_name(&pdev->dev), player); -	if (ret < 0) +	if (ret < 0) { +		dev_err(player->dev, "unable to request IRQ %d\n", player->irq);  		return ret; +	}  	mutex_init(&player->ctrl_lock); diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index 0e1c3ee56675..5992c6ab3833 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c @@ -5,10 +5,6 @@   * License terms:  GNU General Public License (GPL), version 2   */ -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/io.h> -  #include <sound/soc.h>  #include "uniperif.h" @@ -52,7 +48,7 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id)  	if (reader->state == UNIPERIF_STATE_STOPPED) {  		/* Unexpected IRQ: do nothing */ -		dev_warn(reader->dev, "unexpected IRQ "); +		dev_warn(reader->dev, "unexpected IRQ\n");  		return IRQ_HANDLED;  	} @@ -62,7 +58,7 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id)  	/* Check for fifo overflow error */  	if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) { -		dev_err(reader->dev, "FIFO error detected"); +		dev_err(reader->dev, "FIFO error detected\n");  		snd_pcm_stream_lock(reader->substream);  		snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN); @@ -105,7 +101,7 @@ static int uni_reader_prepare_pcm(struct snd_pcm_runtime *runtime,  		SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(reader);  		break;  	default: -		dev_err(reader->dev, "subframe format not supported"); +		dev_err(reader->dev, "subframe format not supported\n");  		return -EINVAL;  	} @@ -125,14 +121,14 @@ static int uni_reader_prepare_pcm(struct snd_pcm_runtime *runtime,  		break;  	default: -		dev_err(reader->dev, "format not supported"); +		dev_err(reader->dev, "format not supported\n");  		return -EINVAL;  	}  	/* Number of channels must be even */  	if ((runtime->channels % 2) || (runtime->channels < 2) ||  	    (runtime->channels > 10)) { -		dev_err(reader->dev, "%s: invalid nb of channels", __func__); +		dev_err(reader->dev, "%s: invalid nb of channels\n", __func__);  		return -EINVAL;  	} @@ -186,11 +182,10 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream,  	struct uniperif *reader = priv->dai_data.uni;  	struct snd_pcm_runtime *runtime = substream->runtime;  	int transfer_size, trigger_limit, ret; -	int count = 10;  	/* The reader should be stopped */  	if (reader->state != UNIPERIF_STATE_STOPPED) { -		dev_err(reader->dev, "%s: invalid reader state %d", __func__, +		dev_err(reader->dev, "%s: invalid reader state %d\n", __func__,  			reader->state);  		return -EINVAL;  	} @@ -219,7 +214,8 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream,  	if ((!trigger_limit % 2) ||  	    (trigger_limit != 1 && transfer_size % 2) ||  	    (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) { -		dev_err(reader->dev, "invalid trigger limit %d", trigger_limit); +		dev_err(reader->dev, "invalid trigger limit %d\n", +			trigger_limit);  		return -EINVAL;  	} @@ -246,7 +242,7 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream,  		SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(reader);  		break;  	default: -		dev_err(reader->dev, "format not supported"); +		dev_err(reader->dev, "format not supported\n");  		return -EINVAL;  	} @@ -287,25 +283,14 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream,  	}  	/* Reset uniperipheral reader */ -	SET_UNIPERIF_SOFT_RST_SOFT_RST(reader); - -	while (GET_UNIPERIF_SOFT_RST_SOFT_RST(reader)) { -		udelay(5); -		count--; -	} -	if (!count) { -		dev_err(reader->dev, "Failed to reset uniperif"); -		return -EIO; -	} - -	return 0; +	return sti_uniperiph_reset(reader);  }  static int uni_reader_start(struct uniperif *reader)  {  	/* The reader should be stopped */  	if (reader->state != UNIPERIF_STATE_STOPPED) { -		dev_err(reader->dev, "%s: invalid reader state", __func__); +		dev_err(reader->dev, "%s: invalid reader state\n", __func__);  		return -EINVAL;  	} @@ -325,7 +310,7 @@ static int uni_reader_stop(struct uniperif *reader)  {  	/* The reader should not be in stopped state */  	if (reader->state == UNIPERIF_STATE_STOPPED) { -		dev_err(reader->dev, "%s: invalid reader state", __func__); +		dev_err(reader->dev, "%s: invalid reader state\n", __func__);  		return -EINVAL;  	} @@ -423,7 +408,7 @@ int uni_reader_init(struct platform_device *pdev,  			       uni_reader_irq_handler, IRQF_SHARED,  			       dev_name(&pdev->dev), reader);  	if (ret < 0) { -		dev_err(&pdev->dev, "Failed to request IRQ"); +		dev_err(&pdev->dev, "Failed to request IRQ\n");  		return -EBUSY;  	} diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index dd2368297fd3..6c344e16aca4 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -9,6 +9,14 @@ config SND_SUN4I_CODEC  	  Select Y or M to add support for the Codec embedded in the Allwinner  	  A10 and affiliated SoCs. +config SND_SUN8I_CODEC_ANALOG +	tristate "Allwinner sun8i Codec Analog Controls Support" +	depends on MACH_SUN8I || COMPILE_TEST +	select REGMAP +	help +	  Say Y or M if you want to add support for the analog controls for +	  the codec embedded in newer Allwinner SoCs. +  config SND_SUN4I_I2S  	tristate "Allwinner A10 I2S Support"  	select SND_SOC_GENERIC_DMAENGINE_PCM diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile index 604c7b842837..241c0df9ca0c 100644 --- a/sound/soc/sunxi/Makefile +++ b/sound/soc/sunxi/Makefile @@ -1,3 +1,4 @@  obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o  obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o  obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o +obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 56ed9472e89f..848af01692a0 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -3,6 +3,7 @@   * Copyright 2014 Jon Smirl <jonsmirl@gmail.com>   * Copyright 2015 Maxime Ripard <maxime.ripard@free-electrons.com>   * Copyright 2015 Adam Sampson <ats@offog.org> + * Copyright 2016 Chen-Yu Tsai <wens@csie.org>   *   * Based on the Allwinner SDK driver, released under the GPL.   * @@ -24,10 +25,12 @@  #include <linux/delay.h>  #include <linux/slab.h>  #include <linux/of.h> -#include <linux/of_platform.h>  #include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_platform.h>  #include <linux/clk.h>  #include <linux/regmap.h> +#include <linux/reset.h>  #include <linux/gpio/consumer.h>  #include <sound/core.h> @@ -38,7 +41,7 @@  #include <sound/initval.h>  #include <sound/dmaengine_pcm.h> -/* Codec DAC register offsets and bit fields */ +/* Codec DAC digital controls and FIFO registers */  #define SUN4I_CODEC_DAC_DPC			(0x00)  #define SUN4I_CODEC_DAC_DPC_EN_DA			(31)  #define SUN4I_CODEC_DAC_DPC_DVOL			(12) @@ -55,6 +58,8 @@  #define SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH		(0)  #define SUN4I_CODEC_DAC_FIFOS			(0x08)  #define SUN4I_CODEC_DAC_TXDATA			(0x0c) + +/* Codec DAC side analog signal controls */  #define SUN4I_CODEC_DAC_ACTL			(0x10)  #define SUN4I_CODEC_DAC_ACTL_DACAENR			(31)  #define SUN4I_CODEC_DAC_ACTL_DACAENL			(30) @@ -69,7 +74,7 @@  #define SUN4I_CODEC_DAC_TUNE			(0x14)  #define SUN4I_CODEC_DAC_DEBUG			(0x18) -/* Codec ADC register offsets and bit fields */ +/* Codec ADC digital controls and FIFO registers */  #define SUN4I_CODEC_ADC_FIFOC			(0x1c)  #define SUN4I_CODEC_ADC_FIFOC_ADC_FS			(29)  #define SUN4I_CODEC_ADC_FIFOC_EN_AD			(28) @@ -81,6 +86,8 @@  #define SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH		(0)  #define SUN4I_CODEC_ADC_FIFOS			(0x20)  #define SUN4I_CODEC_ADC_RXDATA			(0x24) + +/* Codec ADC side analog signal controls */  #define SUN4I_CODEC_ADC_ACTL			(0x28)  #define SUN4I_CODEC_ADC_ACTL_ADC_R_EN			(31)  #define SUN4I_CODEC_ADC_ACTL_ADC_L_EN			(30) @@ -93,19 +100,141 @@  #define SUN4I_CODEC_ADC_ACTL_DDE			(3)  #define SUN4I_CODEC_ADC_DEBUG			(0x2c) -/* Other various ADC registers */ +/* FIFO counters */  #define SUN4I_CODEC_DAC_TXCNT			(0x30)  #define SUN4I_CODEC_ADC_RXCNT			(0x34) + +/* Calibration register (sun7i only) */  #define SUN7I_CODEC_AC_DAC_CAL			(0x38) + +/* Microphone controls (sun7i only) */  #define SUN7I_CODEC_AC_MIC_PHONE_CAL		(0x3c) +/* + * sun6i specific registers + * + * sun6i shares the same digital control and FIFO registers as sun4i, + * but only the DAC digital controls are at the same offset. The others + * have been moved around to accommodate extra analog controls. + */ + +/* Codec DAC digital controls and FIFO registers */ +#define SUN6I_CODEC_ADC_FIFOC			(0x10) +#define SUN6I_CODEC_ADC_FIFOC_EN_AD			(28) +#define SUN6I_CODEC_ADC_FIFOS			(0x14) +#define SUN6I_CODEC_ADC_RXDATA			(0x18) + +/* Output mixer and gain controls */ +#define SUN6I_CODEC_OM_DACA_CTRL		(0x20) +#define SUN6I_CODEC_OM_DACA_CTRL_DACAREN		(31) +#define SUN6I_CODEC_OM_DACA_CTRL_DACALEN		(30) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIXEN			(29) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIXEN			(28) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1		(23) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2		(22) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONE		(21) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONEP		(20) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR		(19) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR		(18) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL		(17) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1		(16) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2		(15) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONE		(14) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONEN		(13) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL		(12) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL		(11) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR		(10) +#define SUN6I_CODEC_OM_DACA_CTRL_RHPIS			(9) +#define SUN6I_CODEC_OM_DACA_CTRL_LHPIS			(8) +#define SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE		(7) +#define SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE		(6) +#define SUN6I_CODEC_OM_DACA_CTRL_HPVOL			(0) +#define SUN6I_CODEC_OM_PA_CTRL			(0x24) +#define SUN6I_CODEC_OM_PA_CTRL_HPPAEN			(31) +#define SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL		(29) +#define SUN6I_CODEC_OM_PA_CTRL_COMPTEN			(28) +#define SUN6I_CODEC_OM_PA_CTRL_MIC1G			(15) +#define SUN6I_CODEC_OM_PA_CTRL_MIC2G			(12) +#define SUN6I_CODEC_OM_PA_CTRL_LINEING			(9) +#define SUN6I_CODEC_OM_PA_CTRL_PHONEG			(6) +#define SUN6I_CODEC_OM_PA_CTRL_PHONEPG			(3) +#define SUN6I_CODEC_OM_PA_CTRL_PHONENG			(0) + +/* Microphone, line out and phone out controls */ +#define SUN6I_CODEC_MIC_CTRL			(0x28) +#define SUN6I_CODEC_MIC_CTRL_HBIASEN			(31) +#define SUN6I_CODEC_MIC_CTRL_MBIASEN			(30) +#define SUN6I_CODEC_MIC_CTRL_MIC1AMPEN			(28) +#define SUN6I_CODEC_MIC_CTRL_MIC1BOOST			(25) +#define SUN6I_CODEC_MIC_CTRL_MIC2AMPEN			(24) +#define SUN6I_CODEC_MIC_CTRL_MIC2BOOST			(21) +#define SUN6I_CODEC_MIC_CTRL_MIC2SLT			(20) +#define SUN6I_CODEC_MIC_CTRL_LINEOUTLEN			(19) +#define SUN6I_CODEC_MIC_CTRL_LINEOUTREN			(18) +#define SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC		(17) +#define SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC		(16) +#define SUN6I_CODEC_MIC_CTRL_LINEOUTVC			(11) +#define SUN6I_CODEC_MIC_CTRL_PHONEPREG			(8) + +/* ADC mixer controls */ +#define SUN6I_CODEC_ADC_ACTL			(0x2c) +#define SUN6I_CODEC_ADC_ACTL_ADCREN			(31) +#define SUN6I_CODEC_ADC_ACTL_ADCLEN			(30) +#define SUN6I_CODEC_ADC_ACTL_ADCRG			(27) +#define SUN6I_CODEC_ADC_ACTL_ADCLG			(24) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1		(13) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2		(12) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONE		(11) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONEP		(10) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR		(9) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR		(8) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL		(7) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1		(6) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2		(5) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONE		(4) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONEN		(3) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL		(2) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL		(1) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR		(0) + +/* Analog performance tuning controls */ +#define SUN6I_CODEC_ADDA_TUNE			(0x30) + +/* Calibration controls */ +#define SUN6I_CODEC_CALIBRATION			(0x34) + +/* FIFO counters */ +#define SUN6I_CODEC_DAC_TXCNT			(0x40) +#define SUN6I_CODEC_ADC_RXCNT			(0x44) + +/* headset jack detection and button support registers */ +#define SUN6I_CODEC_HMIC_CTL			(0x50) +#define SUN6I_CODEC_HMIC_DATA			(0x54) + +/* TODO sun6i DAP (Digital Audio Processing) bits */ + +/* FIFO counters moved on A23 */ +#define SUN8I_A23_CODEC_DAC_TXCNT		(0x1c) +#define SUN8I_A23_CODEC_ADC_RXCNT		(0x20) + +/* TX FIFO moved on H3 */ +#define SUN8I_H3_CODEC_DAC_TXDATA		(0x20) +#define SUN8I_H3_CODEC_DAC_DBG			(0x48) +#define SUN8I_H3_CODEC_ADC_DBG			(0x4c) + +/* TODO H3 DAP (Digital Audio Processing) bits */ +  struct sun4i_codec {  	struct device	*dev;  	struct regmap	*regmap;  	struct clk	*clk_apb;  	struct clk	*clk_module; +	struct reset_control *rst;  	struct gpio_desc *gpio_pa; +	/* ADC_FIFOC register is at different offset on different SoCs */ +	struct regmap_field *reg_adc_fifoc; +  	struct snd_dmaengine_dai_dma_data	capture_dma_data;  	struct snd_dmaengine_dai_dma_data	playback_dma_data;  }; @@ -134,16 +263,16 @@ static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)  static void sun4i_codec_start_capture(struct sun4i_codec *scodec)  {  	/* Enable ADC DRQ */ -	regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, -			   BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), -			   BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN)); +	regmap_field_update_bits(scodec->reg_adc_fifoc, +				 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), +				 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));  }  static void sun4i_codec_stop_capture(struct sun4i_codec *scodec)  {  	/* Disable ADC DRQ */ -	regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, -			   BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0); +	regmap_field_update_bits(scodec->reg_adc_fifoc, +				 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0);  }  static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd, @@ -186,24 +315,29 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,  	/* Flush RX FIFO */ -	regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, -			   BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH), -			   BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH)); +	regmap_field_update_bits(scodec->reg_adc_fifoc, +				 BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH), +				 BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH));  	/* Set RX FIFO trigger level */ -	regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, -			   0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL, -			   0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL); +	regmap_field_update_bits(scodec->reg_adc_fifoc, +				 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL, +				 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL);  	/*  	 * FIXME: Undocumented in the datasheet, but  	 *        Allwinner's code mentions that it is related  	 *        related to microphone gain  	 */ -	regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL, -			   0x3 << 25, -			   0x1 << 25); +	if (of_device_is_compatible(scodec->dev->of_node, +				    "allwinner,sun4i-a10-codec") || +	    of_device_is_compatible(scodec->dev->of_node, +				    "allwinner,sun7i-a20-codec")) { +		regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL, +				   0x3 << 25, +				   0x1 << 25); +	}  	if (of_device_is_compatible(scodec->dev->of_node,  				    "allwinner,sun7i-a20-codec")) @@ -213,9 +347,9 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,  				   0x1 << 8);  	/* Fill most significant bits with valid data MSB */ -	regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, -			   BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE), -			   BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE)); +	regmap_field_update_bits(scodec->reg_adc_fifoc, +				 BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE), +				 BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));  	return 0;  } @@ -342,18 +476,19 @@ static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec,  					 unsigned int hwrate)  {  	/* Set ADC sample rate */ -	regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, -			   7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS, -			   hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS); +	regmap_field_update_bits(scodec->reg_adc_fifoc, +				 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS, +				 hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS);  	/* Set the number of channels we want to use */  	if (params_channels(params) == 1) -		regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, -				   BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), -				   BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN)); +		regmap_field_update_bits(scodec->reg_adc_fifoc, +					 BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), +					 BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));  	else -		regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, -				   BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), 0); +		regmap_field_update_bits(scodec->reg_adc_fifoc, +					 BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), +					 0);  	return 0;  } @@ -502,7 +637,7 @@ static struct snd_soc_dai_driver sun4i_codec_dai = {  	},  }; -/*** Codec ***/ +/*** sun4i Codec ***/  static const struct snd_kcontrol_new sun4i_codec_pa_mute =  	SOC_DAPM_SINGLE("Switch", SUN4I_CODEC_DAC_ACTL,  			SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0); @@ -638,6 +773,337 @@ static struct snd_soc_codec_driver sun4i_codec_codec = {  	},  }; +/*** sun6i Codec ***/ + +/* mixer controls */ +static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = { +	SOC_DAPM_DOUBLE("DAC Playback Switch", +			SUN6I_CODEC_OM_DACA_CTRL, +			SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL, +			SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR, 1, 0), +	SOC_DAPM_DOUBLE("DAC Reversed Playback Switch", +			SUN6I_CODEC_OM_DACA_CTRL, +			SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR, +			SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL, 1, 0), +	SOC_DAPM_DOUBLE("Line In Playback Switch", +			SUN6I_CODEC_OM_DACA_CTRL, +			SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL, +			SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR, 1, 0), +	SOC_DAPM_DOUBLE("Mic1 Playback Switch", +			SUN6I_CODEC_OM_DACA_CTRL, +			SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1, +			SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1, 1, 0), +	SOC_DAPM_DOUBLE("Mic2 Playback Switch", +			SUN6I_CODEC_OM_DACA_CTRL, +			SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2, +			SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2, 1, 0), +}; + +/* ADC mixer controls */ +static const struct snd_kcontrol_new sun6i_codec_adc_mixer_controls[] = { +	SOC_DAPM_DOUBLE("Mixer Capture Switch", +			SUN6I_CODEC_ADC_ACTL, +			SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL, +			SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR, 1, 0), +	SOC_DAPM_DOUBLE("Mixer Reversed Capture Switch", +			SUN6I_CODEC_ADC_ACTL, +			SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR, +			SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL, 1, 0), +	SOC_DAPM_DOUBLE("Line In Capture Switch", +			SUN6I_CODEC_ADC_ACTL, +			SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL, +			SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR, 1, 0), +	SOC_DAPM_DOUBLE("Mic1 Capture Switch", +			SUN6I_CODEC_ADC_ACTL, +			SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1, +			SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1, 1, 0), +	SOC_DAPM_DOUBLE("Mic2 Capture Switch", +			SUN6I_CODEC_ADC_ACTL, +			SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2, +			SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2, 1, 0), +}; + +/* headphone controls */ +static const char * const sun6i_codec_hp_src_enum_text[] = { +	"DAC", "Mixer", +}; + +static SOC_ENUM_DOUBLE_DECL(sun6i_codec_hp_src_enum, +			    SUN6I_CODEC_OM_DACA_CTRL, +			    SUN6I_CODEC_OM_DACA_CTRL_LHPIS, +			    SUN6I_CODEC_OM_DACA_CTRL_RHPIS, +			    sun6i_codec_hp_src_enum_text); + +static const struct snd_kcontrol_new sun6i_codec_hp_src[] = { +	SOC_DAPM_ENUM("Headphone Source Playback Route", +		      sun6i_codec_hp_src_enum), +}; + +/* microphone controls */ +static const char * const sun6i_codec_mic2_src_enum_text[] = { +	"Mic2", "Mic3", +}; + +static SOC_ENUM_SINGLE_DECL(sun6i_codec_mic2_src_enum, +			    SUN6I_CODEC_MIC_CTRL, +			    SUN6I_CODEC_MIC_CTRL_MIC2SLT, +			    sun6i_codec_mic2_src_enum_text); + +static const struct snd_kcontrol_new sun6i_codec_mic2_src[] = { +	SOC_DAPM_ENUM("Mic2 Amplifier Source Route", +		      sun6i_codec_mic2_src_enum), +}; + +/* line out controls */ +static const char * const sun6i_codec_lineout_src_enum_text[] = { +	"Stereo", "Mono Differential", +}; + +static SOC_ENUM_DOUBLE_DECL(sun6i_codec_lineout_src_enum, +			    SUN6I_CODEC_MIC_CTRL, +			    SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC, +			    SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC, +			    sun6i_codec_lineout_src_enum_text); + +static const struct snd_kcontrol_new sun6i_codec_lineout_src[] = { +	SOC_DAPM_ENUM("Line Out Source Playback Route", +		      sun6i_codec_lineout_src_enum), +}; + +/* volume / mute controls */ +static const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0); +static const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1); +static const DECLARE_TLV_DB_SCALE(sun6i_codec_out_mixer_pregain_scale, +				  -450, 150, 0); +static const DECLARE_TLV_DB_RANGE(sun6i_codec_lineout_vol_scale, +	0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), +	2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0), +); +static const DECLARE_TLV_DB_RANGE(sun6i_codec_mic_gain_scale, +	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), +	1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0), +); + +static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = { +	SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC, +		       SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1, +		       sun6i_codec_dvol_scale), +	SOC_SINGLE_TLV("Headphone Playback Volume", +		       SUN6I_CODEC_OM_DACA_CTRL, +		       SUN6I_CODEC_OM_DACA_CTRL_HPVOL, 0x3f, 0, +		       sun6i_codec_hp_vol_scale), +	SOC_SINGLE_TLV("Line Out Playback Volume", +		       SUN6I_CODEC_MIC_CTRL, +		       SUN6I_CODEC_MIC_CTRL_LINEOUTVC, 0x1f, 0, +		       sun6i_codec_lineout_vol_scale), +	SOC_DOUBLE("Headphone Playback Switch", +		   SUN6I_CODEC_OM_DACA_CTRL, +		   SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE, +		   SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0), +	SOC_DOUBLE("Line Out Playback Switch", +		   SUN6I_CODEC_MIC_CTRL, +		   SUN6I_CODEC_MIC_CTRL_LINEOUTLEN, +		   SUN6I_CODEC_MIC_CTRL_LINEOUTREN, 1, 0), +	/* Mixer pre-gains */ +	SOC_SINGLE_TLV("Line In Playback Volume", +		       SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING, +		       0x7, 0, sun6i_codec_out_mixer_pregain_scale), +	SOC_SINGLE_TLV("Mic1 Playback Volume", +		       SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC1G, +		       0x7, 0, sun6i_codec_out_mixer_pregain_scale), +	SOC_SINGLE_TLV("Mic2 Playback Volume", +		       SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC2G, +		       0x7, 0, sun6i_codec_out_mixer_pregain_scale), + +	/* Microphone Amp boost gains */ +	SOC_SINGLE_TLV("Mic1 Boost Volume", SUN6I_CODEC_MIC_CTRL, +		       SUN6I_CODEC_MIC_CTRL_MIC1BOOST, 0x7, 0, +		       sun6i_codec_mic_gain_scale), +	SOC_SINGLE_TLV("Mic2 Boost Volume", SUN6I_CODEC_MIC_CTRL, +		       SUN6I_CODEC_MIC_CTRL_MIC2BOOST, 0x7, 0, +		       sun6i_codec_mic_gain_scale), +	SOC_DOUBLE_TLV("ADC Capture Volume", +		       SUN6I_CODEC_ADC_ACTL, SUN6I_CODEC_ADC_ACTL_ADCLG, +		       SUN6I_CODEC_ADC_ACTL_ADCRG, 0x7, 0, +		       sun6i_codec_out_mixer_pregain_scale), +}; + +static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = { +	/* Microphone inputs */ +	SND_SOC_DAPM_INPUT("MIC1"), +	SND_SOC_DAPM_INPUT("MIC2"), +	SND_SOC_DAPM_INPUT("MIC3"), + +	/* Microphone Bias */ +	SND_SOC_DAPM_SUPPLY("HBIAS", SUN6I_CODEC_MIC_CTRL, +			    SUN6I_CODEC_MIC_CTRL_HBIASEN, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("MBIAS", SUN6I_CODEC_MIC_CTRL, +			    SUN6I_CODEC_MIC_CTRL_MBIASEN, 0, NULL, 0), + +	/* Mic input path */ +	SND_SOC_DAPM_MUX("Mic2 Amplifier Source Route", +			 SND_SOC_NOPM, 0, 0, sun6i_codec_mic2_src), +	SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN6I_CODEC_MIC_CTRL, +			 SUN6I_CODEC_MIC_CTRL_MIC1AMPEN, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN6I_CODEC_MIC_CTRL, +			 SUN6I_CODEC_MIC_CTRL_MIC2AMPEN, 0, NULL, 0), + +	/* Line In */ +	SND_SOC_DAPM_INPUT("LINEIN"), + +	/* Digital parts of the ADCs */ +	SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC, +			    SUN6I_CODEC_ADC_FIFOC_EN_AD, 0, +			    NULL, 0), + +	/* Analog parts of the ADCs */ +	SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL, +			 SUN6I_CODEC_ADC_ACTL_ADCLEN, 0), +	SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL, +			 SUN6I_CODEC_ADC_ACTL_ADCREN, 0), + +	/* ADC Mixers */ +	SOC_MIXER_ARRAY("Left ADC Mixer", SND_SOC_NOPM, 0, 0, +			sun6i_codec_adc_mixer_controls), +	SOC_MIXER_ARRAY("Right ADC Mixer", SND_SOC_NOPM, 0, 0, +			sun6i_codec_adc_mixer_controls), + +	/* Digital parts of the DACs */ +	SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC, +			    SUN4I_CODEC_DAC_DPC_EN_DA, 0, +			    NULL, 0), + +	/* Analog parts of the DACs */ +	SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", +			 SUN6I_CODEC_OM_DACA_CTRL, +			 SUN6I_CODEC_OM_DACA_CTRL_DACALEN, 0), +	SND_SOC_DAPM_DAC("Right DAC", "Codec Playback", +			 SUN6I_CODEC_OM_DACA_CTRL, +			 SUN6I_CODEC_OM_DACA_CTRL_DACAREN, 0), + +	/* Mixers */ +	SOC_MIXER_ARRAY("Left Mixer", SUN6I_CODEC_OM_DACA_CTRL, +			SUN6I_CODEC_OM_DACA_CTRL_LMIXEN, 0, +			sun6i_codec_mixer_controls), +	SOC_MIXER_ARRAY("Right Mixer", SUN6I_CODEC_OM_DACA_CTRL, +			SUN6I_CODEC_OM_DACA_CTRL_RMIXEN, 0, +			sun6i_codec_mixer_controls), + +	/* Headphone output path */ +	SND_SOC_DAPM_MUX("Headphone Source Playback Route", +			 SND_SOC_NOPM, 0, 0, sun6i_codec_hp_src), +	SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN6I_CODEC_OM_PA_CTRL, +			     SUN6I_CODEC_OM_PA_CTRL_HPPAEN, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN6I_CODEC_OM_PA_CTRL, +			    SUN6I_CODEC_OM_PA_CTRL_COMPTEN, 0, NULL, 0), +	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN6I_CODEC_OM_PA_CTRL, +			 SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL, 0x3, 0x3, 0), +	SND_SOC_DAPM_OUTPUT("HP"), + +	/* Line Out path */ +	SND_SOC_DAPM_MUX("Line Out Source Playback Route", +			 SND_SOC_NOPM, 0, 0, sun6i_codec_lineout_src), +	SND_SOC_DAPM_OUTPUT("LINEOUT"), +}; + +static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = { +	/* DAC Routes */ +	{ "Left DAC", NULL, "DAC Enable" }, +	{ "Right DAC", NULL, "DAC Enable" }, + +	/* Microphone Routes */ +	{ "Mic1 Amplifier", NULL, "MIC1"}, +	{ "Mic2 Amplifier Source Route", "Mic2", "MIC2" }, +	{ "Mic2 Amplifier Source Route", "Mic3", "MIC3" }, +	{ "Mic2 Amplifier", NULL, "Mic2 Amplifier Source Route"}, + +	/* Left Mixer Routes */ +	{ "Left Mixer", "DAC Playback Switch", "Left DAC" }, +	{ "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, +	{ "Left Mixer", "Line In Playback Switch", "LINEIN" }, +	{ "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, +	{ "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + +	/* Right Mixer Routes */ +	{ "Right Mixer", "DAC Playback Switch", "Right DAC" }, +	{ "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, +	{ "Right Mixer", "Line In Playback Switch", "LINEIN" }, +	{ "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, +	{ "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + +	/* Left ADC Mixer Routes */ +	{ "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" }, +	{ "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" }, +	{ "Left ADC Mixer", "Line In Capture Switch", "LINEIN" }, +	{ "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, +	{ "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + +	/* Right ADC Mixer Routes */ +	{ "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" }, +	{ "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" }, +	{ "Right ADC Mixer", "Line In Capture Switch", "LINEIN" }, +	{ "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, +	{ "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + +	/* Headphone Routes */ +	{ "Headphone Source Playback Route", "DAC", "Left DAC" }, +	{ "Headphone Source Playback Route", "DAC", "Right DAC" }, +	{ "Headphone Source Playback Route", "Mixer", "Left Mixer" }, +	{ "Headphone Source Playback Route", "Mixer", "Right Mixer" }, +	{ "Headphone Amp", NULL, "Headphone Source Playback Route" }, +	{ "HP", NULL, "Headphone Amp" }, +	{ "HPCOM", NULL, "HPCOM Protection" }, + +	/* Line Out Routes */ +	{ "Line Out Source Playback Route", "Stereo", "Left Mixer" }, +	{ "Line Out Source Playback Route", "Stereo", "Right Mixer" }, +	{ "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, +	{ "LINEOUT", NULL, "Line Out Source Playback Route" }, + +	/* ADC Routes */ +	{ "Left ADC", NULL, "ADC Enable" }, +	{ "Right ADC", NULL, "ADC Enable" }, +	{ "Left ADC", NULL, "Left ADC Mixer" }, +	{ "Right ADC", NULL, "Right ADC Mixer" }, +}; + +static struct snd_soc_codec_driver sun6i_codec_codec = { +	.component_driver = { +		.controls		= sun6i_codec_codec_widgets, +		.num_controls		= ARRAY_SIZE(sun6i_codec_codec_widgets), +		.dapm_widgets		= sun6i_codec_codec_dapm_widgets, +		.num_dapm_widgets	= ARRAY_SIZE(sun6i_codec_codec_dapm_widgets), +		.dapm_routes		= sun6i_codec_codec_dapm_routes, +		.num_dapm_routes	= ARRAY_SIZE(sun6i_codec_codec_dapm_routes), +	}, +}; + +/* sun8i A23 codec */ +static const struct snd_kcontrol_new sun8i_a23_codec_codec_controls[] = { +	SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC, +		       SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1, +		       sun6i_codec_dvol_scale), +}; + +static const struct snd_soc_dapm_widget sun8i_a23_codec_codec_widgets[] = { +	/* Digital parts of the ADCs */ +	SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC, +			    SUN6I_CODEC_ADC_FIFOC_EN_AD, 0, NULL, 0), +	/* Digital parts of the DACs */ +	SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC, +			    SUN4I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0), + +}; + +static struct snd_soc_codec_driver sun8i_a23_codec_codec = { +	.component_driver = { +		.controls		= sun8i_a23_codec_codec_controls, +		.num_controls		= ARRAY_SIZE(sun8i_a23_codec_codec_controls), +		.dapm_widgets		= sun8i_a23_codec_codec_widgets, +		.num_dapm_widgets	= ARRAY_SIZE(sun8i_a23_codec_codec_widgets), +	}, +}; +  static const struct snd_soc_component_driver sun4i_codec_component = {  	.name = "sun4i-codec",  }; @@ -678,45 +1144,6 @@ static struct snd_soc_dai_driver dummy_cpu_dai = {  	 },  }; -static const struct regmap_config sun4i_codec_regmap_config = { -	.reg_bits	= 32, -	.reg_stride	= 4, -	.val_bits	= 32, -	.max_register	= SUN4I_CODEC_ADC_RXCNT, -}; - -static const struct regmap_config sun7i_codec_regmap_config = { -	.reg_bits	= 32, -	.reg_stride	= 4, -	.val_bits	= 32, -	.max_register	= SUN7I_CODEC_AC_MIC_PHONE_CAL, -}; - -struct sun4i_codec_quirks { -	const struct regmap_config *regmap_config; -}; - -static const struct sun4i_codec_quirks sun4i_codec_quirks = { -	.regmap_config = &sun4i_codec_regmap_config, -}; - -static const struct sun4i_codec_quirks sun7i_codec_quirks = { -	.regmap_config = &sun7i_codec_regmap_config, -}; - -static const struct of_device_id sun4i_codec_of_match[] = { -	{ -		.compatible = "allwinner,sun4i-a10-codec", -		.data = &sun4i_codec_quirks, -	}, -	{ -		.compatible = "allwinner,sun7i-a20-codec", -		.data = &sun7i_codec_quirks, -	}, -	{} -}; -MODULE_DEVICE_TABLE(of, sun4i_codec_of_match); -  static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,  							int *num_links)  { @@ -781,6 +1208,259 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)  	return card;  }; +static const struct snd_soc_dapm_widget sun6i_codec_card_dapm_widgets[] = { +	SND_SOC_DAPM_HP("Headphone", NULL), +	SND_SOC_DAPM_LINE("Line In", NULL), +	SND_SOC_DAPM_LINE("Line Out", NULL), +	SND_SOC_DAPM_MIC("Headset Mic", NULL), +	SND_SOC_DAPM_MIC("Mic", NULL), +	SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event), +}; + +static struct snd_soc_card *sun6i_codec_create_card(struct device *dev) +{ +	struct snd_soc_card *card; +	int ret; + +	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); +	if (!card) +		return ERR_PTR(-ENOMEM); + +	card->dai_link = sun4i_codec_create_link(dev, &card->num_links); +	if (!card->dai_link) +		return ERR_PTR(-ENOMEM); + +	card->dev		= dev; +	card->name		= "A31 Audio Codec"; +	card->dapm_widgets	= sun6i_codec_card_dapm_widgets; +	card->num_dapm_widgets	= ARRAY_SIZE(sun6i_codec_card_dapm_widgets); +	card->fully_routed	= true; + +	ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); +	if (ret) +		dev_warn(dev, "failed to parse audio-routing: %d\n", ret); + +	return card; +}; + +/* Connect digital side enables to analog side widgets */ +static const struct snd_soc_dapm_route sun8i_codec_card_routes[] = { +	/* ADC Routes */ +	{ "Left ADC", NULL, "ADC Enable" }, +	{ "Right ADC", NULL, "ADC Enable" }, +	{ "Codec Capture", NULL, "Left ADC" }, +	{ "Codec Capture", NULL, "Right ADC" }, + +	/* DAC Routes */ +	{ "Left DAC", NULL, "DAC Enable" }, +	{ "Right DAC", NULL, "DAC Enable" }, +	{ "Left DAC", NULL, "Codec Playback" }, +	{ "Right DAC", NULL, "Codec Playback" }, +}; + +static struct snd_soc_aux_dev aux_dev = { +	.name = "Codec Analog Controls", +}; + +static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev) +{ +	struct snd_soc_card *card; +	int ret; + +	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); +	if (!card) +		return ERR_PTR(-ENOMEM); + +	aux_dev.codec_of_node = of_parse_phandle(dev->of_node, +						 "allwinner,codec-analog-controls", +						 0); +	if (!aux_dev.codec_of_node) { +		dev_err(dev, "Can't find analog controls for codec.\n"); +		return ERR_PTR(-EINVAL); +	}; + +	card->dai_link = sun4i_codec_create_link(dev, &card->num_links); +	if (!card->dai_link) +		return ERR_PTR(-ENOMEM); + +	card->dev		= dev; +	card->name		= "A23 Audio Codec"; +	card->dapm_widgets	= sun6i_codec_card_dapm_widgets; +	card->num_dapm_widgets	= ARRAY_SIZE(sun6i_codec_card_dapm_widgets); +	card->dapm_routes	= sun8i_codec_card_routes; +	card->num_dapm_routes	= ARRAY_SIZE(sun8i_codec_card_routes); +	card->aux_dev		= &aux_dev; +	card->num_aux_devs	= 1; +	card->fully_routed	= true; + +	ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); +	if (ret) +		dev_warn(dev, "failed to parse audio-routing: %d\n", ret); + +	return card; +}; + +static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev) +{ +	struct snd_soc_card *card; +	int ret; + +	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); +	if (!card) +		return ERR_PTR(-ENOMEM); + +	aux_dev.codec_of_node = of_parse_phandle(dev->of_node, +						 "allwinner,codec-analog-controls", +						 0); +	if (!aux_dev.codec_of_node) { +		dev_err(dev, "Can't find analog controls for codec.\n"); +		return ERR_PTR(-EINVAL); +	}; + +	card->dai_link = sun4i_codec_create_link(dev, &card->num_links); +	if (!card->dai_link) +		return ERR_PTR(-ENOMEM); + +	card->dev		= dev; +	card->name		= "H3 Audio Codec"; +	card->dapm_widgets	= sun6i_codec_card_dapm_widgets; +	card->num_dapm_widgets	= ARRAY_SIZE(sun6i_codec_card_dapm_widgets); +	card->dapm_routes	= sun8i_codec_card_routes; +	card->num_dapm_routes	= ARRAY_SIZE(sun8i_codec_card_routes); +	card->aux_dev		= &aux_dev; +	card->num_aux_devs	= 1; +	card->fully_routed	= true; + +	ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); +	if (ret) +		dev_warn(dev, "failed to parse audio-routing: %d\n", ret); + +	return card; +}; + +static const struct regmap_config sun4i_codec_regmap_config = { +	.reg_bits	= 32, +	.reg_stride	= 4, +	.val_bits	= 32, +	.max_register	= SUN4I_CODEC_ADC_RXCNT, +}; + +static const struct regmap_config sun6i_codec_regmap_config = { +	.reg_bits	= 32, +	.reg_stride	= 4, +	.val_bits	= 32, +	.max_register	= SUN6I_CODEC_HMIC_DATA, +}; + +static const struct regmap_config sun7i_codec_regmap_config = { +	.reg_bits	= 32, +	.reg_stride	= 4, +	.val_bits	= 32, +	.max_register	= SUN7I_CODEC_AC_MIC_PHONE_CAL, +}; + +static const struct regmap_config sun8i_a23_codec_regmap_config = { +	.reg_bits	= 32, +	.reg_stride	= 4, +	.val_bits	= 32, +	.max_register	= SUN8I_A23_CODEC_ADC_RXCNT, +}; + +static const struct regmap_config sun8i_h3_codec_regmap_config = { +	.reg_bits	= 32, +	.reg_stride	= 4, +	.val_bits	= 32, +	.max_register	= SUN8I_H3_CODEC_ADC_DBG, +}; + +struct sun4i_codec_quirks { +	const struct regmap_config *regmap_config; +	const struct snd_soc_codec_driver *codec; +	struct snd_soc_card * (*create_card)(struct device *dev); +	struct reg_field reg_adc_fifoc;	/* used for regmap_field */ +	unsigned int reg_dac_txdata;	/* TX FIFO offset for DMA config */ +	unsigned int reg_adc_rxdata;	/* RX FIFO offset for DMA config */ +	bool has_reset; +}; + +static const struct sun4i_codec_quirks sun4i_codec_quirks = { +	.regmap_config	= &sun4i_codec_regmap_config, +	.codec		= &sun4i_codec_codec, +	.create_card	= sun4i_codec_create_card, +	.reg_adc_fifoc	= REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), +	.reg_dac_txdata	= SUN4I_CODEC_DAC_TXDATA, +	.reg_adc_rxdata	= SUN4I_CODEC_ADC_RXDATA, +}; + +static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = { +	.regmap_config	= &sun6i_codec_regmap_config, +	.codec		= &sun6i_codec_codec, +	.create_card	= sun6i_codec_create_card, +	.reg_adc_fifoc	= REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), +	.reg_dac_txdata	= SUN4I_CODEC_DAC_TXDATA, +	.reg_adc_rxdata	= SUN6I_CODEC_ADC_RXDATA, +	.has_reset	= true, +}; + +static const struct sun4i_codec_quirks sun7i_codec_quirks = { +	.regmap_config	= &sun7i_codec_regmap_config, +	.codec		= &sun4i_codec_codec, +	.create_card	= sun4i_codec_create_card, +	.reg_adc_fifoc	= REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), +	.reg_dac_txdata	= SUN4I_CODEC_DAC_TXDATA, +	.reg_adc_rxdata	= SUN4I_CODEC_ADC_RXDATA, +}; + +static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = { +	.regmap_config	= &sun8i_a23_codec_regmap_config, +	.codec		= &sun8i_a23_codec_codec, +	.create_card	= sun8i_a23_codec_create_card, +	.reg_adc_fifoc	= REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), +	.reg_dac_txdata	= SUN4I_CODEC_DAC_TXDATA, +	.reg_adc_rxdata	= SUN6I_CODEC_ADC_RXDATA, +	.has_reset	= true, +}; + +static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = { +	.regmap_config	= &sun8i_h3_codec_regmap_config, +	/* +	 * TODO Share the codec structure with A23 for now. +	 * This should be split out when adding digital audio +	 * processing support for the H3. +	 */ +	.codec		= &sun8i_a23_codec_codec, +	.create_card	= sun8i_h3_codec_create_card, +	.reg_adc_fifoc	= REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), +	.reg_dac_txdata	= SUN8I_H3_CODEC_DAC_TXDATA, +	.reg_adc_rxdata	= SUN6I_CODEC_ADC_RXDATA, +	.has_reset	= true, +}; + +static const struct of_device_id sun4i_codec_of_match[] = { +	{ +		.compatible = "allwinner,sun4i-a10-codec", +		.data = &sun4i_codec_quirks, +	}, +	{ +		.compatible = "allwinner,sun6i-a31-codec", +		.data = &sun6i_a31_codec_quirks, +	}, +	{ +		.compatible = "allwinner,sun7i-a20-codec", +		.data = &sun7i_codec_quirks, +	}, +	{ +		.compatible = "allwinner,sun8i-a23-codec", +		.data = &sun8i_a23_codec_quirks, +	}, +	{ +		.compatible = "allwinner,sun8i-h3-codec", +		.data = &sun8i_h3_codec_quirks, +	}, +	{} +}; +MODULE_DEVICE_TABLE(of, sun4i_codec_of_match); +  static int sun4i_codec_probe(struct platform_device *pdev)  {  	struct snd_soc_card *card; @@ -829,6 +1509,14 @@ static int sun4i_codec_probe(struct platform_device *pdev)  		return PTR_ERR(scodec->clk_module);  	} +	if (quirks->has_reset) { +		scodec->rst = devm_reset_control_get(&pdev->dev, NULL); +		if (IS_ERR(scodec->rst)) { +			dev_err(&pdev->dev, "Failed to get reset control\n"); +			return PTR_ERR(scodec->rst); +		} +	} +  	scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",  						  GPIOD_OUT_LOW);  	if (IS_ERR(scodec->gpio_pa)) { @@ -838,27 +1526,48 @@ static int sun4i_codec_probe(struct platform_device *pdev)  		return ret;  	} +	/* reg_field setup */ +	scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev, +							scodec->regmap, +							quirks->reg_adc_fifoc); +	if (IS_ERR(scodec->reg_adc_fifoc)) { +		ret = PTR_ERR(scodec->reg_adc_fifoc); +		dev_err(&pdev->dev, "Failed to create regmap fields: %d\n", +			ret); +		return ret; +	} +  	/* Enable the bus clock */  	if (clk_prepare_enable(scodec->clk_apb)) {  		dev_err(&pdev->dev, "Failed to enable the APB clock\n");  		return -EINVAL;  	} +	/* Deassert the reset control */ +	if (scodec->rst) { +		ret = reset_control_deassert(scodec->rst); +		if (ret) { +			dev_err(&pdev->dev, +				"Failed to deassert the reset control\n"); +			goto err_clk_disable; +		} +	} +  	/* DMA configuration for TX FIFO */ -	scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA; -	scodec->playback_dma_data.maxburst = 4; +	scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata; +	scodec->playback_dma_data.maxburst = 8;  	scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;  	/* DMA configuration for RX FIFO */ -	scodec->capture_dma_data.addr = res->start + SUN4I_CODEC_ADC_RXDATA; -	scodec->capture_dma_data.maxburst = 4; +	scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata; +	scodec->capture_dma_data.maxburst = 8;  	scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; -	ret = snd_soc_register_codec(&pdev->dev, &sun4i_codec_codec, +	ret = snd_soc_register_codec(&pdev->dev, quirks->codec,  				     &sun4i_codec_dai, 1);  	if (ret) {  		dev_err(&pdev->dev, "Failed to register our codec\n"); -		goto err_clk_disable; +		goto err_assert_reset;  	}  	ret = devm_snd_soc_register_component(&pdev->dev, @@ -875,7 +1584,7 @@ static int sun4i_codec_probe(struct platform_device *pdev)  		goto err_unregister_codec;  	} -	card = sun4i_codec_create_card(&pdev->dev); +	card = quirks->create_card(&pdev->dev);  	if (IS_ERR(card)) {  		ret = PTR_ERR(card);  		dev_err(&pdev->dev, "Failed to create our card\n"); @@ -895,6 +1604,9 @@ static int sun4i_codec_probe(struct platform_device *pdev)  err_unregister_codec:  	snd_soc_unregister_codec(&pdev->dev); +err_assert_reset: +	if (scodec->rst) +		reset_control_assert(scodec->rst);  err_clk_disable:  	clk_disable_unprepare(scodec->clk_apb);  	return ret; @@ -907,6 +1619,8 @@ static int sun4i_codec_remove(struct platform_device *pdev)  	snd_soc_unregister_card(card);  	snd_soc_unregister_codec(&pdev->dev); +	if (scodec->rst) +		reset_control_assert(scodec->rst);  	clk_disable_unprepare(scodec->clk_apb);  	return 0; @@ -926,4 +1640,5 @@ MODULE_DESCRIPTION("Allwinner A10 codec driver");  MODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>");  MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");  MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); +MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");  MODULE_LICENSE("GPL"); diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 687a8f83dbe5..f24d19526603 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -93,6 +93,9 @@ struct sun4i_i2s {  	struct clk	*mod_clk;  	struct regmap	*regmap; +	unsigned int	mclk_freq; + +	struct snd_dmaengine_dai_dma_data	capture_dma_data;  	struct snd_dmaengine_dai_dma_data	playback_dma_data;  }; @@ -157,14 +160,24 @@ static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s,  }  static int sun4i_i2s_oversample_rates[] = { 128, 192, 256, 384, 512, 768 }; +static bool sun4i_i2s_oversample_is_valid(unsigned int oversample) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(sun4i_i2s_oversample_rates); i++) +		if (sun4i_i2s_oversample_rates[i] == oversample) +			return true; + +	return false; +}  static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,  				  unsigned int rate,  				  unsigned int word_size)  { -	unsigned int clk_rate; +	unsigned int oversample_rate, clk_rate;  	int bclk_div, mclk_div; -	int ret, i; +	int ret;  	switch (rate) {  	case 176400: @@ -196,21 +209,18 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,  	if (ret)  		return ret; -	/* Always favor the highest oversampling rate */ -	for (i = (ARRAY_SIZE(sun4i_i2s_oversample_rates) - 1); i >= 0; i--) { -		unsigned int oversample_rate = sun4i_i2s_oversample_rates[i]; - -		bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate, -						  word_size); -		mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate, -						  clk_rate, -						  rate); +	oversample_rate = i2s->mclk_freq / rate; +	if (!sun4i_i2s_oversample_is_valid(oversample_rate)) +		return -EINVAL; -		if ((bclk_div >= 0) && (mclk_div >= 0)) -			break; -	} +	bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate, +					  word_size); +	if (bclk_div < 0) +		return -EINVAL; -	if ((bclk_div < 0) || (mclk_div < 0)) +	mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate, +					  clk_rate, rate); +	if (mclk_div < 0)  		return -EINVAL;  	regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG, @@ -341,6 +351,27 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)  	return 0;  } +static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s) +{ +	/* Flush RX FIFO */ +	regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG, +			   SUN4I_I2S_FIFO_CTRL_FLUSH_RX, +			   SUN4I_I2S_FIFO_CTRL_FLUSH_RX); + +	/* Clear RX counter */ +	regmap_write(i2s->regmap, SUN4I_I2S_RX_CNT_REG, 0); + +	/* Enable RX Block */ +	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, +			   SUN4I_I2S_CTRL_RX_EN, +			   SUN4I_I2S_CTRL_RX_EN); + +	/* Enable RX DRQ */ +	regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG, +			   SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN, +			   SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN); +} +  static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s)  {  	/* Flush TX FIFO */ @@ -362,6 +393,18 @@ static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s)  			   SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN);  } +static void sun4i_i2s_stop_capture(struct sun4i_i2s *i2s) +{ +	/* Disable RX Block */ +	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, +			   SUN4I_I2S_CTRL_RX_EN, +			   0); + +	/* Disable RX DRQ */ +	regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG, +			   SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN, +			   0); +}  static void sun4i_i2s_stop_playback(struct sun4i_i2s *i2s)  { @@ -388,7 +431,7 @@ static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd,  		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)  			sun4i_i2s_start_playback(i2s);  		else -			return -EINVAL; +			sun4i_i2s_start_capture(i2s);  		break;  	case SNDRV_PCM_TRIGGER_STOP: @@ -397,7 +440,7 @@ static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd,  		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)  			sun4i_i2s_stop_playback(i2s);  		else -			return -EINVAL; +			sun4i_i2s_stop_capture(i2s);  		break;  	default: @@ -447,9 +490,23 @@ static void sun4i_i2s_shutdown(struct snd_pcm_substream *substream,  	regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0);  } +static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, +				unsigned int freq, int dir) +{ +	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + +	if (clk_id != 0) +		return -EINVAL; + +	i2s->mclk_freq = freq; + +	return 0; +} +  static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {  	.hw_params	= sun4i_i2s_hw_params,  	.set_fmt	= sun4i_i2s_set_fmt, +	.set_sysclk	= sun4i_i2s_set_sysclk,  	.shutdown	= sun4i_i2s_shutdown,  	.startup	= sun4i_i2s_startup,  	.trigger	= sun4i_i2s_trigger, @@ -459,7 +516,9 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)  {  	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); -	snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data, NULL); +	snd_soc_dai_init_dma_data(dai, +				  &i2s->playback_dma_data, +				  &i2s->capture_dma_data);  	snd_soc_dai_set_drvdata(dai, i2s); @@ -468,6 +527,13 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)  static struct snd_soc_dai_driver sun4i_i2s_dai = {  	.probe = sun4i_i2s_dai_probe, +	.capture = { +		.stream_name = "Capture", +		.channels_min = 2, +		.channels_max = 2, +		.rates = SNDRV_PCM_RATE_8000_192000, +		.formats = SNDRV_PCM_FMTBIT_S16_LE, +	},  	.playback = {  		.stream_name = "Playback",  		.channels_min = 2, @@ -630,6 +696,9 @@ static int sun4i_i2s_probe(struct platform_device *pdev)  	i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG;  	i2s->playback_dma_data.maxburst = 4; +	i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG; +	i2s->capture_dma_data.maxburst = 4; +  	pm_runtime_enable(&pdev->dev);  	if (!pm_runtime_enabled(&pdev->dev)) {  		ret = sun4i_i2s_runtime_resume(&pdev->dev); diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c new file mode 100644 index 000000000000..af02290ebe49 --- /dev/null +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -0,0 +1,665 @@ +/* + * This driver supports the analog controls for the internal codec + * found in Allwinner's A31s, A23, A33 and H3 SoCs. + * + * Copyright 2016 Chen-Yu Tsai <wens@csie.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> + +/* Codec analog control register offsets and bit fields */ +#define SUN8I_ADDA_HP_VOLC		0x00 +#define SUN8I_ADDA_HP_VOLC_PA_CLK_GATE		7 +#define SUN8I_ADDA_HP_VOLC_HP_VOL		0 +#define SUN8I_ADDA_LOMIXSC		0x01 +#define SUN8I_ADDA_LOMIXSC_MIC1			6 +#define SUN8I_ADDA_LOMIXSC_MIC2			5 +#define SUN8I_ADDA_LOMIXSC_PHONE		4 +#define SUN8I_ADDA_LOMIXSC_PHONEN		3 +#define SUN8I_ADDA_LOMIXSC_LINEINL		2 +#define SUN8I_ADDA_LOMIXSC_DACL			1 +#define SUN8I_ADDA_LOMIXSC_DACR			0 +#define SUN8I_ADDA_ROMIXSC		0x02 +#define SUN8I_ADDA_ROMIXSC_MIC1			6 +#define SUN8I_ADDA_ROMIXSC_MIC2			5 +#define SUN8I_ADDA_ROMIXSC_PHONE		4 +#define SUN8I_ADDA_ROMIXSC_PHONEP		3 +#define SUN8I_ADDA_ROMIXSC_LINEINR		2 +#define SUN8I_ADDA_ROMIXSC_DACR			1 +#define SUN8I_ADDA_ROMIXSC_DACL			0 +#define SUN8I_ADDA_DAC_PA_SRC		0x03 +#define SUN8I_ADDA_DAC_PA_SRC_DACAREN		7 +#define SUN8I_ADDA_DAC_PA_SRC_DACALEN		6 +#define SUN8I_ADDA_DAC_PA_SRC_RMIXEN		5 +#define SUN8I_ADDA_DAC_PA_SRC_LMIXEN		4 +#define SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE		3 +#define SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE		2 +#define SUN8I_ADDA_DAC_PA_SRC_RHPIS		1 +#define SUN8I_ADDA_DAC_PA_SRC_LHPIS		0 +#define SUN8I_ADDA_PHONEIN_GCTRL	0x04 +#define SUN8I_ADDA_PHONEIN_GCTRL_PHONEPG	4 +#define SUN8I_ADDA_PHONEIN_GCTRL_PHONENG	0 +#define SUN8I_ADDA_LINEIN_GCTRL		0x05 +#define SUN8I_ADDA_LINEIN_GCTRL_LINEING		4 +#define SUN8I_ADDA_LINEIN_GCTRL_PHONEG		0 +#define SUN8I_ADDA_MICIN_GCTRL		0x06 +#define SUN8I_ADDA_MICIN_GCTRL_MIC1G		4 +#define SUN8I_ADDA_MICIN_GCTRL_MIC2G		0 +#define SUN8I_ADDA_PAEN_HP_CTRL		0x07 +#define SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN		7 +#define SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN	7	/* H3 specific */ +#define SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC	5 +#define SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN		4 +#define SUN8I_ADDA_PAEN_HP_CTRL_PA_ANTI_POP_CTRL	2 +#define SUN8I_ADDA_PAEN_HP_CTRL_LTRNMUTE	1 +#define SUN8I_ADDA_PAEN_HP_CTRL_RTLNMUTE	0 +#define SUN8I_ADDA_PHONEOUT_CTRL	0x08 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTG	5 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTEN	4 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC1	3 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC2	2 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_RMIX	1 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_LMIX	0 +#define SUN8I_ADDA_PHONE_GAIN_CTRL	0x09 +#define SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL	3 +#define SUN8I_ADDA_PHONE_GAIN_CTRL_PHONEPREG	0 +#define SUN8I_ADDA_MIC2G_CTRL		0x0a +#define SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN		7 +#define SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST		4 +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN	3 +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN	2 +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC	1 +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC	0 +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL	0x0b +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN	7 +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN	6 +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIAS_MODE	5 +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN		3 +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST		0 +#define SUN8I_ADDA_LADCMIXSC		0x0c +#define SUN8I_ADDA_LADCMIXSC_MIC1		6 +#define SUN8I_ADDA_LADCMIXSC_MIC2		5 +#define SUN8I_ADDA_LADCMIXSC_PHONE		4 +#define SUN8I_ADDA_LADCMIXSC_PHONEN		3 +#define SUN8I_ADDA_LADCMIXSC_LINEINL		2 +#define SUN8I_ADDA_LADCMIXSC_OMIXRL		1 +#define SUN8I_ADDA_LADCMIXSC_OMIXRR		0 +#define SUN8I_ADDA_RADCMIXSC		0x0d +#define SUN8I_ADDA_RADCMIXSC_MIC1		6 +#define SUN8I_ADDA_RADCMIXSC_MIC2		5 +#define SUN8I_ADDA_RADCMIXSC_PHONE		4 +#define SUN8I_ADDA_RADCMIXSC_PHONEP		3 +#define SUN8I_ADDA_RADCMIXSC_LINEINR		2 +#define SUN8I_ADDA_RADCMIXSC_OMIXR		1 +#define SUN8I_ADDA_RADCMIXSC_OMIXL		0 +#define SUN8I_ADDA_RES			0x0e +#define SUN8I_ADDA_RES_MMICBIAS_SEL		4 +#define SUN8I_ADDA_RES_PA_ANTI_POP_CTRL		0 +#define SUN8I_ADDA_ADC_AP_EN		0x0f +#define SUN8I_ADDA_ADC_AP_EN_ADCREN		7 +#define SUN8I_ADDA_ADC_AP_EN_ADCLEN		6 +#define SUN8I_ADDA_ADC_AP_EN_ADCG		0 + +/* Analog control register access bits */ +#define ADDA_PR			0x0		/* PRCM base + 0x1c0 */ +#define ADDA_PR_RESET			BIT(28) +#define ADDA_PR_WRITE			BIT(24) +#define ADDA_PR_ADDR_SHIFT		16 +#define ADDA_PR_ADDR_MASK		GENMASK(4, 0) +#define ADDA_PR_DATA_IN_SHIFT		8 +#define ADDA_PR_DATA_IN_MASK		GENMASK(7, 0) +#define ADDA_PR_DATA_OUT_SHIFT		0 +#define ADDA_PR_DATA_OUT_MASK		GENMASK(7, 0) + +/* regmap access bits */ +static int adda_reg_read(void *context, unsigned int reg, unsigned int *val) +{ +	void __iomem *base = (void __iomem *)context; +	u32 tmp; + +	/* De-assert reset */ +	writel(readl(base) | ADDA_PR_RESET, base); + +	/* Clear write bit */ +	writel(readl(base) & ~ADDA_PR_WRITE, base); + +	/* Set register address */ +	tmp = readl(base); +	tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT); +	tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT; +	writel(tmp, base); + +	/* Read back value */ +	*val = readl(base) & ADDA_PR_DATA_OUT_MASK; + +	return 0; +} + +static int adda_reg_write(void *context, unsigned int reg, unsigned int val) +{ +	void __iomem *base = (void __iomem *)context; +	u32 tmp; + +	/* De-assert reset */ +	writel(readl(base) | ADDA_PR_RESET, base); + +	/* Set register address */ +	tmp = readl(base); +	tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT); +	tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT; +	writel(tmp, base); + +	/* Set data to write */ +	tmp = readl(base); +	tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT); +	tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT; +	writel(tmp, base); + +	/* Set write bit to signal a write */ +	writel(readl(base) | ADDA_PR_WRITE, base); + +	/* Clear write bit */ +	writel(readl(base) & ~ADDA_PR_WRITE, base); + +	return 0; +} + +static const struct regmap_config adda_pr_regmap_cfg = { +	.name		= "adda-pr", +	.reg_bits	= 5, +	.reg_stride	= 1, +	.val_bits	= 8, +	.reg_read	= adda_reg_read, +	.reg_write	= adda_reg_write, +	.fast_io	= true, +	.max_register	= 24, +}; + +/* mixer controls */ +static const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = { +	SOC_DAPM_DOUBLE_R("DAC Playback Switch", +			  SUN8I_ADDA_LOMIXSC, +			  SUN8I_ADDA_ROMIXSC, +			  SUN8I_ADDA_LOMIXSC_DACL, 1, 0), +	SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch", +			  SUN8I_ADDA_LOMIXSC, +			  SUN8I_ADDA_ROMIXSC, +			  SUN8I_ADDA_LOMIXSC_DACR, 1, 0), +	SOC_DAPM_DOUBLE_R("Line In Playback Switch", +			  SUN8I_ADDA_LOMIXSC, +			  SUN8I_ADDA_ROMIXSC, +			  SUN8I_ADDA_LOMIXSC_LINEINL, 1, 0), +	SOC_DAPM_DOUBLE_R("Mic1 Playback Switch", +			  SUN8I_ADDA_LOMIXSC, +			  SUN8I_ADDA_ROMIXSC, +			  SUN8I_ADDA_LOMIXSC_MIC1, 1, 0), +	SOC_DAPM_DOUBLE_R("Mic2 Playback Switch", +			  SUN8I_ADDA_LOMIXSC, +			  SUN8I_ADDA_ROMIXSC, +			  SUN8I_ADDA_LOMIXSC_MIC2, 1, 0), +}; + +/* ADC mixer controls */ +static const struct snd_kcontrol_new sun8i_codec_adc_mixer_controls[] = { +	SOC_DAPM_DOUBLE_R("Mixer Capture Switch", +			  SUN8I_ADDA_LADCMIXSC, +			  SUN8I_ADDA_RADCMIXSC, +			  SUN8I_ADDA_LADCMIXSC_OMIXRL, 1, 0), +	SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch", +			  SUN8I_ADDA_LADCMIXSC, +			  SUN8I_ADDA_RADCMIXSC, +			  SUN8I_ADDA_LADCMIXSC_OMIXRR, 1, 0), +	SOC_DAPM_DOUBLE_R("Line In Capture Switch", +			  SUN8I_ADDA_LADCMIXSC, +			  SUN8I_ADDA_RADCMIXSC, +			  SUN8I_ADDA_LADCMIXSC_LINEINL, 1, 0), +	SOC_DAPM_DOUBLE_R("Mic1 Capture Switch", +			  SUN8I_ADDA_LADCMIXSC, +			  SUN8I_ADDA_RADCMIXSC, +			  SUN8I_ADDA_LADCMIXSC_MIC1, 1, 0), +	SOC_DAPM_DOUBLE_R("Mic2 Capture Switch", +			  SUN8I_ADDA_LADCMIXSC, +			  SUN8I_ADDA_RADCMIXSC, +			  SUN8I_ADDA_LADCMIXSC_MIC2, 1, 0), +}; + +/* volume / mute controls */ +static const DECLARE_TLV_DB_SCALE(sun8i_codec_out_mixer_pregain_scale, +				  -450, 150, 0); +static const DECLARE_TLV_DB_RANGE(sun8i_codec_mic_gain_scale, +	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), +	1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0), +); + +static const struct snd_kcontrol_new sun8i_codec_common_controls[] = { +	/* Mixer pre-gains */ +	SOC_SINGLE_TLV("Line In Playback Volume", SUN8I_ADDA_LINEIN_GCTRL, +		       SUN8I_ADDA_LINEIN_GCTRL_LINEING, +		       0x7, 0, sun8i_codec_out_mixer_pregain_scale), +	SOC_SINGLE_TLV("Mic1 Playback Volume", SUN8I_ADDA_MICIN_GCTRL, +		       SUN8I_ADDA_MICIN_GCTRL_MIC1G, +		       0x7, 0, sun8i_codec_out_mixer_pregain_scale), +	SOC_SINGLE_TLV("Mic2 Playback Volume", +		       SUN8I_ADDA_MICIN_GCTRL, SUN8I_ADDA_MICIN_GCTRL_MIC2G, +		       0x7, 0, sun8i_codec_out_mixer_pregain_scale), + +	/* Microphone Amp boost gains */ +	SOC_SINGLE_TLV("Mic1 Boost Volume", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, +		       SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST, 0x7, 0, +		       sun8i_codec_mic_gain_scale), +	SOC_SINGLE_TLV("Mic2 Boost Volume", SUN8I_ADDA_MIC2G_CTRL, +		       SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST, 0x7, 0, +		       sun8i_codec_mic_gain_scale), + +	/* ADC */ +	SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN8I_ADDA_ADC_AP_EN, +		       SUN8I_ADDA_ADC_AP_EN_ADCG, 0x7, 0, +		       sun8i_codec_out_mixer_pregain_scale), +}; + +static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = { +	/* ADC */ +	SND_SOC_DAPM_ADC("Left ADC", NULL, SUN8I_ADDA_ADC_AP_EN, +			 SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0), +	SND_SOC_DAPM_ADC("Right ADC", NULL, SUN8I_ADDA_ADC_AP_EN, +			 SUN8I_ADDA_ADC_AP_EN_ADCREN, 0), + +	/* DAC */ +	SND_SOC_DAPM_DAC("Left DAC", NULL, SUN8I_ADDA_DAC_PA_SRC, +			 SUN8I_ADDA_DAC_PA_SRC_DACALEN, 0), +	SND_SOC_DAPM_DAC("Right DAC", NULL, SUN8I_ADDA_DAC_PA_SRC, +			 SUN8I_ADDA_DAC_PA_SRC_DACAREN, 0), +	/* +	 * Due to this component and the codec belonging to separate DAPM +	 * contexts, we need to manually link the above widgets to their +	 * stream widgets at the card level. +	 */ + +	/* Line In */ +	SND_SOC_DAPM_INPUT("LINEIN"), + +	/* Microphone inputs */ +	SND_SOC_DAPM_INPUT("MIC1"), +	SND_SOC_DAPM_INPUT("MIC2"), + +	/* Microphone Bias */ +	SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, +			    SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN, +			    0, NULL, 0), + +	/* Mic input path */ +	SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, +			 SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN8I_ADDA_MIC2G_CTRL, +			 SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN, 0, NULL, 0), + +	/* Mixers */ +	SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC, +			   SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0, +			   sun8i_codec_mixer_controls, +			   ARRAY_SIZE(sun8i_codec_mixer_controls)), +	SND_SOC_DAPM_MIXER("Right Mixer", SUN8I_ADDA_DAC_PA_SRC, +			   SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0, +			   sun8i_codec_mixer_controls, +			   ARRAY_SIZE(sun8i_codec_mixer_controls)), +	SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN, +			   SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0, +			   sun8i_codec_adc_mixer_controls, +			   ARRAY_SIZE(sun8i_codec_adc_mixer_controls)), +	SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN, +			   SUN8I_ADDA_ADC_AP_EN_ADCREN, 0, +			   sun8i_codec_adc_mixer_controls, +			   ARRAY_SIZE(sun8i_codec_adc_mixer_controls)), +}; + +static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = { +	/* Microphone Routes */ +	{ "Mic1 Amplifier", NULL, "MIC1"}, +	{ "Mic2 Amplifier", NULL, "MIC2"}, + +	/* Left Mixer Routes */ +	{ "Left Mixer", "DAC Playback Switch", "Left DAC" }, +	{ "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, +	{ "Left Mixer", "Line In Playback Switch", "LINEIN" }, +	{ "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, +	{ "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + +	/* Right Mixer Routes */ +	{ "Right Mixer", "DAC Playback Switch", "Right DAC" }, +	{ "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, +	{ "Right Mixer", "Line In Playback Switch", "LINEIN" }, +	{ "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, +	{ "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + +	/* Left ADC Mixer Routes */ +	{ "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" }, +	{ "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" }, +	{ "Left ADC Mixer", "Line In Capture Switch", "LINEIN" }, +	{ "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, +	{ "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + +	/* Right ADC Mixer Routes */ +	{ "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" }, +	{ "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" }, +	{ "Right ADC Mixer", "Line In Capture Switch", "LINEIN" }, +	{ "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, +	{ "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + +	/* ADC Routes */ +	{ "Left ADC", NULL, "Left ADC Mixer" }, +	{ "Right ADC", NULL, "Right ADC Mixer" }, +}; + +/* headphone specific controls, widgets, and routes */ +static const DECLARE_TLV_DB_SCALE(sun8i_codec_hp_vol_scale, -6300, 100, 1); +static const struct snd_kcontrol_new sun8i_codec_headphone_controls[] = { +	SOC_SINGLE_TLV("Headphone Playback Volume", +		       SUN8I_ADDA_HP_VOLC, +		       SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0, +		       sun8i_codec_hp_vol_scale), +	SOC_DOUBLE("Headphone Playback Switch", +		   SUN8I_ADDA_DAC_PA_SRC, +		   SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE, +		   SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE, 1, 0), +}; + +static const char * const sun8i_codec_hp_src_enum_text[] = { +	"DAC", "Mixer", +}; + +static SOC_ENUM_DOUBLE_DECL(sun8i_codec_hp_src_enum, +			    SUN8I_ADDA_DAC_PA_SRC, +			    SUN8I_ADDA_DAC_PA_SRC_LHPIS, +			    SUN8I_ADDA_DAC_PA_SRC_RHPIS, +			    sun8i_codec_hp_src_enum_text); + +static const struct snd_kcontrol_new sun8i_codec_hp_src[] = { +	SOC_DAPM_ENUM("Headphone Source Playback Route", +		      sun8i_codec_hp_src_enum), +}; + +static const struct snd_soc_dapm_widget sun8i_codec_headphone_widgets[] = { +	SND_SOC_DAPM_MUX("Headphone Source Playback Route", +			 SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src), +	SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL, +			     SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN8I_ADDA_PAEN_HP_CTRL, +			    SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN, 0, NULL, 0), +	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN8I_ADDA_PAEN_HP_CTRL, +			 SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC, 0x3, 0x3, 0), +	SND_SOC_DAPM_OUTPUT("HP"), +}; + +static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = { +	{ "Headphone Source Playback Route", "DAC", "Left DAC" }, +	{ "Headphone Source Playback Route", "DAC", "Right DAC" }, +	{ "Headphone Source Playback Route", "Mixer", "Left Mixer" }, +	{ "Headphone Source Playback Route", "Mixer", "Right Mixer" }, +	{ "Headphone Amp", NULL, "Headphone Source Playback Route" }, +	{ "HPCOM", NULL, "HPCOM Protection" }, +	{ "HP", NULL, "Headphone Amp" }, +}; + +static int sun8i_codec_add_headphone(struct snd_soc_component *cmpnt) +{ +	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); +	struct device *dev = cmpnt->dev; +	int ret; + +	ret = snd_soc_add_component_controls(cmpnt, +					     sun8i_codec_headphone_controls, +					     ARRAY_SIZE(sun8i_codec_headphone_controls)); +	if (ret) { +		dev_err(dev, "Failed to add Headphone controls: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_headphone_widgets, +					ARRAY_SIZE(sun8i_codec_headphone_widgets)); +	if (ret) { +		dev_err(dev, "Failed to add Headphone DAPM widgets: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_headphone_routes, +				      ARRAY_SIZE(sun8i_codec_headphone_routes)); +	if (ret) { +		dev_err(dev, "Failed to add Headphone DAPM routes: %d\n", ret); +		return ret; +	} + +	return 0; +} + +/* hmic specific widget */ +static const struct snd_soc_dapm_widget sun8i_codec_hmic_widgets[] = { +	SND_SOC_DAPM_SUPPLY("HBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, +			    SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN, +			    0, NULL, 0), +}; + +static int sun8i_codec_add_hmic(struct snd_soc_component *cmpnt) +{ +	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); +	struct device *dev = cmpnt->dev; +	int ret; + +	ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_hmic_widgets, +					ARRAY_SIZE(sun8i_codec_hmic_widgets)); +	if (ret) +		dev_err(dev, "Failed to add Mic3 DAPM widgets: %d\n", ret); + +	return ret; +} + +/* line out specific controls, widgets and routes */ +static const DECLARE_TLV_DB_RANGE(sun8i_codec_lineout_vol_scale, +	0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), +	2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0), +); +static const struct snd_kcontrol_new sun8i_codec_lineout_controls[] = { +	SOC_SINGLE_TLV("Line Out Playback Volume", +		       SUN8I_ADDA_PHONE_GAIN_CTRL, +		       SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL, 0x1f, 0, +		       sun8i_codec_lineout_vol_scale), +	SOC_DOUBLE("Line Out Playback Switch", +		   SUN8I_ADDA_MIC2G_CTRL, +		   SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN, +		   SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN, 1, 0), +}; + +static const char * const sun8i_codec_lineout_src_enum_text[] = { +	"Stereo", "Mono Differential", +}; + +static SOC_ENUM_DOUBLE_DECL(sun8i_codec_lineout_src_enum, +			    SUN8I_ADDA_MIC2G_CTRL, +			    SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC, +			    SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC, +			    sun8i_codec_lineout_src_enum_text); + +static const struct snd_kcontrol_new sun8i_codec_lineout_src[] = { +	SOC_DAPM_ENUM("Line Out Source Playback Route", +		      sun8i_codec_lineout_src_enum), +}; + +static const struct snd_soc_dapm_widget sun8i_codec_lineout_widgets[] = { +	SND_SOC_DAPM_MUX("Line Out Source Playback Route", +			 SND_SOC_NOPM, 0, 0, sun8i_codec_lineout_src), +	/* It is unclear if this is a buffer or gate, model it as a supply */ +	SND_SOC_DAPM_SUPPLY("Line Out Enable", SUN8I_ADDA_PAEN_HP_CTRL, +			    SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN, 0, NULL, 0), +	SND_SOC_DAPM_OUTPUT("LINEOUT"), +}; + +static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = { +	{ "Line Out Source Playback Route", "Stereo", "Left Mixer" }, +	{ "Line Out Source Playback Route", "Stereo", "Right Mixer" }, +	{ "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, +	{ "Line Out Source Playback Route", "Mono Differential", "Right Mixer" }, +	{ "LINEOUT", NULL, "Line Out Source Playback Route" }, +	{ "LINEOUT", NULL, "Line Out Enable", }, +}; + +static int sun8i_codec_add_lineout(struct snd_soc_component *cmpnt) +{ +	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); +	struct device *dev = cmpnt->dev; +	int ret; + +	ret = snd_soc_add_component_controls(cmpnt, +					     sun8i_codec_lineout_controls, +					     ARRAY_SIZE(sun8i_codec_lineout_controls)); +	if (ret) { +		dev_err(dev, "Failed to add Line Out controls: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_lineout_widgets, +					ARRAY_SIZE(sun8i_codec_lineout_widgets)); +	if (ret) { +		dev_err(dev, "Failed to add Line Out DAPM widgets: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_lineout_routes, +				      ARRAY_SIZE(sun8i_codec_lineout_routes)); +	if (ret) { +		dev_err(dev, "Failed to add Line Out DAPM routes: %d\n", ret); +		return ret; +	} + +	return 0; +} + +struct sun8i_codec_analog_quirks { +	bool has_headphone; +	bool has_hmic; +	bool has_lineout; +}; + +static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = { +	.has_headphone	= true, +	.has_hmic	= true, +}; + +static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = { +	.has_lineout	= true, +}; + +static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) +{ +	struct device *dev = cmpnt->dev; +	const struct sun8i_codec_analog_quirks *quirks; +	int ret; + +	/* +	 * This would never return NULL unless someone directly registers a +	 * platform device matching this driver's name, without specifying a +	 * device tree node. +	 */ +	quirks = of_device_get_match_data(dev); + +	/* Add controls, widgets, and routes for individual features */ + +	if (quirks->has_headphone) { +		ret = sun8i_codec_add_headphone(cmpnt); +		if (ret) +			return ret; +	} + +	if (quirks->has_hmic) { +		ret = sun8i_codec_add_hmic(cmpnt); +		if (ret) +			return ret; +	} + +	if (quirks->has_lineout) { +		ret = sun8i_codec_add_lineout(cmpnt); +		if (ret) +			return ret; +	} + +	return 0; +} + +static const struct snd_soc_component_driver sun8i_codec_analog_cmpnt_drv = { +	.controls		= sun8i_codec_common_controls, +	.num_controls		= ARRAY_SIZE(sun8i_codec_common_controls), +	.dapm_widgets		= sun8i_codec_common_widgets, +	.num_dapm_widgets	= ARRAY_SIZE(sun8i_codec_common_widgets), +	.dapm_routes		= sun8i_codec_common_routes, +	.num_dapm_routes	= ARRAY_SIZE(sun8i_codec_common_routes), +	.probe			= sun8i_codec_analog_cmpnt_probe, +}; + +static const struct of_device_id sun8i_codec_analog_of_match[] = { +	{ +		.compatible = "allwinner,sun8i-a23-codec-analog", +		.data = &sun8i_a23_quirks, +	}, +	{ +		.compatible = "allwinner,sun8i-h3-codec-analog", +		.data = &sun8i_h3_quirks, +	}, +	{} +}; +MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match); + +static int sun8i_codec_analog_probe(struct platform_device *pdev) +{ +	struct resource *res; +	struct regmap *regmap; +	void __iomem *base; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(base)) { +		dev_err(&pdev->dev, "Failed to map the registers\n"); +		return PTR_ERR(base); +	} + +	regmap = devm_regmap_init(&pdev->dev, NULL, base, &adda_pr_regmap_cfg); +	if (IS_ERR(regmap)) { +		dev_err(&pdev->dev, "Failed to create regmap\n"); +		return PTR_ERR(regmap); +	} + +	return devm_snd_soc_register_component(&pdev->dev, +					       &sun8i_codec_analog_cmpnt_drv, +					       NULL, 0); +} + +static struct platform_driver sun8i_codec_analog_driver = { +	.driver = { +		.name = "sun8i-codec-analog", +		.of_match_table = sun8i_codec_analog_of_match, +	}, +	.probe = sun8i_codec_analog_probe, +}; +module_platform_driver(sun8i_codec_analog_driver); + +MODULE_DESCRIPTION("Allwinner internal codec analog controls driver"); +MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sun8i-codec-analog"); diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index deb597f7c302..eead6e7f205b 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -65,7 +65,7 @@ static int tegra_alc5632_asoc_hw_params(struct snd_pcm_substream *substream,  	return 0;  } -static struct snd_soc_ops tegra_alc5632_asoc_ops = { +static const struct snd_soc_ops tegra_alc5632_asoc_ops = {  	.hw_params = tegra_alc5632_asoc_hw_params,  }; diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c index 902da36581d1..a403db6d563e 100644 --- a/sound/soc/tegra/tegra_max98090.c +++ b/sound/soc/tegra/tegra_max98090.c @@ -93,7 +93,7 @@ static int tegra_max98090_asoc_hw_params(struct snd_pcm_substream *substream,  	return 0;  } -static struct snd_soc_ops tegra_max98090_ops = { +static const struct snd_soc_ops tegra_max98090_ops = {  	.hw_params = tegra_max98090_asoc_hw_params,  }; diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index e5ef4e9c4ac5..25b9fc03ba62 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c @@ -76,7 +76,7 @@ static int tegra_rt5640_asoc_hw_params(struct snd_pcm_substream *substream,  	return 0;  } -static struct snd_soc_ops tegra_rt5640_ops = { +static const struct snd_soc_ops tegra_rt5640_ops = {  	.hw_params = tegra_rt5640_asoc_hw_params,  }; diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c index 1470873ecde6..ebf58d0e0f10 100644 --- a/sound/soc/tegra/tegra_rt5677.c +++ b/sound/soc/tegra/tegra_rt5677.c @@ -93,7 +93,7 @@ static int tegra_rt5677_event_hp(struct snd_soc_dapm_widget *w,  	return 0;  } -static struct snd_soc_ops tegra_rt5677_ops = { +static const struct snd_soc_ops tegra_rt5677_ops = {  	.hw_params = tegra_rt5677_asoc_hw_params,  }; diff --git a/sound/soc/tegra/tegra_sgtl5000.c b/sound/soc/tegra/tegra_sgtl5000.c index 1e76869dd488..4bbab098f50b 100644 --- a/sound/soc/tegra/tegra_sgtl5000.c +++ b/sound/soc/tegra/tegra_sgtl5000.c @@ -82,7 +82,7 @@ static int tegra_sgtl5000_hw_params(struct snd_pcm_substream *substream,  	return 0;  } -static struct snd_soc_ops tegra_sgtl5000_ops = { +static const struct snd_soc_ops tegra_sgtl5000_ops = {  	.hw_params = tegra_sgtl5000_hw_params,  }; diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c index f0cd01dbfc38..bdedd1028569 100644 --- a/sound/soc/tegra/tegra_wm8753.c +++ b/sound/soc/tegra/tegra_wm8753.c @@ -89,7 +89,7 @@ static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream,  	return 0;  } -static struct snd_soc_ops tegra_wm8753_ops = { +static const struct snd_soc_ops tegra_wm8753_ops = {  	.hw_params = tegra_wm8753_hw_params,  }; diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index e485278e027a..2013e9c4bba0 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -96,7 +96,7 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream,  	return 0;  } -static struct snd_soc_ops tegra_wm8903_ops = { +static const struct snd_soc_ops tegra_wm8903_ops = {  	.hw_params = tegra_wm8903_hw_params,  }; diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c index 2cea203c4f5f..870f84ab5005 100644 --- a/sound/soc/tegra/trimslice.c +++ b/sound/soc/tegra/trimslice.c @@ -74,7 +74,7 @@ static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream,  	return 0;  } -static struct snd_soc_ops trimslice_asoc_ops = { +static const struct snd_soc_ops trimslice_asoc_ops = {  	.hw_params = trimslice_asoc_hw_params,  }; diff --git a/sound/soc/zte/Kconfig b/sound/soc/zte/Kconfig index c47eb25e441f..6d8a90d36315 100644 --- a/sound/soc/zte/Kconfig +++ b/sound/soc/zte/Kconfig @@ -1,17 +1,17 @@ -config ZX296702_SPDIF -	tristate "ZX296702 spdif" -	depends on SOC_ZX296702 || COMPILE_TEST +config ZX_SPDIF +	tristate "ZTE ZX SPDIF Driver Support" +	depends on ARCH_ZX || COMPILE_TEST  	depends on COMMON_CLK  	select SND_SOC_GENERIC_DMAENGINE_PCM  	help  	  Say Y or M if you want to add support for codecs attached to the -	  zx296702 spdif interface +	  ZTE ZX SPDIF interface -config ZX296702_I2S -	tristate "ZX296702 i2s" -	depends on SOC_ZX296702 || COMPILE_TEST +config ZX_I2S +	tristate "ZTE ZX I2S Driver Support" +	depends on ARCH_ZX || COMPILE_TEST  	depends on COMMON_CLK  	select SND_SOC_GENERIC_DMAENGINE_PCM  	help  	  Say Y or M if you want to add support for codecs attached to the -	  zx296702 i2s interface +	  ZTE ZX I2S interface diff --git a/sound/soc/zte/Makefile b/sound/soc/zte/Makefile index 254ed2c8c1a0..77768f5fd10c 100644 --- a/sound/soc/zte/Makefile +++ b/sound/soc/zte/Makefile @@ -1,2 +1,2 @@ -obj-$(CONFIG_ZX296702_SPDIF)	+= zx296702-spdif.o -obj-$(CONFIG_ZX296702_I2S)	+= zx296702-i2s.o +obj-$(CONFIG_ZX_SPDIF)	+= zx-spdif.o +obj-$(CONFIG_ZX_I2S)	+= zx-i2s.o diff --git a/sound/soc/zte/zx296702-i2s.c b/sound/soc/zte/zx-i2s.c index 1cad93dc1fcf..1cad93dc1fcf 100644 --- a/sound/soc/zte/zx296702-i2s.c +++ b/sound/soc/zte/zx-i2s.c diff --git a/sound/soc/zte/zx296702-spdif.c b/sound/soc/zte/zx-spdif.c index 26265ce4caca..9fa6463ce5d7 100644 --- a/sound/soc/zte/zx296702-spdif.c +++ b/sound/soc/zte/zx-spdif.c @@ -71,7 +71,7 @@  #define ZX_VALID_RIGHT_TRACK		(2 << 0)  #define ZX_VALID_TRACK_MASK		(3 << 0) -#define ZX_SPDIF_CLK_RAT		(4 * 32) +#define ZX_SPDIF_CLK_RAT		(2 * 32)  struct zx_spdif_info {  	struct snd_dmaengine_dai_dma_data	dma_data;  |