diff options
Diffstat (limited to 'sound/soc/codecs/ad1938.c')
| -rw-r--r-- | sound/soc/codecs/ad1938.c | 228 | 
1 files changed, 40 insertions, 188 deletions
| diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index 5d489186c05b..c233810d463d 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c @@ -46,6 +46,11 @@ struct ad1938_priv {  	u8 reg_cache[AD1938_NUM_REGS];  }; +/* ad1938 register cache & default register settings */ +static const u8 ad1938_reg[AD1938_NUM_REGS] = { +	0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, +}; +  static struct snd_soc_codec *ad1938_codec;  struct snd_soc_codec_device soc_codec_dev_ad1938;  static int ad1938_register(struct ad1938_priv *ad1938); @@ -97,6 +102,7 @@ static const struct snd_kcontrol_new ad1938_snd_controls[] = {  static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = {  	SND_SOC_DAPM_DAC("DAC", "Playback", AD1938_DAC_CTRL0, 0, 1),  	SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_SUPPLY("PLL_PWR", AD1938_PLL_CLK_CTRL0, 0, 1, NULL, 0),  	SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1938_ADC_CTRL0, 0, 1, NULL, 0),  	SND_SOC_DAPM_OUTPUT("DAC1OUT"),  	SND_SOC_DAPM_OUTPUT("DAC2OUT"), @@ -107,6 +113,8 @@ static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = {  };  static const struct snd_soc_dapm_route audio_paths[] = { +	{ "DAC", NULL, "PLL_PWR" }, +	{ "ADC", NULL, "PLL_PWR" },  	{ "DAC", NULL, "ADC_PWR" },  	{ "ADC", NULL, "ADC_PWR" },  	{ "DAC1OUT", "DAC1 Switch", "DAC" }, @@ -126,30 +134,20 @@ static int ad1938_mute(struct snd_soc_dai *dai, int mute)  	struct snd_soc_codec *codec = dai->codec;  	int reg; -	reg = codec->read(codec, AD1938_DAC_CTRL2); +	reg = snd_soc_read(codec, AD1938_DAC_CTRL2);  	reg = (mute > 0) ? reg | AD1938_DAC_MASTER_MUTE : reg &  		(~AD1938_DAC_MASTER_MUTE); -	codec->write(codec, AD1938_DAC_CTRL2, reg); - -	return 0; -} - -static inline int ad1938_pll_powerctrl(struct snd_soc_codec *codec, int cmd) -{ -	int reg = codec->read(codec, AD1938_PLL_CLK_CTRL0); -	reg = (cmd > 0) ? reg & (~AD1938_PLL_POWERDOWN) : reg | -		AD1938_PLL_POWERDOWN; -	codec->write(codec, AD1938_PLL_CLK_CTRL0, reg); +	snd_soc_write(codec, AD1938_DAC_CTRL2, reg);  	return 0;  }  static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, -			       unsigned int mask, int slots, int width) +			       unsigned int rx_mask, int slots, int width)  {  	struct snd_soc_codec *codec = dai->codec; -	int dac_reg = codec->read(codec, AD1938_DAC_CTRL1); -	int adc_reg = codec->read(codec, AD1938_ADC_CTRL2); +	int dac_reg = snd_soc_read(codec, AD1938_DAC_CTRL1); +	int adc_reg = snd_soc_read(codec, AD1938_ADC_CTRL2);  	dac_reg &= ~AD1938_DAC_CHAN_MASK;  	adc_reg &= ~AD1938_ADC_CHAN_MASK; @@ -175,8 +173,8 @@ static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,  		return -EINVAL;  	} -	codec->write(codec, AD1938_DAC_CTRL1, dac_reg); -	codec->write(codec, AD1938_ADC_CTRL2, adc_reg); +	snd_soc_write(codec, AD1938_DAC_CTRL1, dac_reg); +	snd_soc_write(codec, AD1938_ADC_CTRL2, adc_reg);  	return 0;  } @@ -187,8 +185,8 @@ static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai,  	struct snd_soc_codec *codec = codec_dai->codec;  	int adc_reg, dac_reg; -	adc_reg = codec->read(codec, AD1938_ADC_CTRL2); -	dac_reg = codec->read(codec, AD1938_DAC_CTRL1); +	adc_reg = snd_soc_read(codec, AD1938_ADC_CTRL2); +	dac_reg = snd_soc_read(codec, AD1938_DAC_CTRL1);  	/* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S  	 * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) @@ -265,8 +263,8 @@ static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai,  		return -EINVAL;  	} -	codec->write(codec, AD1938_ADC_CTRL2, adc_reg); -	codec->write(codec, AD1938_DAC_CTRL1, dac_reg); +	snd_soc_write(codec, AD1938_ADC_CTRL2, adc_reg); +	snd_soc_write(codec, AD1938_DAC_CTRL1, dac_reg);  	return 0;  } @@ -295,134 +293,13 @@ static int ad1938_hw_params(struct snd_pcm_substream *substream,  		break;  	} -	reg = codec->read(codec, AD1938_DAC_CTRL2); +	reg = snd_soc_read(codec, AD1938_DAC_CTRL2);  	reg = (reg & (~AD1938_DAC_WORD_LEN_MASK)) | word_len; -	codec->write(codec, AD1938_DAC_CTRL2, reg); +	snd_soc_write(codec, AD1938_DAC_CTRL2, reg); -	reg = codec->read(codec, AD1938_ADC_CTRL1); +	reg = snd_soc_read(codec, AD1938_ADC_CTRL1);  	reg = (reg & (~AD1938_ADC_WORD_LEN_MASK)) | word_len; -	codec->write(codec, AD1938_ADC_CTRL1, reg); - -	return 0; -} - -static int ad1938_set_bias_level(struct snd_soc_codec *codec, -		enum snd_soc_bias_level level) -{ -	switch (level) { -	case SND_SOC_BIAS_ON: -		ad1938_pll_powerctrl(codec, 1); -		break; -	case SND_SOC_BIAS_PREPARE: -		break; -	case SND_SOC_BIAS_STANDBY: -	case SND_SOC_BIAS_OFF: -		ad1938_pll_powerctrl(codec, 0); -		break; -	} -	codec->bias_level = level; -	return 0; -} - -/* - * interface to read/write ad1938 register - */ - -#define AD1938_SPI_ADDR    0x4 -#define AD1938_SPI_READ    0x1 -#define AD1938_SPI_BUFLEN  3 - -/* - * write to the ad1938 register space - */ - -static int ad1938_write_reg(struct snd_soc_codec *codec, unsigned int reg, -		unsigned int value) -{ -	u8 *reg_cache = codec->reg_cache; -	int ret = 0; - -	if (value != reg_cache[reg]) { -		uint8_t buf[AD1938_SPI_BUFLEN]; -		struct spi_transfer t = { -			.tx_buf = buf, -			.len = AD1938_SPI_BUFLEN, -		}; -		struct spi_message m; - -		buf[0] = AD1938_SPI_ADDR << 1; -		buf[1] = reg; -		buf[2] = value; -		spi_message_init(&m); -		spi_message_add_tail(&t, &m); -		ret = spi_sync(codec->control_data, &m); -		if (ret == 0) -			reg_cache[reg] = value; -	} - -	return ret; -} - -/* - * read from the ad1938 register space cache - */ - -static unsigned int ad1938_read_reg_cache(struct snd_soc_codec *codec, -					  unsigned int reg) -{ -	u8 *reg_cache = codec->reg_cache; - -	if (reg >= codec->reg_cache_size) -		return -EINVAL; - -	return reg_cache[reg]; -} - -/* - * read from the ad1938 register space - */ - -static unsigned int ad1938_read_reg(struct snd_soc_codec *codec, -						unsigned int reg) -{ -	char w_buf[AD1938_SPI_BUFLEN]; -	char r_buf[AD1938_SPI_BUFLEN]; -	int ret; - -	struct spi_transfer t = { -		.tx_buf = w_buf, -		.rx_buf = r_buf, -		.len = AD1938_SPI_BUFLEN, -	}; -	struct spi_message m; - -	w_buf[0] = (AD1938_SPI_ADDR << 1) | AD1938_SPI_READ; -	w_buf[1] = reg; -	w_buf[2] = 0; - -	spi_message_init(&m); -	spi_message_add_tail(&t, &m); -	ret = spi_sync(codec->control_data, &m); -	if (ret == 0) -		return	r_buf[2]; -	else -		return -EIO; -} - -static int ad1938_fill_cache(struct snd_soc_codec *codec) -{ -	int i; -	u8 *reg_cache = codec->reg_cache; -	struct spi_device *spi = codec->control_data; - -	for (i = 0; i < codec->reg_cache_size; i++) { -		int ret = ad1938_read_reg(codec, i); -		if (ret == -EIO) { -			dev_err(&spi->dev, "AD1938 SPI read failure\n"); -			return ret; -		} -		reg_cache[i] = ret; -	} +	snd_soc_write(codec, AD1938_ADC_CTRL1, reg);  	return 0;  } @@ -512,32 +389,37 @@ static int ad1938_register(struct ad1938_priv *ad1938)  	codec->owner = THIS_MODULE;  	codec->dai = &ad1938_dai;  	codec->num_dai = 1; -	codec->write = ad1938_write_reg; -	codec->read = ad1938_read_reg_cache; -	codec->set_bias_level = ad1938_set_bias_level;  	INIT_LIST_HEAD(&codec->dapm_widgets);  	INIT_LIST_HEAD(&codec->dapm_paths);  	ad1938_dai.dev = codec->dev;  	ad1938_codec = codec; +	memcpy(codec->reg_cache, ad1938_reg, AD1938_NUM_REGS); + +	ret = snd_soc_codec_set_cache_io(codec, 16, 8, SND_SOC_SPI); +	if (ret < 0) { +		dev_err(codec->dev, "failed to set cache I/O: %d\n", +				ret); +		kfree(ad1938); +		return ret; +	} +  	/* default setting for ad1938 */  	/* unmute dac channels */ -	codec->write(codec, AD1938_DAC_CHNL_MUTE, 0x0); +	snd_soc_write(codec, AD1938_DAC_CHNL_MUTE, 0x0);  	/* de-emphasis: 48kHz, powedown dac */ -	codec->write(codec, AD1938_DAC_CTRL2, 0x1A); +	snd_soc_write(codec, AD1938_DAC_CTRL2, 0x1A);  	/* powerdown dac, dac in tdm mode */ -	codec->write(codec, AD1938_DAC_CTRL0, 0x41); +	snd_soc_write(codec, AD1938_DAC_CTRL0, 0x41);  	/* high-pass filter enable */ -	codec->write(codec, AD1938_ADC_CTRL0, 0x3); +	snd_soc_write(codec, AD1938_ADC_CTRL0, 0x3);  	/* sata delay=1, adc aux mode */ -	codec->write(codec, AD1938_ADC_CTRL1, 0x43); +	snd_soc_write(codec, AD1938_ADC_CTRL1, 0x43);  	/* pll input: mclki/xi */ -	codec->write(codec, AD1938_PLL_CLK_CTRL0, 0x9D); -	codec->write(codec, AD1938_PLL_CLK_CTRL1, 0x04); - -	ad1938_fill_cache(codec); +	snd_soc_write(codec, AD1938_PLL_CLK_CTRL0, 0x9D); +	snd_soc_write(codec, AD1938_PLL_CLK_CTRL1, 0x04);  	ret = snd_soc_register_codec(codec);  	if (ret != 0) { @@ -559,7 +441,6 @@ static int ad1938_register(struct ad1938_priv *ad1938)  static void ad1938_unregister(struct ad1938_priv *ad1938)  { -	ad1938_set_bias_level(&ad1938->codec, SND_SOC_BIAS_OFF);  	snd_soc_unregister_dai(&ad1938_dai);  	snd_soc_unregister_codec(&ad1938->codec);  	kfree(ad1938); @@ -593,7 +474,6 @@ static int ad1938_probe(struct platform_device *pdev)  				  ARRAY_SIZE(ad1938_dapm_widgets));  	snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); -	ad1938_set_bias_level(codec, SND_SOC_BIAS_STANDBY);  pcm_err:  	return ret; @@ -610,37 +490,9 @@ static int ad1938_remove(struct platform_device *pdev)  	return 0;  } -#ifdef CONFIG_PM -static int ad1938_suspend(struct platform_device *pdev, -		pm_message_t state) -{ -	struct snd_soc_device *socdev = platform_get_drvdata(pdev); -	struct snd_soc_codec *codec = socdev->card->codec; - -	ad1938_set_bias_level(codec, SND_SOC_BIAS_OFF); -	return 0; -} - -static int ad1938_resume(struct platform_device *pdev) -{ -	struct snd_soc_device *socdev = platform_get_drvdata(pdev); -	struct snd_soc_codec *codec = socdev->card->codec; - -	if (codec->suspend_bias_level == SND_SOC_BIAS_ON) -		ad1938_set_bias_level(codec, SND_SOC_BIAS_ON); - -	return 0; -} -#else -#define ad1938_suspend NULL -#define ad1938_resume NULL -#endif -  struct snd_soc_codec_device soc_codec_dev_ad1938 = {  	.probe = 	ad1938_probe,  	.remove = 	ad1938_remove, -	.suspend =      ad1938_suspend, -	.resume =       ad1938_resume,  };  EXPORT_SYMBOL_GPL(soc_codec_dev_ad1938); | 
