diff options
Diffstat (limited to 'sound/soc/codecs/mc13783.c')
| -rw-r--r-- | sound/soc/codecs/mc13783.c | 209 | 
1 files changed, 112 insertions, 97 deletions
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index ea141e1d6f2..9965277b595 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -22,6 +22,7 @@   */  #include <linux/module.h>  #include <linux/device.h> +#include <linux/of.h>  #include <linux/mfd/mc13xxx.h>  #include <linux/slab.h>  #include <sound/core.h> @@ -30,16 +31,10 @@  #include <sound/soc.h>  #include <sound/initval.h>  #include <sound/soc-dapm.h> +#include <linux/regmap.h>  #include "mc13783.h" -#define MC13783_AUDIO_RX0	36 -#define MC13783_AUDIO_RX1	37 -#define MC13783_AUDIO_TX	38 -#define MC13783_SSI_NETWORK	39 -#define MC13783_AUDIO_CODEC	40 -#define MC13783_AUDIO_DAC	41 -  #define AUDIO_RX0_ALSPEN		(1 << 5)  #define AUDIO_RX0_ALSPSEL		(1 << 7)  #define AUDIO_RX0_ADDCDC		(1 << 21) @@ -95,45 +90,12 @@  struct mc13783_priv {  	struct mc13xxx *mc13xxx; +	struct regmap *regmap;  	enum mc13783_ssi_port adc_ssi_port;  	enum mc13783_ssi_port dac_ssi_port;  }; -static unsigned int mc13783_read(struct snd_soc_codec *codec, -	unsigned int reg) -{ -	struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); -	unsigned int value = 0; - -	mc13xxx_lock(priv->mc13xxx); - -	mc13xxx_reg_read(priv->mc13xxx, reg, &value); - -	mc13xxx_unlock(priv->mc13xxx); - -	return value; -} - -static int mc13783_write(struct snd_soc_codec *codec, -	unsigned int reg, unsigned int value) -{ -	struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); -	int ret; - -	mc13xxx_lock(priv->mc13xxx); - -	ret = mc13xxx_reg_write(priv->mc13xxx, reg, value); - -	/* include errata fix for spi audio problems */ -	if (reg == MC13783_AUDIO_CODEC || reg == MC13783_AUDIO_DAC) -		ret = mc13xxx_reg_write(priv->mc13xxx, reg, value); - -	mc13xxx_unlock(priv->mc13xxx); - -	return ret; -} -  /* Mapping between sample rates and register value */  static unsigned int mc13783_rates[] = {  	8000, 11025, 12000, 16000, @@ -145,8 +107,7 @@ static int mc13783_pcm_hw_params_dac(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;  	unsigned int rate = params_rate(params);  	int i; @@ -165,8 +126,7 @@ static int mc13783_pcm_hw_params_codec(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;  	unsigned int rate = params_rate(params);  	unsigned int val; @@ -382,7 +342,7 @@ static int mc13783_set_tdm_slot_dac(struct snd_soc_dai *dai,  		break;  	default:  		return -EINVAL; -	}; +	}  	snd_soc_update_bits(codec, MC13783_SSI_NETWORK, mask, val); @@ -447,25 +407,46 @@ static const char * const adcl_enum_text[] = {  	"MC1L", "RXINL",  }; -static const struct soc_enum adcl_enum = -	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcl_enum_text), adcl_enum_text); +static SOC_ENUM_SINGLE_VIRT_DECL(adcl_enum, adcl_enum_text);  static const struct snd_kcontrol_new left_input_mux = -	SOC_DAPM_ENUM_VIRT("Route", adcl_enum); +	SOC_DAPM_ENUM("Route", adcl_enum);  static const char * const adcr_enum_text[] = {  	"MC1R", "MC2", "RXINR", "TXIN",  }; -static const struct soc_enum adcr_enum = -	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcr_enum_text), adcr_enum_text); +static SOC_ENUM_SINGLE_VIRT_DECL(adcr_enum, adcr_enum_text);  static const struct snd_kcontrol_new right_input_mux = -	SOC_DAPM_ENUM_VIRT("Route", adcr_enum); +	SOC_DAPM_ENUM("Route", adcr_enum);  static const struct snd_kcontrol_new samp_ctl =  	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 3, 1, 0); +static const char * const speaker_amp_source_text[] = { +	"CODEC", "Right" +}; +static SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4, +			    speaker_amp_source_text); +static const struct snd_kcontrol_new speaker_amp_source_mux = +	SOC_DAPM_ENUM("Speaker Amp Source MUX", speaker_amp_source); + +static const char * const headset_amp_source_text[] = { +	"CODEC", "Mixer" +}; + +static SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11, +			    headset_amp_source_text); +static const struct snd_kcontrol_new headset_amp_source_mux = +	SOC_DAPM_ENUM("Headset Amp Source MUX", headset_amp_source); + +static const struct snd_kcontrol_new cdcout_ctl = +	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 18, 1, 0); + +static const struct snd_kcontrol_new adc_bypass_ctl = +	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_CODEC, 16, 1, 0); +  static const struct snd_kcontrol_new lamp_ctl =  	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 5, 1, 0); @@ -498,17 +479,27 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {  	SND_SOC_DAPM_SWITCH("MC2 Amp", MC13783_AUDIO_TX, 9, 0, &mc2_amp_ctl),  	SND_SOC_DAPM_SWITCH("TXIN Amp", MC13783_AUDIO_TX, 11, 0, &atx_amp_ctl), -	SND_SOC_DAPM_VIRT_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0, +	SND_SOC_DAPM_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0,  			      &left_input_mux), -	SND_SOC_DAPM_VIRT_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0, +	SND_SOC_DAPM_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0,  			      &right_input_mux), +	SND_SOC_DAPM_MUX("Speaker Amp Source MUX", SND_SOC_NOPM, 0, 0, +			 &speaker_amp_source_mux), + +	SND_SOC_DAPM_MUX("Headset Amp Source MUX", SND_SOC_NOPM, 0, 0, +			 &headset_amp_source_mux), +  	SND_SOC_DAPM_PGA("PGA Left Input", SND_SOC_NOPM, 0, 0, NULL, 0),  	SND_SOC_DAPM_PGA("PGA Right Input", SND_SOC_NOPM, 0, 0, NULL, 0),  	SND_SOC_DAPM_ADC("ADC", "Capture", MC13783_AUDIO_CODEC, 11, 0),  	SND_SOC_DAPM_SUPPLY("ADC_Reset", MC13783_AUDIO_CODEC, 15, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Voice CODEC PGA", MC13783_AUDIO_RX1, 0, 0, NULL, 0), +	SND_SOC_DAPM_SWITCH("Voice CODEC Bypass", MC13783_AUDIO_CODEC, 16, 0, +			&adc_bypass_ctl), +  /* Output */  	SND_SOC_DAPM_SUPPLY("DAC_E", MC13783_AUDIO_DAC, 11, 0, NULL, 0),  	SND_SOC_DAPM_SUPPLY("DAC_Reset", MC13783_AUDIO_DAC, 15, 0, NULL, 0), @@ -516,10 +507,15 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {  	SND_SOC_DAPM_OUTPUT("RXOUTR"),  	SND_SOC_DAPM_OUTPUT("HSL"),  	SND_SOC_DAPM_OUTPUT("HSR"), +	SND_SOC_DAPM_OUTPUT("LSPL"),  	SND_SOC_DAPM_OUTPUT("LSP"),  	SND_SOC_DAPM_OUTPUT("SP"), +	SND_SOC_DAPM_OUTPUT("CDCOUT"), -	SND_SOC_DAPM_SWITCH("Speaker Amp", MC13783_AUDIO_RX0, 3, 0, &samp_ctl), +	SND_SOC_DAPM_SWITCH("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 0, +			&cdcout_ctl), +	SND_SOC_DAPM_SWITCH("Speaker Amp Switch", MC13783_AUDIO_RX0, 3, 0, +			&samp_ctl),  	SND_SOC_DAPM_SWITCH("Loudspeaker Amp", SND_SOC_NOPM, 0, 0, &lamp_ctl),  	SND_SOC_DAPM_SWITCH("Headset Amp Left", MC13783_AUDIO_RX0, 10, 0,  			&hlamp_ctl), @@ -554,42 +550,66 @@ static struct snd_soc_dapm_route mc13783_routes[] = {  	{ "ADC", NULL, "PGA Right Input"},  	{ "ADC", NULL, "ADC_Reset"}, +	{ "Voice CODEC PGA", "Voice CODEC Bypass", "ADC" }, + +	{ "Speaker Amp Source MUX", "CODEC", "Voice CODEC PGA"}, +	{ "Speaker Amp Source MUX", "Right", "DAC PGA"}, + +	{ "Headset Amp Source MUX", "CODEC", "Voice CODEC PGA"}, +	{ "Headset Amp Source MUX", "Mixer", "DAC PGA"}, +  /* Output */  	{ "HSL", NULL, "Headset Amp Left" },  	{ "HSR", NULL, "Headset Amp Right"},  	{ "RXOUTL", NULL, "Line out Amp Left"},  	{ "RXOUTR", NULL, "Line out Amp Right"}, -	{ "SP", NULL, "Speaker Amp"}, -	{ "Speaker Amp", NULL, "DAC PGA"}, -	{ "LSP", NULL, "DAC PGA"}, -	{ "Headset Amp Left", NULL, "DAC PGA"}, -	{ "Headset Amp Right", NULL, "DAC PGA"}, +	{ "SP", "Speaker Amp Switch", "Speaker Amp Source MUX"}, +	{ "LSP", "Loudspeaker Amp", "Speaker Amp Source MUX"}, +	{ "HSL", "Headset Amp Left", "Headset Amp Source MUX"}, +	{ "HSR", "Headset Amp Right", "Headset Amp Source MUX"},  	{ "Line out Amp Left", NULL, "DAC PGA"},  	{ "Line out Amp Right", NULL, "DAC PGA"},  	{ "DAC PGA", NULL, "DAC"},  	{ "DAC", NULL, "DAC_E"}, +	{ "CDCOUT", "CDCOUT Switch", "Voice CODEC PGA"},  };  static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix",  						"Mono", "Mono Mix"}; -static const struct soc_enum mc13783_enum_3d_mixer = -	SOC_ENUM_SINGLE(MC13783_AUDIO_RX1, 16, ARRAY_SIZE(mc13783_3d_mixer), -			mc13783_3d_mixer); +static SOC_ENUM_SINGLE_DECL(mc13783_enum_3d_mixer, +			    MC13783_AUDIO_RX1, 16, +			    mc13783_3d_mixer);  static struct snd_kcontrol_new mc13783_control_list[] = {  	SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0),  	SOC_SINGLE("PCM Playback Volume", MC13783_AUDIO_RX1, 6, 15, 0), +	SOC_SINGLE("PCM Playback Switch", MC13783_AUDIO_RX1, 5, 1, 0),  	SOC_DOUBLE("PCM Capture Volume", MC13783_AUDIO_TX, 19, 14, 31, 0),  	SOC_ENUM("3D Control", mc13783_enum_3d_mixer), + +	SOC_SINGLE("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 1, 0), +	SOC_SINGLE("Earpiece Amp Switch", MC13783_AUDIO_RX0, 3, 1, 0), +	SOC_DOUBLE("Headset Amp Switch", MC13783_AUDIO_RX0, 10, 9, 1, 0), +	SOC_DOUBLE("Line out Amp Switch", MC13783_AUDIO_RX0, 16, 15, 1, 0), + +	SOC_SINGLE("PCM Capture Mixin Switch", MC13783_AUDIO_RX0, 22, 1, 0), +	SOC_SINGLE("Line in Capture Mixin Switch", MC13783_AUDIO_RX0, 23, 1, 0), + +	SOC_SINGLE("CODEC Capture Volume", MC13783_AUDIO_RX1, 1, 15, 0), +	SOC_SINGLE("CODEC Capture Mixin Switch", MC13783_AUDIO_RX0, 21, 1, 0), + +	SOC_SINGLE("Line in Capture Volume", MC13783_AUDIO_RX1, 12, 15, 0), +	SOC_SINGLE("Line in Capture Switch", MC13783_AUDIO_RX1, 10, 1, 0), + +	SOC_SINGLE("MC1 Capture Bias Switch", MC13783_AUDIO_TX, 0, 1, 0), +	SOC_SINGLE("MC2 Capture Bias Switch", MC13783_AUDIO_TX, 1, 1, 0),  };  static int mc13783_probe(struct snd_soc_codec *codec)  {  	struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); -	mc13xxx_lock(priv->mc13xxx); -  	/* these are the reset values */  	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893);  	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX1, 0x00d35A); @@ -612,8 +632,6 @@ static int mc13783_probe(struct snd_soc_codec *codec)  		mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,  				0, AUDIO_SSI_SEL); -	mc13xxx_unlock(priv->mc13xxx); -  	return 0;  } @@ -621,13 +639,9 @@ static int mc13783_remove(struct snd_soc_codec *codec)  {  	struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); -	mc13xxx_lock(priv->mc13xxx); -  	/* Make sure VAUDIOON is off */  	mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_RX0, 0x3, 0); -	mc13xxx_unlock(priv->mc13xxx); -  	return 0;  } @@ -714,11 +728,15 @@ static struct snd_soc_dai_driver mc13783_dai_sync[] = {  	}  }; +static struct regmap *mc13783_get_regmap(struct device *dev) +{ +	return dev_get_regmap(dev->parent, NULL); +} +  static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {  	.probe		= mc13783_probe,  	.remove		= mc13783_remove, -	.read		= mc13783_read, -	.write		= mc13783_write, +	.get_regmap	= mc13783_get_regmap,  	.controls	= mc13783_control_list,  	.num_controls	= ARRAY_SIZE(mc13783_control_list),  	.dapm_widgets	= mc13783_dapm_widgets, @@ -727,30 +745,37 @@ static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {  	.num_dapm_routes = ARRAY_SIZE(mc13783_routes),  }; -static int mc13783_codec_probe(struct platform_device *pdev) +static int __init mc13783_codec_probe(struct platform_device *pdev)  { -	struct mc13xxx *mc13xxx;  	struct mc13783_priv *priv;  	struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data; +	struct device_node *np;  	int ret; -	mc13xxx = dev_get_drvdata(pdev->dev.parent); - -  	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -	if (priv == NULL) +	if (!priv)  		return -ENOMEM; -	dev_set_drvdata(&pdev->dev, priv); -	priv->mc13xxx = mc13xxx;  	if (pdata) {  		priv->adc_ssi_port = pdata->adc_ssi_port;  		priv->dac_ssi_port = pdata->dac_ssi_port;  	} else { -		priv->adc_ssi_port = MC13783_SSI1_PORT; -		priv->dac_ssi_port = MC13783_SSI2_PORT; +		np = of_get_child_by_name(pdev->dev.parent->of_node, "codec"); +		if (!np) +			return -ENOSYS; + +		ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port); +		if (ret) +			return ret; + +		ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port); +		if (ret) +			return ret;  	} +	dev_set_drvdata(&pdev->dev, priv); +	priv->mc13xxx = dev_get_drvdata(pdev->dev.parent); +  	if (priv->adc_ssi_port == priv->dac_ssi_port)  		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,  			mc13783_dai_sync, ARRAY_SIZE(mc13783_dai_sync)); @@ -758,14 +783,6 @@ static int mc13783_codec_probe(struct platform_device *pdev)  		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,  			mc13783_dai_async, ARRAY_SIZE(mc13783_dai_async)); -	if (ret) -		goto err_register_codec; - -	return 0; - -err_register_codec: -	dev_err(&pdev->dev, "register codec failed with %d\n", ret); -  	return ret;  } @@ -778,14 +795,12 @@ static int mc13783_codec_remove(struct platform_device *pdev)  static struct platform_driver mc13783_codec_driver = {  	.driver = { -		   .name = "mc13783-codec", -		   .owner = THIS_MODULE, -		   }, -	.probe = mc13783_codec_probe, +		.name	= "mc13783-codec", +		.owner	= THIS_MODULE, +	},  	.remove = mc13783_codec_remove,  }; - -module_platform_driver(mc13783_codec_driver); +module_platform_driver_probe(mc13783_codec_driver, mc13783_codec_probe);  MODULE_DESCRIPTION("ASoC MC13783 driver");  MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");  | 
