|
|
|
@ -19,6 +19,8 @@ |
|
|
|
|
#include <sound/soc.h> |
|
|
|
|
#include <sound/tlv.h> |
|
|
|
|
#include <linux/spi/spi.h> |
|
|
|
|
#include <linux/regmap.h> |
|
|
|
|
|
|
|
|
|
#include "ad1836.h" |
|
|
|
|
|
|
|
|
|
enum ad1836_type { |
|
|
|
@ -30,6 +32,7 @@ enum ad1836_type { |
|
|
|
|
/* codec private data */ |
|
|
|
|
struct ad1836_priv { |
|
|
|
|
enum ad1836_type type; |
|
|
|
|
struct regmap *regmap; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -161,8 +164,8 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream, |
|
|
|
|
struct snd_pcm_hw_params *params, |
|
|
|
|
struct snd_soc_dai *dai) |
|
|
|
|
{ |
|
|
|
|
struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(dai->codec); |
|
|
|
|
int word_len = 0; |
|
|
|
|
struct snd_soc_codec *codec = dai->codec; |
|
|
|
|
|
|
|
|
|
/* bit size */ |
|
|
|
|
switch (params_format(params)) { |
|
|
|
@ -178,10 +181,12 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream, |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
snd_soc_update_bits(codec, AD1836_DAC_CTRL1, AD1836_DAC_WORD_LEN_MASK, |
|
|
|
|
regmap_update_bits(ad1836->regmap, AD1836_DAC_CTRL1, |
|
|
|
|
AD1836_DAC_WORD_LEN_MASK, |
|
|
|
|
word_len << AD1836_DAC_WORD_LEN_OFFSET); |
|
|
|
|
|
|
|
|
|
snd_soc_update_bits(codec, AD1836_ADC_CTRL2, AD1836_ADC_WORD_LEN_MASK, |
|
|
|
|
regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2, |
|
|
|
|
AD1836_ADC_WORD_LEN_MASK, |
|
|
|
|
word_len << AD1836_ADC_WORD_OFFSET); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
@ -223,15 +228,17 @@ static struct snd_soc_dai_driver ad183x_dais[] = { |
|
|
|
|
#ifdef CONFIG_PM |
|
|
|
|
static int ad1836_suspend(struct snd_soc_codec *codec) |
|
|
|
|
{ |
|
|
|
|
struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec); |
|
|
|
|
/* reset clock control mode */ |
|
|
|
|
return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, |
|
|
|
|
return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2, |
|
|
|
|
AD1836_ADC_SERFMT_MASK, 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int ad1836_resume(struct snd_soc_codec *codec) |
|
|
|
|
{ |
|
|
|
|
struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec); |
|
|
|
|
/* restore clock control mode */ |
|
|
|
|
return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, |
|
|
|
|
return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2, |
|
|
|
|
AD1836_ADC_SERFMT_MASK, AD1836_ADC_AUX); |
|
|
|
|
} |
|
|
|
|
#else |
|
|
|
@ -250,37 +257,30 @@ static int ad1836_probe(struct snd_soc_codec *codec) |
|
|
|
|
num_dacs = ad183x_dais[ad1836->type].playback.channels_max / 2; |
|
|
|
|
num_adcs = ad183x_dais[ad1836->type].capture.channels_max / 2; |
|
|
|
|
|
|
|
|
|
ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
dev_err(codec->dev, "failed to set cache I/O: %d\n", |
|
|
|
|
ret); |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* default setting for ad1836 */ |
|
|
|
|
/* de-emphasis: 48kHz, power-on dac */ |
|
|
|
|
snd_soc_write(codec, AD1836_DAC_CTRL1, 0x300); |
|
|
|
|
regmap_write(ad1836->regmap, AD1836_DAC_CTRL1, 0x300); |
|
|
|
|
/* unmute dac channels */ |
|
|
|
|
snd_soc_write(codec, AD1836_DAC_CTRL2, 0x0); |
|
|
|
|
regmap_write(ad1836->regmap, AD1836_DAC_CTRL2, 0x0); |
|
|
|
|
/* high-pass filter enable, power-on adc */ |
|
|
|
|
snd_soc_write(codec, AD1836_ADC_CTRL1, 0x100); |
|
|
|
|
regmap_write(ad1836->regmap, AD1836_ADC_CTRL1, 0x100); |
|
|
|
|
/* unmute adc channles, adc aux mode */ |
|
|
|
|
snd_soc_write(codec, AD1836_ADC_CTRL2, 0x180); |
|
|
|
|
regmap_write(ad1836->regmap, AD1836_ADC_CTRL2, 0x180); |
|
|
|
|
/* volume */ |
|
|
|
|
for (i = 1; i <= num_dacs; ++i) { |
|
|
|
|
snd_soc_write(codec, AD1836_DAC_L_VOL(i), 0x3FF); |
|
|
|
|
snd_soc_write(codec, AD1836_DAC_R_VOL(i), 0x3FF); |
|
|
|
|
regmap_write(ad1836->regmap, AD1836_DAC_L_VOL(i), 0x3FF); |
|
|
|
|
regmap_write(ad1836->regmap, AD1836_DAC_R_VOL(i), 0x3FF); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (ad1836->type == AD1836) { |
|
|
|
|
/* left/right diff:PGA/MUX */ |
|
|
|
|
snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A); |
|
|
|
|
regmap_write(ad1836->regmap, AD1836_ADC_CTRL3, 0x3A); |
|
|
|
|
ret = snd_soc_add_codec_controls(codec, ad1836_controls, |
|
|
|
|
ARRAY_SIZE(ad1836_controls)); |
|
|
|
|
if (ret) |
|
|
|
|
return ret; |
|
|
|
|
} else { |
|
|
|
|
snd_soc_write(codec, AD1836_ADC_CTRL3, 0x00); |
|
|
|
|
regmap_write(ad1836->regmap, AD1836_ADC_CTRL3, 0x00); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ret = snd_soc_add_codec_controls(codec, ad183x_dac_controls, num_dacs * 2); |
|
|
|
@ -313,8 +313,9 @@ static int ad1836_probe(struct snd_soc_codec *codec) |
|
|
|
|
/* power down chip */ |
|
|
|
|
static int ad1836_remove(struct snd_soc_codec *codec) |
|
|
|
|
{ |
|
|
|
|
struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec); |
|
|
|
|
/* reset clock control mode */ |
|
|
|
|
return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, |
|
|
|
|
return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2, |
|
|
|
|
AD1836_ADC_SERFMT_MASK, 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -323,8 +324,6 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1836 = { |
|
|
|
|
.remove = ad1836_remove, |
|
|
|
|
.suspend = ad1836_suspend, |
|
|
|
|
.resume = ad1836_resume, |
|
|
|
|
.reg_cache_size = AD1836_NUM_REGS, |
|
|
|
|
.reg_word_size = sizeof(u16), |
|
|
|
|
|
|
|
|
|
.controls = ad183x_controls, |
|
|
|
|
.num_controls = ARRAY_SIZE(ad183x_controls), |
|
|
|
@ -334,6 +333,33 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1836 = { |
|
|
|
|
.num_dapm_routes = ARRAY_SIZE(ad183x_dapm_routes), |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static const struct reg_default ad1836_reg_defaults[] = { |
|
|
|
|
{ AD1836_DAC_CTRL1, 0x0000 }, |
|
|
|
|
{ AD1836_DAC_CTRL2, 0x0000 }, |
|
|
|
|
{ AD1836_DAC_L_VOL(0), 0x0000 }, |
|
|
|
|
{ AD1836_DAC_R_VOL(0), 0x0000 }, |
|
|
|
|
{ AD1836_DAC_L_VOL(1), 0x0000 }, |
|
|
|
|
{ AD1836_DAC_R_VOL(1), 0x0000 }, |
|
|
|
|
{ AD1836_DAC_L_VOL(2), 0x0000 }, |
|
|
|
|
{ AD1836_DAC_R_VOL(2), 0x0000 }, |
|
|
|
|
{ AD1836_DAC_L_VOL(3), 0x0000 }, |
|
|
|
|
{ AD1836_DAC_R_VOL(3), 0x0000 }, |
|
|
|
|
{ AD1836_ADC_CTRL1, 0x0000 }, |
|
|
|
|
{ AD1836_ADC_CTRL2, 0x0000 }, |
|
|
|
|
{ AD1836_ADC_CTRL3, 0x0000 }, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static const struct regmap_config ad1836_regmap_config = { |
|
|
|
|
.val_bits = 12, |
|
|
|
|
.reg_bits = 4, |
|
|
|
|
.read_flag_mask = 0x08, |
|
|
|
|
|
|
|
|
|
.max_register = AD1836_ADC_CTRL3, |
|
|
|
|
.reg_defaults = ad1836_reg_defaults, |
|
|
|
|
.num_reg_defaults = ARRAY_SIZE(ad1836_reg_defaults), |
|
|
|
|
.cache_type = REGCACHE_RBTREE, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static int __devinit ad1836_spi_probe(struct spi_device *spi) |
|
|
|
|
{ |
|
|
|
|
struct ad1836_priv *ad1836; |
|
|
|
@ -344,6 +370,10 @@ static int __devinit ad1836_spi_probe(struct spi_device *spi) |
|
|
|
|
if (ad1836 == NULL) |
|
|
|
|
return -ENOMEM; |
|
|
|
|
|
|
|
|
|
ad1836->regmap = devm_regmap_init_spi(spi, &ad1836_regmap_config); |
|
|
|
|
if (IS_ERR(ad1836->regmap)) |
|
|
|
|
return PTR_ERR(ad1836->regmap); |
|
|
|
|
|
|
|
|
|
ad1836->type = spi_get_device_id(spi)->driver_data; |
|
|
|
|
|
|
|
|
|
spi_set_drvdata(spi, ad1836); |
|
|
|
|