[alsa-devel] [PATCH 8/8] ASoC: AD183x: add support for more multiple parts
Mike Frysinger
vapier at gentoo.org
Tue Jun 14 23:34:28 CEST 2011
From: Barry Song <barry.song at analog.com>
This extends the AD1836 codec driver to also support the parts:
- AD1835A
- AD1837A
- AD1838A
- AD1839A
Signed-off-by: Barry Song <barry.song at analog.com>
Signed-off-by: Scott Jiang <scott.jiang at analog.com>
Signed-off-by: Mike Frysinger <vapier at gentoo.org>
---
sound/soc/codecs/ad183x.c | 217 ++++++++++++++++++++++++++++++++++++++++-----
sound/soc/codecs/ad183x.h | 7 ++-
2 files changed, 199 insertions(+), 25 deletions(-)
diff --git a/sound/soc/codecs/ad183x.c b/sound/soc/codecs/ad183x.c
index 21567ce..5a13599 100644
--- a/sound/soc/codecs/ad183x.c
+++ b/sound/soc/codecs/ad183x.c
@@ -1,5 +1,6 @@
/*
- * Audio Codec driver supporting AD1836
+ * Audio Codec driver supporting:
+ * AD1835A, AD1836, AD1837A, AD1838A, AD1839A
*
* Copyright 2009-2011 Analog Devices Inc.
*
@@ -21,9 +22,19 @@
#include "ad183x.h"
/* codec private data */
+struct ad183x_chl_ctrls {
+ const struct snd_kcontrol_new *snd_ctrls;
+ const struct snd_soc_dapm_widget *dapm_widgets;
+ const struct snd_soc_dapm_route *audio_paths;
+ int ctrl_num;
+ int widget_num;
+ int path_num;
+ int play_max, capt_max;
+};
+
struct ad183x_priv {
enum snd_soc_control_type control_type;
- void *control_data;
+ const struct ad183x_chl_ctrls *chl_ctrl;
};
/*
@@ -34,7 +45,76 @@ static const char *ad183x_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"};
static const struct soc_enum ad183x_deemp_enum =
SOC_ENUM_SINGLE(AD183X_DAC_CTRL1, 8, 4, ad183x_deemp);
-static const struct snd_kcontrol_new ad183x_snd_controls[] = {
+/* AD1835A/AD1837A: 4 stereo DAC, 1 stereo ADC; */
+static const struct snd_kcontrol_new ad1835a_ad1837a_snd_controls[] = {
+ /* DAC volume control */
+ SOC_DOUBLE_R("DAC1 Volume", AD183X_DAC_L1_VOL,
+ AD183X_DAC_R1_VOL, 0, 0x3FF, 0),
+ SOC_DOUBLE_R("DAC2 Volume", AD183X_DAC_L2_VOL,
+ AD183X_DAC_R2_VOL, 0, 0x3FF, 0),
+ SOC_DOUBLE_R("DAC3 Volume", AD183X_DAC_L3_VOL,
+ AD183X_DAC_R3_VOL, 0, 0x3FF, 0),
+ SOC_DOUBLE_R("DAC4 Volume", AD183X_DAC_L4_VOL,
+ AD183X_DAC_R4_VOL, 0, 0x3FF, 0),
+
+ /* ADC switch control */
+ SOC_DOUBLE("ADC1 Switch", AD183X_ADC_CTRL2, AD183X_ADCL1_MUTE,
+ AD183X_ADCR1_MUTE, 1, 1),
+
+ /* DAC switch control */
+ SOC_DOUBLE("DAC1 Switch", AD183X_DAC_CTRL2, AD183X_DACL1_MUTE,
+ AD183X_DACR1_MUTE, 1, 1),
+ SOC_DOUBLE("DAC2 Switch", AD183X_DAC_CTRL2, AD183X_DACL2_MUTE,
+ AD183X_DACR2_MUTE, 1, 1),
+ SOC_DOUBLE("DAC3 Switch", AD183X_DAC_CTRL2, AD183X_DACL3_MUTE,
+ AD183X_DACR3_MUTE, 1, 1),
+ SOC_DOUBLE("DAC4 Switch", AD183X_DAC_CTRL2, AD183X_DACL4_MUTE,
+ AD183X_DACR4_MUTE, 1, 1),
+
+ /* ADC high-pass filter */
+ SOC_SINGLE("ADC High Pass Filter Switch", AD183X_ADC_CTRL1,
+ AD183X_ADC_HIGHPASS_FILTER, 1, 0),
+
+ /* DAC de-emphasis */
+ SOC_ENUM("Playback Deemphasis", ad183x_deemp_enum),
+};
+
+static const struct snd_soc_dapm_widget ad1835a_ad1837a_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("DAC", "Playback", AD183X_DAC_CTRL1,
+ AD183X_DAC_POWERDOWN, 1),
+ SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_SUPPLY("ADC_PWR", AD183X_ADC_CTRL1,
+ AD183X_ADC_POWERDOWN, 1, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("DAC1OUT"),
+ SND_SOC_DAPM_OUTPUT("DAC2OUT"),
+ SND_SOC_DAPM_OUTPUT("DAC3OUT"),
+ SND_SOC_DAPM_OUTPUT("DAC4OUT"),
+ SND_SOC_DAPM_INPUT("ADC1IN"),
+};
+
+static const struct snd_soc_dapm_route ad1835a_ad1837a_audio_paths[] = {
+ { "DAC", NULL, "ADC_PWR" },
+ { "ADC", NULL, "ADC_PWR" },
+ { "DAC1OUT", "DAC1 Switch", "DAC" },
+ { "DAC2OUT", "DAC2 Switch", "DAC" },
+ { "DAC3OUT", "DAC3 Switch", "DAC" },
+ { "DAC3OUT", "DAC4 Switch", "DAC" },
+ { "ADC", "ADC1 Switch", "ADC1IN" },
+};
+
+static const struct ad183x_chl_ctrls ad1835a_ad1837a_chl_ctrls = {
+ .snd_ctrls = ad1835a_ad1837a_snd_controls,
+ .dapm_widgets = ad1835a_ad1837a_dapm_widgets,
+ .audio_paths = ad1835a_ad1837a_audio_paths,
+ .ctrl_num = ARRAY_SIZE(ad1835a_ad1837a_snd_controls),
+ .widget_num = ARRAY_SIZE(ad1835a_ad1837a_dapm_widgets),
+ .path_num = ARRAY_SIZE(ad1835a_ad1837a_audio_paths),
+ .play_max = 8,
+ .capt_max = 2,
+};
+
+/* AD1836: 3 stereo DAC, 2 stereo ADC; */
+static const struct snd_kcontrol_new ad1836_snd_controls[] = {
/* DAC volume control */
SOC_DOUBLE_R("DAC1 Volume", AD183X_DAC_L1_VOL,
AD183X_DAC_R1_VOL, 0, 0x3FF, 0),
@@ -45,17 +125,17 @@ static const struct snd_kcontrol_new ad183x_snd_controls[] = {
/* ADC switch control */
SOC_DOUBLE("ADC1 Switch", AD183X_ADC_CTRL2, AD183X_ADCL1_MUTE,
- AD183X_ADCR1_MUTE, 1, 1),
+ AD183X_ADCR1_MUTE, 1, 1),
SOC_DOUBLE("ADC2 Switch", AD183X_ADC_CTRL2, AD183X_ADCL2_MUTE,
- AD183X_ADCR2_MUTE, 1, 1),
+ AD183X_ADCR2_MUTE, 1, 1),
/* DAC switch control */
SOC_DOUBLE("DAC1 Switch", AD183X_DAC_CTRL2, AD183X_DACL1_MUTE,
- AD183X_DACR1_MUTE, 1, 1),
+ AD183X_DACR1_MUTE, 1, 1),
SOC_DOUBLE("DAC2 Switch", AD183X_DAC_CTRL2, AD183X_DACL2_MUTE,
- AD183X_DACR2_MUTE, 1, 1),
+ AD183X_DACR2_MUTE, 1, 1),
SOC_DOUBLE("DAC3 Switch", AD183X_DAC_CTRL2, AD183X_DACL3_MUTE,
- AD183X_DACR3_MUTE, 1, 1),
+ AD183X_DACR3_MUTE, 1, 1),
/* ADC high-pass filter */
SOC_SINGLE("ADC High Pass Filter Switch", AD183X_ADC_CTRL1,
@@ -65,12 +145,12 @@ static const struct snd_kcontrol_new ad183x_snd_controls[] = {
SOC_ENUM("Playback Deemphasis", ad183x_deemp_enum),
};
-static const struct snd_soc_dapm_widget ad183x_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget ad1836_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DAC", "Playback", AD183X_DAC_CTRL1,
- AD183X_DAC_POWERDOWN, 1),
+ AD183X_DAC_POWERDOWN, 1),
SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_SUPPLY("ADC_PWR", AD183X_ADC_CTRL1,
- AD183X_ADC_POWERDOWN, 1, NULL, 0),
+ AD183X_ADC_POWERDOWN, 1, NULL, 0),
SND_SOC_DAPM_OUTPUT("DAC1OUT"),
SND_SOC_DAPM_OUTPUT("DAC2OUT"),
SND_SOC_DAPM_OUTPUT("DAC3OUT"),
@@ -78,7 +158,7 @@ static const struct snd_soc_dapm_widget ad183x_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("ADC2IN"),
};
-static const struct snd_soc_dapm_route audio_paths[] = {
+static const struct snd_soc_dapm_route ad1836_audio_paths[] = {
{ "DAC", NULL, "ADC_PWR" },
{ "ADC", NULL, "ADC_PWR" },
{ "DAC1OUT", "DAC1 Switch", "DAC" },
@@ -88,6 +168,79 @@ static const struct snd_soc_dapm_route audio_paths[] = {
{ "ADC", "ADC2 Switch", "ADC2IN" },
};
+static const struct ad183x_chl_ctrls ad1836_chl_ctrls = {
+ .snd_ctrls = ad1836_snd_controls,
+ .dapm_widgets = ad1836_dapm_widgets,
+ .audio_paths = ad1836_audio_paths,
+ .ctrl_num = ARRAY_SIZE(ad1836_snd_controls),
+ .widget_num = ARRAY_SIZE(ad1836_dapm_widgets),
+ .path_num = ARRAY_SIZE(ad1836_audio_paths),
+ .play_max = 6,
+ .capt_max = 4,
+};
+
+/* AD1838A/AD1939A: 3 stereo DAC, 1 stereo ADC; */
+static const struct snd_kcontrol_new ad1838a_ad1839a_snd_controls[] = {
+ /* DAC volume control */
+ SOC_DOUBLE_R("DAC1 Volume", AD183X_DAC_L1_VOL,
+ AD183X_DAC_R1_VOL, 0, 0x3FF, 0),
+ SOC_DOUBLE_R("DAC2 Volume", AD183X_DAC_L2_VOL,
+ AD183X_DAC_R2_VOL, 0, 0x3FF, 0),
+ SOC_DOUBLE_R("DAC3 Volume", AD183X_DAC_L3_VOL,
+ AD183X_DAC_R3_VOL, 0, 0x3FF, 0),
+
+ /* ADC switch control */
+ SOC_DOUBLE("ADC1 Switch", AD183X_ADC_CTRL2, AD183X_ADCL1_MUTE,
+ AD183X_ADCR1_MUTE, 1, 1),
+
+ /* DAC switch control */
+ SOC_DOUBLE("DAC1 Switch", AD183X_DAC_CTRL2, AD183X_DACL1_MUTE,
+ AD183X_DACR1_MUTE, 1, 1),
+ SOC_DOUBLE("DAC2 Switch", AD183X_DAC_CTRL2, AD183X_DACL2_MUTE,
+ AD183X_DACR2_MUTE, 1, 1),
+ SOC_DOUBLE("DAC3 Switch", AD183X_DAC_CTRL2, AD183X_DACL3_MUTE,
+ AD183X_DACR3_MUTE, 1, 1),
+
+ /* ADC high-pass filter */
+ SOC_SINGLE("ADC High Pass Filter Switch", AD183X_ADC_CTRL1,
+ AD183X_ADC_HIGHPASS_FILTER, 1, 0),
+
+ /* DAC de-emphasis */
+ SOC_ENUM("Playback Deemphasis", ad183x_deemp_enum),
+};
+
+static const struct snd_soc_dapm_widget ad1838a_ad1839a_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("DAC", "Playback", AD183X_DAC_CTRL1,
+ AD183X_DAC_POWERDOWN, 1),
+ SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_SUPPLY("ADC_PWR", AD183X_ADC_CTRL1,
+ AD183X_ADC_POWERDOWN, 1, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("DAC1OUT"),
+ SND_SOC_DAPM_OUTPUT("DAC2OUT"),
+ SND_SOC_DAPM_OUTPUT("DAC3OUT"),
+ SND_SOC_DAPM_INPUT("ADC1IN"),
+};
+
+static const struct snd_soc_dapm_route ad1838a_ad1839a_audio_paths[] = {
+ { "DAC", NULL, "ADC_PWR" },
+ { "ADC", NULL, "ADC_PWR" },
+ { "DAC1OUT", "DAC1 Switch", "DAC" },
+ { "DAC2OUT", "DAC2 Switch", "DAC" },
+ { "DAC3OUT", "DAC3 Switch", "DAC" },
+ { "ADC", "ADC1 Switch", "ADC1IN" },
+};
+
+static const struct ad183x_chl_ctrls ad1838a_ad1839a_chl_ctrls = {
+ .snd_ctrls = ad1838a_ad1839a_snd_controls,
+ .dapm_widgets = ad1838a_ad1839a_dapm_widgets,
+ .audio_paths = ad1838a_ad1839a_audio_paths,
+ .ctrl_num = ARRAY_SIZE(ad1838a_ad1839a_snd_controls),
+ .widget_num = ARRAY_SIZE(ad1838a_ad1839a_dapm_widgets),
+ .path_num = ARRAY_SIZE(ad1838a_ad1839a_audio_paths),
+ .play_max = 6,
+ .capt_max = 2,
+};
+
/*
* DAI ops entries
*/
@@ -208,24 +361,22 @@ static int ad183x_resume(struct snd_soc_codec *codec)
static int ad183x_probe(struct snd_soc_codec *codec)
{
struct ad183x_priv *ad183x = snd_soc_codec_get_drvdata(codec);
+ const struct ad183x_chl_ctrls *chl_ctrl;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret = 0;
+ int ret;
- codec->control_data = ad183x->control_data;
ret = snd_soc_codec_set_cache_io(codec, 4, 12, ad183x->control_type);
if (ret < 0) {
- dev_err(codec->dev, "failed to set cache I/O: %d\n",
- ret);
+ dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
return ret;
}
- snd_soc_add_controls(codec, ad183x_snd_controls,
- ARRAY_SIZE(ad183x_snd_controls));
- snd_soc_dapm_new_controls(dapm, ad183x_dapm_widgets,
- ARRAY_SIZE(ad183x_dapm_widgets));
- snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));
+ chl_ctrl = ad183x->chl_ctrl;
+ snd_soc_add_controls(codec, chl_ctrl->snd_ctrls, chl_ctrl->ctrl_num);
+ snd_soc_dapm_new_controls(dapm, chl_ctrl->dapm_widgets, chl_ctrl->widget_num);
+ snd_soc_dapm_add_routes(dapm, chl_ctrl->audio_paths, chl_ctrl->path_num);
- return ret;
+ return 0;
}
/* power down chip */
@@ -251,19 +402,37 @@ static int __devinit ad183x_spi_probe(struct spi_device *spi)
{
struct ad183x_priv *ad183x;
int ret;
+ const char *chip_name = spi->dev.platform_data;
+
+ if (!chip_name)
+ return -ENODEV;
ad183x = kzalloc(sizeof(struct ad183x_priv), GFP_KERNEL);
if (ad183x == NULL)
return -ENOMEM;
+ if (!strcmp(chip_name, "ad1835a") || !strcmp(chip_name, "ad1837a"))
+ ad183x->chl_ctrl = &ad1835a_ad1837a_chl_ctrls;
+ else if (!strcmp(chip_name, "ad1838a") || !strcmp(chip_name, "ad1839a"))
+ ad183x->chl_ctrl = &ad1838a_ad1839a_chl_ctrls;
+ else if (!strcmp(chip_name, "ad1836"))
+ ad183x->chl_ctrl = &ad1836_chl_ctrls;
+ else {
+ dev_err(&spi->dev, "unsupported chip type: %s\n", chip_name);
+ return -EINVAL;
+ }
+
+ ad183x_dai.playback.channels_max = ad183x->chl_ctrl->play_max;
+ ad183x_dai.capture.channels_max = ad183x->chl_ctrl->capt_max;
+
spi_set_drvdata(spi, ad183x);
- ad183x->control_data = spi;
ad183x->control_type = SND_SOC_SPI;
ret = snd_soc_register_codec(&spi->dev,
- &soc_codec_dev_ad183x, &ad183x_dai, 1);
+ &soc_codec_dev_ad183x, &ad183x_dai, 1);
if (ret < 0)
kfree(ad183x);
+
return ret;
}
diff --git a/sound/soc/codecs/ad183x.h b/sound/soc/codecs/ad183x.h
index b8f7289..7591dc1 100644
--- a/sound/soc/codecs/ad183x.h
+++ b/sound/soc/codecs/ad183x.h
@@ -1,5 +1,6 @@
/*
- * Audio Codec driver supporting AD1836
+ * Audio Codec driver supporting:
+ * AD1835A, AD1836, AD1837A, AD1838A, AD1839A
*
* Copyright 2009-2011 Analog Devices Inc.
*
@@ -24,6 +25,8 @@
#define AD183X_DACR2_MUTE 3
#define AD183X_DACL3_MUTE 4
#define AD183X_DACR3_MUTE 5
+#define AD183X_DACL4_MUTE 6
+#define AD183X_DACR4_MUTE 7
#define AD183X_DAC_L1_VOL 2
#define AD183X_DAC_R1_VOL 3
@@ -31,6 +34,8 @@
#define AD183X_DAC_R2_VOL 5
#define AD183X_DAC_L3_VOL 6
#define AD183X_DAC_R3_VOL 7
+#define AD183X_DAC_L4_VOL 8
+#define AD183X_DAC_R4_VOL 9
#define AD183X_ADC_CTRL1 12
#define AD183X_ADC_POWERDOWN 7
--
1.7.5.3
More information about the Alsa-devel
mailing list