aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/ad1836.c
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2011-06-06 07:38:38 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-06-06 16:54:42 -0400
commit874ce77bc3027ce08e3ee35c3edad3b254e496d1 (patch)
tree043e77092f66ed9fff4da4f0276291d54469af80 /sound/soc/codecs/ad1836.c
parent2cf034282205a2115777b7a899f6f12d06943b62 (diff)
ASoC: AD1836: Add AD1835/AD1837/AD1838/AD1839 support
The AD183X codec devices are mostly register compatible and can easily be supported by the same driver. The main difference between those devices is the number of DACs and ADCs. This patch adjusts the driver to allocate the controls, DAPM widgets and routes for the DACs and ADCs dynamically based on the chip type. The AD1836 is a bit special in that it supports different modes for its second ADC, so it needs some special handling. Right now the driver hardcodes the mode to the differential PGA mode. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Acked-by: Liam Girdwood <lrg@ti.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/ad1836.c')
-rw-r--r--sound/soc/codecs/ad1836.c183
1 files changed, 129 insertions, 54 deletions
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index a2de8a571bfd..ad4c06760440 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -30,10 +30,17 @@
30#include <linux/spi/spi.h> 30#include <linux/spi/spi.h>
31#include "ad1836.h" 31#include "ad1836.h"
32 32
33enum ad1836_type {
34 AD1835,
35 AD1836,
36 AD1838,
37};
38
33/* codec private data */ 39/* codec private data */
34struct ad1836_priv { 40struct ad1836_priv {
35 enum snd_soc_control_type control_type; 41 enum snd_soc_control_type control_type;
36 void *control_data; 42 void *control_data;
43 enum ad1836_type type;
37}; 44};
38 45
39/* 46/*
@@ -56,21 +63,48 @@ static const struct soc_enum ad1836_deemp_enum =
56 SOC_DOUBLE("ADC" #x " Capture Switch", AD1836_ADC_CTRL2, \ 63 SOC_DOUBLE("ADC" #x " Capture Switch", AD1836_ADC_CTRL2, \
57 AD1836_MUTE_LEFT(x), AD1836_MUTE_RIGHT(x), 1, 1) 64 AD1836_MUTE_LEFT(x), AD1836_MUTE_RIGHT(x), 1, 1)
58 65
59static const struct snd_kcontrol_new ad1836_snd_controls[] = { 66static const struct snd_kcontrol_new ad183x_dac_controls[] = {
60 /* DAC volume control */
61 AD1836_DAC_VOLUME(1), 67 AD1836_DAC_VOLUME(1),
68 AD1836_DAC_SWITCH(1),
62 AD1836_DAC_VOLUME(2), 69 AD1836_DAC_VOLUME(2),
70 AD1836_DAC_SWITCH(2),
63 AD1836_DAC_VOLUME(3), 71 AD1836_DAC_VOLUME(3),
72 AD1836_DAC_SWITCH(3),
73 AD1836_DAC_VOLUME(4),
74 AD1836_DAC_SWITCH(4),
75};
76
77static const struct snd_soc_dapm_widget ad183x_dac_dapm_widgets[] = {
78 SND_SOC_DAPM_OUTPUT("DAC1OUT"),
79 SND_SOC_DAPM_OUTPUT("DAC2OUT"),
80 SND_SOC_DAPM_OUTPUT("DAC3OUT"),
81 SND_SOC_DAPM_OUTPUT("DAC4OUT"),
82};
83
84static const struct snd_soc_dapm_route ad183x_dac_routes[] = {
85 { "DAC1OUT", NULL, "DAC" },
86 { "DAC2OUT", NULL, "DAC" },
87 { "DAC3OUT", NULL, "DAC" },
88 { "DAC4OUT", NULL, "DAC" },
89};
64 90
65 /* ADC switch control */ 91static const struct snd_kcontrol_new ad183x_adc_controls[] = {
66 AD1836_ADC_SWITCH(1), 92 AD1836_ADC_SWITCH(1),
67 AD1836_ADC_SWITCH(2), 93 AD1836_ADC_SWITCH(2),
94 AD1836_ADC_SWITCH(3),
95};
68 96
69 /* DAC switch control */ 97static const struct snd_soc_dapm_widget ad183x_adc_dapm_widgets[] = {
70 AD1836_DAC_SWITCH(1), 98 SND_SOC_DAPM_INPUT("ADC1IN"),
71 AD1836_DAC_SWITCH(2), 99 SND_SOC_DAPM_INPUT("ADC2IN"),
72 AD1836_DAC_SWITCH(3), 100};
101
102static const struct snd_soc_dapm_route ad183x_adc_routes[] = {
103 { "ADC", NULL, "ADC1IN" },
104 { "ADC", NULL, "ADC2IN" },
105};
73 106
107static const struct snd_kcontrol_new ad183x_controls[] = {
74 /* ADC high-pass filter */ 108 /* ADC high-pass filter */
75 SOC_SINGLE("ADC High Pass Filter Switch", AD1836_ADC_CTRL1, 109 SOC_SINGLE("ADC High Pass Filter Switch", AD1836_ADC_CTRL1,
76 AD1836_ADC_HIGHPASS_FILTER, 1, 0), 110 AD1836_ADC_HIGHPASS_FILTER, 1, 0),
@@ -79,27 +113,17 @@ static const struct snd_kcontrol_new ad1836_snd_controls[] = {
79 SOC_ENUM("Playback Deemphasis", ad1836_deemp_enum), 113 SOC_ENUM("Playback Deemphasis", ad1836_deemp_enum),
80}; 114};
81 115
82static const struct snd_soc_dapm_widget ad1836_dapm_widgets[] = { 116static const struct snd_soc_dapm_widget ad183x_dapm_widgets[] = {
83 SND_SOC_DAPM_DAC("DAC", "Playback", AD1836_DAC_CTRL1, 117 SND_SOC_DAPM_DAC("DAC", "Playback", AD1836_DAC_CTRL1,
84 AD1836_DAC_POWERDOWN, 1), 118 AD1836_DAC_POWERDOWN, 1),
85 SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), 119 SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
86 SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1836_ADC_CTRL1, 120 SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1836_ADC_CTRL1,
87 AD1836_ADC_POWERDOWN, 1, NULL, 0), 121 AD1836_ADC_POWERDOWN, 1, NULL, 0),
88 SND_SOC_DAPM_OUTPUT("DAC1OUT"),
89 SND_SOC_DAPM_OUTPUT("DAC2OUT"),
90 SND_SOC_DAPM_OUTPUT("DAC3OUT"),
91 SND_SOC_DAPM_INPUT("ADC1IN"),
92 SND_SOC_DAPM_INPUT("ADC2IN"),
93}; 122};
94 123
95static const struct snd_soc_dapm_route audio_paths[] = { 124static const struct snd_soc_dapm_route ad183x_dapm_routes[] = {
96 { "DAC", NULL, "ADC_PWR" }, 125 { "DAC", NULL, "ADC_PWR" },
97 { "ADC", NULL, "ADC_PWR" }, 126 { "ADC", NULL, "ADC_PWR" },
98 { "DAC1OUT", "DAC1 Switch", "DAC" },
99 { "DAC2OUT", "DAC2 Switch", "DAC" },
100 { "DAC3OUT", "DAC3 Switch", "DAC" },
101 { "ADC", "ADC1 Switch", "ADC1IN" },
102 { "ADC", "ADC2 Switch", "ADC2IN" },
103}; 127};
104 128
105/* 129/*
@@ -194,33 +218,44 @@ static struct snd_soc_dai_ops ad1836_dai_ops = {
194 .set_fmt = ad1836_set_dai_fmt, 218 .set_fmt = ad1836_set_dai_fmt,
195}; 219};
196 220
197/* codec DAI instance */ 221#define AD183X_DAI(_name, num_dacs, num_adcs) \
198static struct snd_soc_dai_driver ad1836_dai = { 222{ \
199 .name = "ad1836-hifi", 223 .name = _name "-hifi", \
200 .playback = { 224 .playback = { \
201 .stream_name = "Playback", 225 .stream_name = "Playback", \
202 .channels_min = 2, 226 .channels_min = 2, \
203 .channels_max = 6, 227 .channels_max = (num_dacs) * 2, \
204 .rates = SNDRV_PCM_RATE_48000, 228 .rates = SNDRV_PCM_RATE_48000, \
205 .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | 229 .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | \
206 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, 230 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, \
207 }, 231 }, \
208 .capture = { 232 .capture = { \
209 .stream_name = "Capture", 233 .stream_name = "Capture", \
210 .channels_min = 2, 234 .channels_min = 2, \
211 .channels_max = 4, 235 .channels_max = (num_adcs) * 2, \
212 .rates = SNDRV_PCM_RATE_48000, 236 .rates = SNDRV_PCM_RATE_48000, \
213 .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | 237 .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | \
214 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, 238 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, \
215 }, 239 }, \
216 .ops = &ad1836_dai_ops, 240 .ops = &ad1836_dai_ops, \
241}
242
243static struct snd_soc_dai_driver ad183x_dais[] = {
244 [AD1835] = AD183X_DAI("ad1835", 4, 1),
245 [AD1836] = AD183X_DAI("ad1836", 3, 2),
246 [AD1838] = AD183X_DAI("ad1838", 3, 1),
217}; 247};
218 248
219static int ad1836_probe(struct snd_soc_codec *codec) 249static int ad1836_probe(struct snd_soc_codec *codec)
220{ 250{
221 struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec); 251 struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
222 struct snd_soc_dapm_context *dapm = &codec->dapm; 252 struct snd_soc_dapm_context *dapm = &codec->dapm;
253 int num_dacs, num_adcs;
223 int ret = 0; 254 int ret = 0;
255 int i;
256
257 num_dacs = ad183x_dais[ad1836->type].playback.channels_max / 2;
258 num_adcs = ad183x_dais[ad1836->type].capture.channels_max / 2;
224 259
225 codec->control_data = ad1836->control_data; 260 codec->control_data = ad1836->control_data;
226 ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI); 261 ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI);
@@ -239,21 +274,42 @@ static int ad1836_probe(struct snd_soc_codec *codec)
239 snd_soc_write(codec, AD1836_ADC_CTRL1, 0x100); 274 snd_soc_write(codec, AD1836_ADC_CTRL1, 0x100);
240 /* unmute adc channles, adc aux mode */ 275 /* unmute adc channles, adc aux mode */
241 snd_soc_write(codec, AD1836_ADC_CTRL2, 0x180); 276 snd_soc_write(codec, AD1836_ADC_CTRL2, 0x180);
242 /* left/right diff:PGA/MUX */
243 snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A);
244 /* volume */ 277 /* volume */
245 snd_soc_write(codec, AD1836_DAC_L_VOL(1), 0x3FF); 278 for (i = 1; i <= num_dacs; ++i) {
246 snd_soc_write(codec, AD1836_DAC_R_VOL(1), 0x3FF); 279 snd_soc_write(codec, AD1836_DAC_L_VOL(i), 0x3FF);
247 snd_soc_write(codec, AD1836_DAC_L_VOL(2), 0x3FF); 280 snd_soc_write(codec, AD1836_DAC_R_VOL(i), 0x3FF);
248 snd_soc_write(codec, AD1836_DAC_R_VOL(2), 0x3FF); 281 }
249 snd_soc_write(codec, AD1836_DAC_L_VOL(3), 0x3FF); 282
250 snd_soc_write(codec, AD1836_DAC_R_VOL(3), 0x3FF); 283 if (ad1836->type == AD1836) {
251 284 /* left/right diff:PGA/MUX */
252 snd_soc_add_controls(codec, ad1836_snd_controls, 285 snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A);
253 ARRAY_SIZE(ad1836_snd_controls)); 286 } else {
254 snd_soc_dapm_new_controls(dapm, ad1836_dapm_widgets, 287 snd_soc_write(codec, AD1836_ADC_CTRL3, 0x00);
255 ARRAY_SIZE(ad1836_dapm_widgets)); 288 }
256 snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths)); 289
290 ret = snd_soc_add_controls(codec, ad183x_dac_controls, num_dacs * 2);
291 if (ret)
292 return ret;
293
294 ret = snd_soc_add_controls(codec, ad183x_adc_controls, num_adcs);
295 if (ret)
296 return ret;
297
298 ret = snd_soc_dapm_new_controls(dapm, ad183x_dac_dapm_widgets, num_dacs);
299 if (ret)
300 return ret;
301
302 ret = snd_soc_dapm_new_controls(dapm, ad183x_adc_dapm_widgets, num_adcs);
303 if (ret)
304 return ret;
305
306 ret = snd_soc_dapm_add_routes(dapm, ad183x_dac_routes, num_dacs);
307 if (ret)
308 return ret;
309
310 ret = snd_soc_dapm_add_routes(dapm, ad183x_adc_routes, num_adcs);
311 if (ret)
312 return ret;
257 313
258 return ret; 314 return ret;
259} 315}
@@ -273,6 +329,13 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
273 .resume = ad1836_soc_resume, 329 .resume = ad1836_soc_resume,
274 .reg_cache_size = AD1836_NUM_REGS, 330 .reg_cache_size = AD1836_NUM_REGS,
275 .reg_word_size = sizeof(u16), 331 .reg_word_size = sizeof(u16),
332
333 .controls = ad183x_controls,
334 .num_controls = ARRAY_SIZE(ad183x_controls),
335 .dapm_widgets = ad183x_dapm_widgets,
336 .num_dapm_widgets = ARRAY_SIZE(ad183x_dapm_widgets),
337 .dapm_routes = ad183x_dapm_routes,
338 .num_dapm_routes = ARRAY_SIZE(ad183x_dapm_routes),
276}; 339};
277 340
278static int __devinit ad1836_spi_probe(struct spi_device *spi) 341static int __devinit ad1836_spi_probe(struct spi_device *spi)
@@ -284,12 +347,14 @@ static int __devinit ad1836_spi_probe(struct spi_device *spi)
284 if (ad1836 == NULL) 347 if (ad1836 == NULL)
285 return -ENOMEM; 348 return -ENOMEM;
286 349
350 ad1836->type = spi_get_device_id(spi)->driver_data;
351
287 spi_set_drvdata(spi, ad1836); 352 spi_set_drvdata(spi, ad1836);
288 ad1836->control_data = spi; 353 ad1836->control_data = spi;
289 ad1836->control_type = SND_SOC_SPI; 354 ad1836->control_type = SND_SOC_SPI;
290 355
291 ret = snd_soc_register_codec(&spi->dev, 356 ret = snd_soc_register_codec(&spi->dev,
292 &soc_codec_dev_ad1836, &ad1836_dai, 1); 357 &soc_codec_dev_ad1836, &ad183x_dais[ad1836->type], 1);
293 if (ret < 0) 358 if (ret < 0)
294 kfree(ad1836); 359 kfree(ad1836);
295 return ret; 360 return ret;
@@ -301,6 +366,15 @@ static int __devexit ad1836_spi_remove(struct spi_device *spi)
301 kfree(spi_get_drvdata(spi)); 366 kfree(spi_get_drvdata(spi));
302 return 0; 367 return 0;
303} 368}
369static const struct spi_device_id ad1836_ids[] = {
370 { "ad1835", AD1835 },
371 { "ad1836", AD1836 },
372 { "ad1837", AD1835 },
373 { "ad1838", AD1838 },
374 { "ad1839", AD1838 },
375 { },
376};
377MODULE_DEVICE_TABLE(spi, ad1836_ids);
304 378
305static struct spi_driver ad1836_spi_driver = { 379static struct spi_driver ad1836_spi_driver = {
306 .driver = { 380 .driver = {
@@ -309,6 +383,7 @@ static struct spi_driver ad1836_spi_driver = {
309 }, 383 },
310 .probe = ad1836_spi_probe, 384 .probe = ad1836_spi_probe,
311 .remove = __devexit_p(ad1836_spi_remove), 385 .remove = __devexit_p(ad1836_spi_remove),
386 .id_table = ad1836_ids,
312}; 387};
313 388
314static int __init ad1836_init(void) 389static int __init ad1836_init(void)