aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2014-05-27 04:53:18 -0400
committerMark Brown <broonie@linaro.org>2014-05-27 15:54:50 -0400
commitdab464b60b2435a2aaae3630266db8ad130b7fad (patch)
tree11eafcd4aebe454f6d14821dab97efb2b26ee20a /sound
parent4101866c743a3695666e8562b5713b4d7f341cbf (diff)
ASoC: Add ADAU1361/ADAU1761 audio CODEC support
This patch adds support for the Analog Devices ADAU1361 and ADAU1761 CODECs. The device is a a low-power, 24-bit stereo audio CODEC with multiple analog input and outputs, one digital microphone input and an I2S interface. The device can be controlled either via I2C or SPI. The main difference between the two variants is that the ADAU1761 has a built-in SigmaDSP, while the ADAU1361 has not. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/Kconfig16
-rw-r--r--sound/soc/codecs/Makefile6
-rw-r--r--sound/soc/codecs/adau1761-i2c.c60
-rw-r--r--sound/soc/codecs/adau1761-spi.c77
-rw-r--r--sound/soc/codecs/adau1761.c803
-rw-r--r--sound/soc/codecs/adau1761.h23
6 files changed, 985 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 182a39751a91..4233ed118c48 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -23,6 +23,8 @@ config SND_SOC_ALL_CODECS
23 select SND_SOC_AD1980 if SND_SOC_AC97_BUS 23 select SND_SOC_AD1980 if SND_SOC_AC97_BUS
24 select SND_SOC_AD73311 24 select SND_SOC_AD73311
25 select SND_SOC_ADAU1373 if I2C 25 select SND_SOC_ADAU1373 if I2C
26 select SND_SOC_ADAU1761_I2C if I2C
27 select SND_SOC_ADAU1761_SPI if SPI
26 select SND_SOC_ADAV801 if SPI_MASTER 28 select SND_SOC_ADAV801 if SPI_MASTER
27 select SND_SOC_ADAV803 if I2C 29 select SND_SOC_ADAV803 if I2C
28 select SND_SOC_ADAU1977_SPI if SPI_MASTER 30 select SND_SOC_ADAU1977_SPI if SPI_MASTER
@@ -222,6 +224,20 @@ config SND_SOC_ADAU17X1
222 tristate 224 tristate
223 select SND_SOC_SIGMADSP 225 select SND_SOC_SIGMADSP
224 226
227config SND_SOC_ADAU1761
228 tristate
229 select SND_SOC_ADAU17X1
230
231config SND_SOC_ADAU1761_I2C
232 tristate
233 select SND_SOC_ADAU1761
234 select REGMAP_I2C
235
236config SND_SOC_ADAU1761_SPI
237 tristate
238 select SND_SOC_ADAU1761
239 select REGMAP_SPI
240
225config SND_SOC_ADAU1977 241config SND_SOC_ADAU1977
226 tristate 242 tristate
227 243
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index a8cba3086830..e96499ca76bd 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -10,6 +10,9 @@ snd-soc-ad73311-objs := ad73311.o
10snd-soc-adau1373-objs := adau1373.o 10snd-soc-adau1373-objs := adau1373.o
11snd-soc-adau1701-objs := adau1701.o 11snd-soc-adau1701-objs := adau1701.o
12snd-soc-adau17x1-objs := adau17x1.o 12snd-soc-adau17x1-objs := adau17x1.o
13snd-soc-adau1761-objs := adau1761.o
14snd-soc-adau1761-i2c-objs := adau1761-i2c.o
15snd-soc-adau1761-spi-objs := adau1761-spi.o
13snd-soc-adau1977-objs := adau1977.o 16snd-soc-adau1977-objs := adau1977.o
14snd-soc-adau1977-spi-objs := adau1977-spi.o 17snd-soc-adau1977-spi-objs := adau1977-spi.o
15snd-soc-adau1977-i2c-objs := adau1977-i2c.o 18snd-soc-adau1977-i2c-objs := adau1977-i2c.o
@@ -160,6 +163,9 @@ obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
160obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o 163obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o
161obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o 164obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o
162obj-$(CONFIG_SND_SOC_ADAU17X1) += snd-soc-adau17x1.o 165obj-$(CONFIG_SND_SOC_ADAU17X1) += snd-soc-adau17x1.o
166obj-$(CONFIG_SND_SOC_ADAU1761) += snd-soc-adau1761.o
167obj-$(CONFIG_SND_SOC_ADAU1761_I2C) += snd-soc-adau1761-i2c.o
168obj-$(CONFIG_SND_SOC_ADAU1761_SPI) += snd-soc-adau1761-spi.o
163obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o 169obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o
164obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o 170obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o
165obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o 171obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o
diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c
new file mode 100644
index 000000000000..862796dec693
--- /dev/null
+++ b/sound/soc/codecs/adau1761-i2c.c
@@ -0,0 +1,60 @@
1/*
2 * Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec
3 *
4 * Copyright 2014 Analog Devices Inc.
5 * Author: Lars-Peter Clausen <lars@metafoo.de>
6 *
7 * Licensed under the GPL-2.
8 */
9
10#include <linux/i2c.h>
11#include <linux/mod_devicetable.h>
12#include <linux/module.h>
13#include <linux/regmap.h>
14#include <sound/soc.h>
15
16#include "adau1761.h"
17
18static int adau1761_i2c_probe(struct i2c_client *client,
19 const struct i2c_device_id *id)
20{
21 struct regmap_config config;
22
23 config = adau1761_regmap_config;
24 config.val_bits = 8;
25 config.reg_bits = 16;
26
27 return adau1761_probe(&client->dev,
28 devm_regmap_init_i2c(client, &config),
29 id->driver_data, NULL);
30}
31
32static int adau1761_i2c_remove(struct i2c_client *client)
33{
34 snd_soc_unregister_codec(&client->dev);
35 return 0;
36}
37
38static const struct i2c_device_id adau1761_i2c_ids[] = {
39 { "adau1361", ADAU1361 },
40 { "adau1461", ADAU1761 },
41 { "adau1761", ADAU1761 },
42 { "adau1961", ADAU1361 },
43 { }
44};
45MODULE_DEVICE_TABLE(i2c, adau1761_i2c_ids);
46
47static struct i2c_driver adau1761_i2c_driver = {
48 .driver = {
49 .name = "adau1761",
50 .owner = THIS_MODULE,
51 },
52 .probe = adau1761_i2c_probe,
53 .remove = adau1761_i2c_remove,
54 .id_table = adau1761_i2c_ids,
55};
56module_i2c_driver(adau1761_i2c_driver);
57
58MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC I2C driver");
59MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
60MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1761-spi.c b/sound/soc/codecs/adau1761-spi.c
new file mode 100644
index 000000000000..cce2f11f1ffb
--- /dev/null
+++ b/sound/soc/codecs/adau1761-spi.c
@@ -0,0 +1,77 @@
1/*
2 * Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec
3 *
4 * Copyright 2014 Analog Devices Inc.
5 * Author: Lars-Peter Clausen <lars@metafoo.de>
6 *
7 * Licensed under the GPL-2.
8 */
9
10#include <linux/mod_devicetable.h>
11#include <linux/module.h>
12#include <linux/regmap.h>
13#include <linux/spi/spi.h>
14#include <sound/soc.h>
15
16#include "adau1761.h"
17
18static void adau1761_spi_switch_mode(struct device *dev)
19{
20 struct spi_device *spi = to_spi_device(dev);
21
22 /*
23 * To get the device into SPI mode CLATCH has to be pulled low three
24 * times. Do this by issuing three dummy reads.
25 */
26 spi_w8r8(spi, 0x00);
27 spi_w8r8(spi, 0x00);
28 spi_w8r8(spi, 0x00);
29}
30
31static int adau1761_spi_probe(struct spi_device *spi)
32{
33 const struct spi_device_id *id = spi_get_device_id(spi);
34 struct regmap_config config;
35
36 if (!id)
37 return -EINVAL;
38
39 config = adau1761_regmap_config;
40 config.val_bits = 8;
41 config.reg_bits = 24;
42 config.read_flag_mask = 0x1;
43
44 return adau1761_probe(&spi->dev,
45 devm_regmap_init_spi(spi, &config),
46 id->driver_data, adau1761_spi_switch_mode);
47}
48
49static int adau1761_spi_remove(struct spi_device *spi)
50{
51 snd_soc_unregister_codec(&spi->dev);
52 return 0;
53}
54
55static const struct spi_device_id adau1761_spi_id[] = {
56 { "adau1361", ADAU1361 },
57 { "adau1461", ADAU1761 },
58 { "adau1761", ADAU1761 },
59 { "adau1961", ADAU1361 },
60 { }
61};
62MODULE_DEVICE_TABLE(spi, adau1761_spi_id);
63
64static struct spi_driver adau1761_spi_driver = {
65 .driver = {
66 .name = "adau1761",
67 .owner = THIS_MODULE,
68 },
69 .probe = adau1761_spi_probe,
70 .remove = adau1761_spi_remove,
71 .id_table = adau1761_spi_id,
72};
73module_spi_driver(adau1761_spi_driver);
74
75MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC SPI driver");
76MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
77MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c
new file mode 100644
index 000000000000..848cab839553
--- /dev/null
+++ b/sound/soc/codecs/adau1761.c
@@ -0,0 +1,803 @@
1/*
2 * Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec
3 *
4 * Copyright 2011-2013 Analog Devices Inc.
5 * Author: Lars-Peter Clausen <lars@metafoo.de>
6 *
7 * Licensed under the GPL-2 or later.
8 */
9
10#include <linux/module.h>
11#include <linux/init.h>
12#include <linux/i2c.h>
13#include <linux/spi/spi.h>
14#include <linux/slab.h>
15#include <sound/core.h>
16#include <sound/pcm.h>
17#include <sound/pcm_params.h>
18#include <sound/soc.h>
19#include <sound/tlv.h>
20#include <linux/platform_data/adau17x1.h>
21
22#include "adau17x1.h"
23#include "adau1761.h"
24
25#define ADAU1761_DIGMIC_JACKDETECT 0x4008
26#define ADAU1761_REC_MIXER_LEFT0 0x400a
27#define ADAU1761_REC_MIXER_LEFT1 0x400b
28#define ADAU1761_REC_MIXER_RIGHT0 0x400c
29#define ADAU1761_REC_MIXER_RIGHT1 0x400d
30#define ADAU1761_LEFT_DIFF_INPUT_VOL 0x400e
31#define ADAU1761_RIGHT_DIFF_INPUT_VOL 0x400f
32#define ADAU1761_PLAY_LR_MIXER_LEFT 0x4020
33#define ADAU1761_PLAY_MIXER_LEFT0 0x401c
34#define ADAU1761_PLAY_MIXER_LEFT1 0x401d
35#define ADAU1761_PLAY_MIXER_RIGHT0 0x401e
36#define ADAU1761_PLAY_MIXER_RIGHT1 0x401f
37#define ADAU1761_PLAY_LR_MIXER_RIGHT 0x4021
38#define ADAU1761_PLAY_MIXER_MONO 0x4022
39#define ADAU1761_PLAY_HP_LEFT_VOL 0x4023
40#define ADAU1761_PLAY_HP_RIGHT_VOL 0x4024
41#define ADAU1761_PLAY_LINE_LEFT_VOL 0x4025
42#define ADAU1761_PLAY_LINE_RIGHT_VOL 0x4026
43#define ADAU1761_PLAY_MONO_OUTPUT_VOL 0x4027
44#define ADAU1761_POP_CLICK_SUPPRESS 0x4028
45#define ADAU1761_JACK_DETECT_PIN 0x4031
46#define ADAU1761_DEJITTER 0x4036
47#define ADAU1761_CLK_ENABLE0 0x40f9
48#define ADAU1761_CLK_ENABLE1 0x40fa
49
50#define ADAU1761_DIGMIC_JACKDETECT_ACTIVE_LOW BIT(0)
51#define ADAU1761_DIGMIC_JACKDETECT_DIGMIC BIT(5)
52
53#define ADAU1761_DIFF_INPUT_VOL_LDEN BIT(0)
54
55#define ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP BIT(0)
56#define ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE BIT(1)
57
58#define ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP BIT(0)
59
60#define ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP BIT(0)
61
62#define ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP BIT(0)
63
64
65#define ADAU1761_FIRMWARE "adau1761.bin"
66
67static const struct reg_default adau1761_reg_defaults[] = {
68 { ADAU1761_DEJITTER, 0x03 },
69 { ADAU1761_DIGMIC_JACKDETECT, 0x00 },
70 { ADAU1761_REC_MIXER_LEFT0, 0x00 },
71 { ADAU1761_REC_MIXER_LEFT1, 0x00 },
72 { ADAU1761_REC_MIXER_RIGHT0, 0x00 },
73 { ADAU1761_REC_MIXER_RIGHT1, 0x00 },
74 { ADAU1761_LEFT_DIFF_INPUT_VOL, 0x00 },
75 { ADAU1761_RIGHT_DIFF_INPUT_VOL, 0x00 },
76 { ADAU1761_PLAY_LR_MIXER_LEFT, 0x00 },
77 { ADAU1761_PLAY_MIXER_LEFT0, 0x00 },
78 { ADAU1761_PLAY_MIXER_LEFT1, 0x00 },
79 { ADAU1761_PLAY_MIXER_RIGHT0, 0x00 },
80 { ADAU1761_PLAY_MIXER_RIGHT1, 0x00 },
81 { ADAU1761_PLAY_LR_MIXER_RIGHT, 0x00 },
82 { ADAU1761_PLAY_MIXER_MONO, 0x00 },
83 { ADAU1761_PLAY_HP_LEFT_VOL, 0x00 },
84 { ADAU1761_PLAY_HP_RIGHT_VOL, 0x00 },
85 { ADAU1761_PLAY_LINE_LEFT_VOL, 0x00 },
86 { ADAU1761_PLAY_LINE_RIGHT_VOL, 0x00 },
87 { ADAU1761_PLAY_MONO_OUTPUT_VOL, 0x00 },
88 { ADAU1761_POP_CLICK_SUPPRESS, 0x00 },
89 { ADAU1761_JACK_DETECT_PIN, 0x00 },
90 { ADAU1761_CLK_ENABLE0, 0x00 },
91 { ADAU1761_CLK_ENABLE1, 0x00 },
92 { ADAU17X1_CLOCK_CONTROL, 0x00 },
93 { ADAU17X1_PLL_CONTROL, 0x00 },
94 { ADAU17X1_REC_POWER_MGMT, 0x00 },
95 { ADAU17X1_MICBIAS, 0x00 },
96 { ADAU17X1_SERIAL_PORT0, 0x00 },
97 { ADAU17X1_SERIAL_PORT1, 0x00 },
98 { ADAU17X1_CONVERTER0, 0x00 },
99 { ADAU17X1_CONVERTER1, 0x00 },
100 { ADAU17X1_LEFT_INPUT_DIGITAL_VOL, 0x00 },
101 { ADAU17X1_RIGHT_INPUT_DIGITAL_VOL, 0x00 },
102 { ADAU17X1_ADC_CONTROL, 0x00 },
103 { ADAU17X1_PLAY_POWER_MGMT, 0x00 },
104 { ADAU17X1_DAC_CONTROL0, 0x00 },
105 { ADAU17X1_DAC_CONTROL1, 0x00 },
106 { ADAU17X1_DAC_CONTROL2, 0x00 },
107 { ADAU17X1_SERIAL_PORT_PAD, 0xaa },
108 { ADAU17X1_CONTROL_PORT_PAD0, 0xaa },
109 { ADAU17X1_CONTROL_PORT_PAD1, 0x00 },
110 { ADAU17X1_DSP_SAMPLING_RATE, 0x01 },
111 { ADAU17X1_SERIAL_INPUT_ROUTE, 0x00 },
112 { ADAU17X1_SERIAL_OUTPUT_ROUTE, 0x00 },
113 { ADAU17X1_DSP_ENABLE, 0x00 },
114 { ADAU17X1_DSP_RUN, 0x00 },
115 { ADAU17X1_SERIAL_SAMPLING_RATE, 0x00 },
116};
117
118static const DECLARE_TLV_DB_SCALE(adau1761_sing_in_tlv, -1500, 300, 1);
119static const DECLARE_TLV_DB_SCALE(adau1761_diff_in_tlv, -1200, 75, 0);
120static const DECLARE_TLV_DB_SCALE(adau1761_out_tlv, -5700, 100, 0);
121static const DECLARE_TLV_DB_SCALE(adau1761_sidetone_tlv, -1800, 300, 1);
122static const DECLARE_TLV_DB_SCALE(adau1761_boost_tlv, -600, 600, 1);
123static const DECLARE_TLV_DB_SCALE(adau1761_pga_boost_tlv, -2000, 2000, 1);
124
125static const unsigned int adau1761_bias_select_values[] = {
126 0, 2, 3,
127};
128
129static const char * const adau1761_bias_select_text[] = {
130 "Normal operation", "Enhanced performance", "Power saving",
131};
132
133static const char * const adau1761_bias_select_extreme_text[] = {
134 "Normal operation", "Extreme power saving", "Enhanced performance",
135 "Power saving",
136};
137
138static SOC_ENUM_SINGLE_DECL(adau1761_adc_bias_enum,
139 ADAU17X1_REC_POWER_MGMT, 3, adau1761_bias_select_extreme_text);
140static SOC_ENUM_SINGLE_DECL(adau1761_hp_bias_enum,
141 ADAU17X1_PLAY_POWER_MGMT, 6, adau1761_bias_select_extreme_text);
142static SOC_ENUM_SINGLE_DECL(adau1761_dac_bias_enum,
143 ADAU17X1_PLAY_POWER_MGMT, 4, adau1761_bias_select_extreme_text);
144static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_playback_bias_enum,
145 ADAU17X1_PLAY_POWER_MGMT, 2, 0x3, adau1761_bias_select_text,
146 adau1761_bias_select_values);
147static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_capture_bias_enum,
148 ADAU17X1_REC_POWER_MGMT, 1, 0x3, adau1761_bias_select_text,
149 adau1761_bias_select_values);
150
151static const struct snd_kcontrol_new adau1761_jack_detect_controls[] = {
152 SOC_SINGLE("Speaker Auto-mute Switch", ADAU1761_DIGMIC_JACKDETECT,
153 4, 1, 0),
154};
155
156static const struct snd_kcontrol_new adau1761_differential_mode_controls[] = {
157 SOC_DOUBLE_R_TLV("Capture Volume", ADAU1761_LEFT_DIFF_INPUT_VOL,
158 ADAU1761_RIGHT_DIFF_INPUT_VOL, 2, 0x3f, 0,
159 adau1761_diff_in_tlv),
160 SOC_DOUBLE_R("Capture Switch", ADAU1761_LEFT_DIFF_INPUT_VOL,
161 ADAU1761_RIGHT_DIFF_INPUT_VOL, 1, 1, 0),
162
163 SOC_DOUBLE_R_TLV("PGA Boost Capture Volume", ADAU1761_REC_MIXER_LEFT1,
164 ADAU1761_REC_MIXER_RIGHT1, 3, 2, 0, adau1761_pga_boost_tlv),
165};
166
167static const struct snd_kcontrol_new adau1761_single_mode_controls[] = {
168 SOC_SINGLE_TLV("Input 1 Capture Volume", ADAU1761_REC_MIXER_LEFT0,
169 4, 7, 0, adau1761_sing_in_tlv),
170 SOC_SINGLE_TLV("Input 2 Capture Volume", ADAU1761_REC_MIXER_LEFT0,
171 1, 7, 0, adau1761_sing_in_tlv),
172 SOC_SINGLE_TLV("Input 3 Capture Volume", ADAU1761_REC_MIXER_RIGHT0,
173 4, 7, 0, adau1761_sing_in_tlv),
174 SOC_SINGLE_TLV("Input 4 Capture Volume", ADAU1761_REC_MIXER_RIGHT0,
175 1, 7, 0, adau1761_sing_in_tlv),
176};
177
178static const struct snd_kcontrol_new adau1761_controls[] = {
179 SOC_DOUBLE_R_TLV("Aux Capture Volume", ADAU1761_REC_MIXER_LEFT1,
180 ADAU1761_REC_MIXER_RIGHT1, 0, 7, 0, adau1761_sing_in_tlv),
181
182 SOC_DOUBLE_R_TLV("Headphone Playback Volume", ADAU1761_PLAY_HP_LEFT_VOL,
183 ADAU1761_PLAY_HP_RIGHT_VOL, 2, 0x3f, 0, adau1761_out_tlv),
184 SOC_DOUBLE_R("Headphone Playback Switch", ADAU1761_PLAY_HP_LEFT_VOL,
185 ADAU1761_PLAY_HP_RIGHT_VOL, 1, 1, 0),
186 SOC_DOUBLE_R_TLV("Lineout Playback Volume", ADAU1761_PLAY_LINE_LEFT_VOL,
187 ADAU1761_PLAY_LINE_RIGHT_VOL, 2, 0x3f, 0, adau1761_out_tlv),
188 SOC_DOUBLE_R("Lineout Playback Switch", ADAU1761_PLAY_LINE_LEFT_VOL,
189 ADAU1761_PLAY_LINE_RIGHT_VOL, 1, 1, 0),
190
191 SOC_ENUM("ADC Bias", adau1761_adc_bias_enum),
192 SOC_ENUM("DAC Bias", adau1761_dac_bias_enum),
193 SOC_ENUM("Capture Bias", adau1761_capture_bias_enum),
194 SOC_ENUM("Playback Bias", adau1761_playback_bias_enum),
195 SOC_ENUM("Headphone Bias", adau1761_hp_bias_enum),
196};
197
198static const struct snd_kcontrol_new adau1761_mono_controls[] = {
199 SOC_SINGLE_TLV("Mono Playback Volume", ADAU1761_PLAY_MONO_OUTPUT_VOL,
200 2, 0x3f, 0, adau1761_out_tlv),
201 SOC_SINGLE("Mono Playback Switch", ADAU1761_PLAY_MONO_OUTPUT_VOL,
202 1, 1, 0),
203};
204
205static const struct snd_kcontrol_new adau1761_left_mixer_controls[] = {
206 SOC_DAPM_SINGLE_AUTODISABLE("Left DAC Switch",
207 ADAU1761_PLAY_MIXER_LEFT0, 5, 1, 0),
208 SOC_DAPM_SINGLE_AUTODISABLE("Right DAC Switch",
209 ADAU1761_PLAY_MIXER_LEFT0, 6, 1, 0),
210 SOC_DAPM_SINGLE_TLV("Aux Bypass Volume",
211 ADAU1761_PLAY_MIXER_LEFT0, 1, 8, 0, adau1761_sidetone_tlv),
212 SOC_DAPM_SINGLE_TLV("Right Bypass Volume",
213 ADAU1761_PLAY_MIXER_LEFT1, 4, 8, 0, adau1761_sidetone_tlv),
214 SOC_DAPM_SINGLE_TLV("Left Bypass Volume",
215 ADAU1761_PLAY_MIXER_LEFT1, 0, 8, 0, adau1761_sidetone_tlv),
216};
217
218static const struct snd_kcontrol_new adau1761_right_mixer_controls[] = {
219 SOC_DAPM_SINGLE_AUTODISABLE("Left DAC Switch",
220 ADAU1761_PLAY_MIXER_RIGHT0, 5, 1, 0),
221 SOC_DAPM_SINGLE_AUTODISABLE("Right DAC Switch",
222 ADAU1761_PLAY_MIXER_RIGHT0, 6, 1, 0),
223 SOC_DAPM_SINGLE_TLV("Aux Bypass Volume",
224 ADAU1761_PLAY_MIXER_RIGHT0, 1, 8, 0, adau1761_sidetone_tlv),
225 SOC_DAPM_SINGLE_TLV("Right Bypass Volume",
226 ADAU1761_PLAY_MIXER_RIGHT1, 4, 8, 0, adau1761_sidetone_tlv),
227 SOC_DAPM_SINGLE_TLV("Left Bypass Volume",
228 ADAU1761_PLAY_MIXER_RIGHT1, 0, 8, 0, adau1761_sidetone_tlv),
229};
230
231static const struct snd_kcontrol_new adau1761_left_lr_mixer_controls[] = {
232 SOC_DAPM_SINGLE_TLV("Left Volume",
233 ADAU1761_PLAY_LR_MIXER_LEFT, 1, 2, 0, adau1761_boost_tlv),
234 SOC_DAPM_SINGLE_TLV("Right Volume",
235 ADAU1761_PLAY_LR_MIXER_LEFT, 3, 2, 0, adau1761_boost_tlv),
236};
237
238static const struct snd_kcontrol_new adau1761_right_lr_mixer_controls[] = {
239 SOC_DAPM_SINGLE_TLV("Left Volume",
240 ADAU1761_PLAY_LR_MIXER_RIGHT, 1, 2, 0, adau1761_boost_tlv),
241 SOC_DAPM_SINGLE_TLV("Right Volume",
242 ADAU1761_PLAY_LR_MIXER_RIGHT, 3, 2, 0, adau1761_boost_tlv),
243};
244
245static const char * const adau1761_input_mux_text[] = {
246 "ADC", "DMIC",
247};
248
249static SOC_ENUM_SINGLE_DECL(adau1761_input_mux_enum,
250 ADAU17X1_ADC_CONTROL, 2, adau1761_input_mux_text);
251
252static const struct snd_kcontrol_new adau1761_input_mux_control =
253 SOC_DAPM_ENUM("Input Select", adau1761_input_mux_enum);
254
255static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w,
256 struct snd_kcontrol *kcontrol, int event)
257{
258 struct adau *adau = snd_soc_codec_get_drvdata(w->codec);
259
260 /* After any power changes have been made the dejitter circuit
261 * has to be reinitialized. */
262 regmap_write(adau->regmap, ADAU1761_DEJITTER, 0);
263 if (!adau->master)
264 regmap_write(adau->regmap, ADAU1761_DEJITTER, 3);
265
266 return 0;
267}
268
269static const struct snd_soc_dapm_widget adau1x61_dapm_widgets[] = {
270 SND_SOC_DAPM_MIXER("Left Input Mixer", ADAU1761_REC_MIXER_LEFT0, 0, 0,
271 NULL, 0),
272 SND_SOC_DAPM_MIXER("Right Input Mixer", ADAU1761_REC_MIXER_RIGHT0, 0, 0,
273 NULL, 0),
274
275 SOC_MIXER_ARRAY("Left Playback Mixer", ADAU1761_PLAY_MIXER_LEFT0,
276 0, 0, adau1761_left_mixer_controls),
277 SOC_MIXER_ARRAY("Right Playback Mixer", ADAU1761_PLAY_MIXER_RIGHT0,
278 0, 0, adau1761_right_mixer_controls),
279 SOC_MIXER_ARRAY("Left LR Playback Mixer", ADAU1761_PLAY_LR_MIXER_LEFT,
280 0, 0, adau1761_left_lr_mixer_controls),
281 SOC_MIXER_ARRAY("Right LR Playback Mixer", ADAU1761_PLAY_LR_MIXER_RIGHT,
282 0, 0, adau1761_right_lr_mixer_controls),
283
284 SND_SOC_DAPM_SUPPLY("Headphone", ADAU1761_PLAY_HP_LEFT_VOL,
285 0, 0, NULL, 0),
286
287 SND_SOC_DAPM_SUPPLY_S("SYSCLK", 2, SND_SOC_NOPM, 0, 0, NULL, 0),
288
289 SND_SOC_DAPM_POST("Dejitter fixup", adau1761_dejitter_fixup),
290
291 SND_SOC_DAPM_INPUT("LAUX"),
292 SND_SOC_DAPM_INPUT("RAUX"),
293 SND_SOC_DAPM_INPUT("LINP"),
294 SND_SOC_DAPM_INPUT("LINN"),
295 SND_SOC_DAPM_INPUT("RINP"),
296 SND_SOC_DAPM_INPUT("RINN"),
297
298 SND_SOC_DAPM_OUTPUT("LOUT"),
299 SND_SOC_DAPM_OUTPUT("ROUT"),
300 SND_SOC_DAPM_OUTPUT("LHP"),
301 SND_SOC_DAPM_OUTPUT("RHP"),
302};
303
304static const struct snd_soc_dapm_widget adau1761_mono_dapm_widgets[] = {
305 SND_SOC_DAPM_MIXER("Mono Playback Mixer", ADAU1761_PLAY_MIXER_MONO,
306 0, 0, NULL, 0),
307
308 SND_SOC_DAPM_OUTPUT("MONOOUT"),
309};
310
311static const struct snd_soc_dapm_widget adau1761_capless_dapm_widgets[] = {
312 SND_SOC_DAPM_SUPPLY_S("Headphone VGND", 1, ADAU1761_PLAY_MIXER_MONO,
313 0, 0, NULL, 0),
314};
315
316static const struct snd_soc_dapm_route adau1x61_dapm_routes[] = {
317 { "Left Input Mixer", NULL, "LINP" },
318 { "Left Input Mixer", NULL, "LINN" },
319 { "Left Input Mixer", NULL, "LAUX" },
320
321 { "Right Input Mixer", NULL, "RINP" },
322 { "Right Input Mixer", NULL, "RINN" },
323 { "Right Input Mixer", NULL, "RAUX" },
324
325 { "Left Playback Mixer", NULL, "Left Playback Enable"},
326 { "Right Playback Mixer", NULL, "Right Playback Enable"},
327 { "Left LR Playback Mixer", NULL, "Left Playback Enable"},
328 { "Right LR Playback Mixer", NULL, "Right Playback Enable"},
329
330 { "Left Playback Mixer", "Left DAC Switch", "Left DAC" },
331 { "Left Playback Mixer", "Right DAC Switch", "Right DAC" },
332
333 { "Right Playback Mixer", "Left DAC Switch", "Left DAC" },
334 { "Right Playback Mixer", "Right DAC Switch", "Right DAC" },
335
336 { "Left LR Playback Mixer", "Left Volume", "Left Playback Mixer" },
337 { "Left LR Playback Mixer", "Right Volume", "Right Playback Mixer" },
338
339 { "Right LR Playback Mixer", "Left Volume", "Left Playback Mixer" },
340 { "Right LR Playback Mixer", "Right Volume", "Right Playback Mixer" },
341
342 { "LHP", NULL, "Left Playback Mixer" },
343 { "RHP", NULL, "Right Playback Mixer" },
344
345 { "LHP", NULL, "Headphone" },
346 { "RHP", NULL, "Headphone" },
347
348 { "LOUT", NULL, "Left LR Playback Mixer" },
349 { "ROUT", NULL, "Right LR Playback Mixer" },
350
351 { "Left Playback Mixer", "Aux Bypass Volume", "LAUX" },
352 { "Left Playback Mixer", "Left Bypass Volume", "Left Input Mixer" },
353 { "Left Playback Mixer", "Right Bypass Volume", "Right Input Mixer" },
354 { "Right Playback Mixer", "Aux Bypass Volume", "RAUX" },
355 { "Right Playback Mixer", "Left Bypass Volume", "Left Input Mixer" },
356 { "Right Playback Mixer", "Right Bypass Volume", "Right Input Mixer" },
357};
358
359static const struct snd_soc_dapm_route adau1761_mono_dapm_routes[] = {
360 { "Mono Playback Mixer", NULL, "Left Playback Mixer" },
361 { "Mono Playback Mixer", NULL, "Right Playback Mixer" },
362
363 { "MONOOUT", NULL, "Mono Playback Mixer" },
364};
365
366static const struct snd_soc_dapm_route adau1761_capless_dapm_routes[] = {
367 { "Headphone", NULL, "Headphone VGND" },
368};
369
370static const struct snd_soc_dapm_widget adau1761_dmic_widgets[] = {
371 SND_SOC_DAPM_MUX("Left Decimator Mux", SND_SOC_NOPM, 0, 0,
372 &adau1761_input_mux_control),
373 SND_SOC_DAPM_MUX("Right Decimator Mux", SND_SOC_NOPM, 0, 0,
374 &adau1761_input_mux_control),
375
376 SND_SOC_DAPM_INPUT("DMIC"),
377};
378
379static const struct snd_soc_dapm_route adau1761_dmic_routes[] = {
380 { "Left Decimator Mux", "ADC", "Left Input Mixer" },
381 { "Left Decimator Mux", "DMIC", "DMIC" },
382 { "Right Decimator Mux", "ADC", "Right Input Mixer" },
383 { "Right Decimator Mux", "DMIC", "DMIC" },
384
385 { "Left Decimator", NULL, "Left Decimator Mux" },
386 { "Right Decimator", NULL, "Right Decimator Mux" },
387};
388
389static const struct snd_soc_dapm_route adau1761_no_dmic_routes[] = {
390 { "Left Decimator", NULL, "Left Input Mixer" },
391 { "Right Decimator", NULL, "Right Input Mixer" },
392};
393
394static const struct snd_soc_dapm_widget adau1761_dapm_widgets[] = {
395 SND_SOC_DAPM_SUPPLY("Serial Port Clock", ADAU1761_CLK_ENABLE0,
396 0, 0, NULL, 0),
397 SND_SOC_DAPM_SUPPLY("Serial Input Routing Clock", ADAU1761_CLK_ENABLE0,
398 1, 0, NULL, 0),
399 SND_SOC_DAPM_SUPPLY("Serial Output Routing Clock", ADAU1761_CLK_ENABLE0,
400 3, 0, NULL, 0),
401
402 SND_SOC_DAPM_SUPPLY("Decimator Resync Clock", ADAU1761_CLK_ENABLE0,
403 4, 0, NULL, 0),
404 SND_SOC_DAPM_SUPPLY("Interpolator Resync Clock", ADAU1761_CLK_ENABLE0,
405 2, 0, NULL, 0),
406
407 SND_SOC_DAPM_SUPPLY("Slew Clock", ADAU1761_CLK_ENABLE0, 6, 0, NULL, 0),
408
409 SND_SOC_DAPM_SUPPLY_S("Digital Clock 0", 1, ADAU1761_CLK_ENABLE1,
410 0, 0, NULL, 0),
411 SND_SOC_DAPM_SUPPLY_S("Digital Clock 1", 1, ADAU1761_CLK_ENABLE1,
412 1, 0, NULL, 0),
413};
414
415static const struct snd_soc_dapm_route adau1761_dapm_routes[] = {
416 { "Left Decimator", NULL, "Digital Clock 0", },
417 { "Right Decimator", NULL, "Digital Clock 0", },
418 { "Left DAC", NULL, "Digital Clock 0", },
419 { "Right DAC", NULL, "Digital Clock 0", },
420
421 { "AIFCLK", NULL, "Digital Clock 1" },
422
423 { "Playback", NULL, "Serial Port Clock" },
424 { "Capture", NULL, "Serial Port Clock" },
425 { "Playback", NULL, "Serial Input Routing Clock" },
426 { "Capture", NULL, "Serial Output Routing Clock" },
427
428 { "Left Decimator", NULL, "Decimator Resync Clock" },
429 { "Right Decimator", NULL, "Decimator Resync Clock" },
430 { "Left DAC", NULL, "Interpolator Resync Clock" },
431 { "Right DAC", NULL, "Interpolator Resync Clock" },
432
433 { "DSP", NULL, "Digital Clock 0" },
434
435 { "Slew Clock", NULL, "Digital Clock 0" },
436 { "Right Playback Mixer", NULL, "Slew Clock" },
437 { "Left Playback Mixer", NULL, "Slew Clock" },
438
439 { "Digital Clock 0", NULL, "SYSCLK" },
440 { "Digital Clock 1", NULL, "SYSCLK" },
441};
442
443static int adau1761_set_bias_level(struct snd_soc_codec *codec,
444 enum snd_soc_bias_level level)
445{
446 struct adau *adau = snd_soc_codec_get_drvdata(codec);
447
448 switch (level) {
449 case SND_SOC_BIAS_ON:
450 break;
451 case SND_SOC_BIAS_PREPARE:
452 break;
453 case SND_SOC_BIAS_STANDBY:
454 regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
455 ADAU17X1_CLOCK_CONTROL_SYSCLK_EN,
456 ADAU17X1_CLOCK_CONTROL_SYSCLK_EN);
457 break;
458 case SND_SOC_BIAS_OFF:
459 regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
460 ADAU17X1_CLOCK_CONTROL_SYSCLK_EN, 0);
461 break;
462
463 }
464 codec->dapm.bias_level = level;
465 return 0;
466}
467
468static enum adau1761_output_mode adau1761_get_lineout_mode(
469 struct snd_soc_codec *codec)
470{
471 struct adau1761_platform_data *pdata = codec->dev->platform_data;
472
473 if (pdata)
474 return pdata->lineout_mode;
475
476 return ADAU1761_OUTPUT_MODE_LINE;
477}
478
479static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
480{
481 struct adau1761_platform_data *pdata = codec->dev->platform_data;
482 struct adau *adau = snd_soc_codec_get_drvdata(codec);
483 enum adau1761_digmic_jackdet_pin_mode mode;
484 unsigned int val = 0;
485 int ret;
486
487 if (pdata)
488 mode = pdata->digmic_jackdetect_pin_mode;
489 else
490 mode = ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE;
491
492 switch (mode) {
493 case ADAU1761_DIGMIC_JACKDET_PIN_MODE_JACKDETECT:
494 switch (pdata->jackdetect_debounce_time) {
495 case ADAU1761_JACKDETECT_DEBOUNCE_5MS:
496 case ADAU1761_JACKDETECT_DEBOUNCE_10MS:
497 case ADAU1761_JACKDETECT_DEBOUNCE_20MS:
498 case ADAU1761_JACKDETECT_DEBOUNCE_40MS:
499 val |= pdata->jackdetect_debounce_time << 6;
500 break;
501 default:
502 return -EINVAL;
503 }
504 if (pdata->jackdetect_active_low)
505 val |= ADAU1761_DIGMIC_JACKDETECT_ACTIVE_LOW;
506
507 ret = snd_soc_add_codec_controls(codec,
508 adau1761_jack_detect_controls,
509 ARRAY_SIZE(adau1761_jack_detect_controls));
510 if (ret)
511 return ret;
512 case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: /* fallthrough */
513 ret = snd_soc_dapm_add_routes(&codec->dapm,
514 adau1761_no_dmic_routes,
515 ARRAY_SIZE(adau1761_no_dmic_routes));
516 if (ret)
517 return ret;
518 break;
519 case ADAU1761_DIGMIC_JACKDET_PIN_MODE_DIGMIC:
520 ret = snd_soc_dapm_new_controls(&codec->dapm,
521 adau1761_dmic_widgets,
522 ARRAY_SIZE(adau1761_dmic_widgets));
523 if (ret)
524 return ret;
525
526 ret = snd_soc_dapm_add_routes(&codec->dapm,
527 adau1761_dmic_routes,
528 ARRAY_SIZE(adau1761_dmic_routes));
529 if (ret)
530 return ret;
531
532 val |= ADAU1761_DIGMIC_JACKDETECT_DIGMIC;
533 break;
534 default:
535 return -EINVAL;
536 }
537
538 regmap_write(adau->regmap, ADAU1761_DIGMIC_JACKDETECT, val);
539
540 return 0;
541}
542
543static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec)
544{
545 struct adau *adau = snd_soc_codec_get_drvdata(codec);
546 struct adau1761_platform_data *pdata = codec->dev->platform_data;
547 enum adau1761_output_mode mode;
548 int ret;
549
550 if (pdata)
551 mode = pdata->headphone_mode;
552 else
553 mode = ADAU1761_OUTPUT_MODE_HEADPHONE;
554
555 switch (mode) {
556 case ADAU1761_OUTPUT_MODE_LINE:
557 break;
558 case ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS:
559 regmap_update_bits(adau->regmap, ADAU1761_PLAY_MONO_OUTPUT_VOL,
560 ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP |
561 ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE,
562 ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP |
563 ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE);
564 /* fallthrough */
565 case ADAU1761_OUTPUT_MODE_HEADPHONE:
566 regmap_update_bits(adau->regmap, ADAU1761_PLAY_HP_RIGHT_VOL,
567 ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP,
568 ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP);
569 break;
570 default:
571 return -EINVAL;
572 }
573
574 if (mode == ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS) {
575 ret = snd_soc_dapm_new_controls(&codec->dapm,
576 adau1761_capless_dapm_widgets,
577 ARRAY_SIZE(adau1761_capless_dapm_widgets));
578 if (ret)
579 return ret;
580 ret = snd_soc_dapm_add_routes(&codec->dapm,
581 adau1761_capless_dapm_routes,
582 ARRAY_SIZE(adau1761_capless_dapm_routes));
583 } else {
584 ret = snd_soc_add_codec_controls(codec, adau1761_mono_controls,
585 ARRAY_SIZE(adau1761_mono_controls));
586 if (ret)
587 return ret;
588 ret = snd_soc_dapm_new_controls(&codec->dapm,
589 adau1761_mono_dapm_widgets,
590 ARRAY_SIZE(adau1761_mono_dapm_widgets));
591 if (ret)
592 return ret;
593 ret = snd_soc_dapm_add_routes(&codec->dapm,
594 adau1761_mono_dapm_routes,
595 ARRAY_SIZE(adau1761_mono_dapm_routes));
596 }
597
598 return ret;
599}
600
601static bool adau1761_readable_register(struct device *dev, unsigned int reg)
602{
603 switch (reg) {
604 case ADAU1761_DIGMIC_JACKDETECT:
605 case ADAU1761_REC_MIXER_LEFT0:
606 case ADAU1761_REC_MIXER_LEFT1:
607 case ADAU1761_REC_MIXER_RIGHT0:
608 case ADAU1761_REC_MIXER_RIGHT1:
609 case ADAU1761_LEFT_DIFF_INPUT_VOL:
610 case ADAU1761_RIGHT_DIFF_INPUT_VOL:
611 case ADAU1761_PLAY_LR_MIXER_LEFT:
612 case ADAU1761_PLAY_MIXER_LEFT0:
613 case ADAU1761_PLAY_MIXER_LEFT1:
614 case ADAU1761_PLAY_MIXER_RIGHT0:
615 case ADAU1761_PLAY_MIXER_RIGHT1:
616 case ADAU1761_PLAY_LR_MIXER_RIGHT:
617 case ADAU1761_PLAY_MIXER_MONO:
618 case ADAU1761_PLAY_HP_LEFT_VOL:
619 case ADAU1761_PLAY_HP_RIGHT_VOL:
620 case ADAU1761_PLAY_LINE_LEFT_VOL:
621 case ADAU1761_PLAY_LINE_RIGHT_VOL:
622 case ADAU1761_PLAY_MONO_OUTPUT_VOL:
623 case ADAU1761_POP_CLICK_SUPPRESS:
624 case ADAU1761_JACK_DETECT_PIN:
625 case ADAU1761_DEJITTER:
626 case ADAU1761_CLK_ENABLE0:
627 case ADAU1761_CLK_ENABLE1:
628 return true;
629 default:
630 break;
631 }
632
633 return adau17x1_readable_register(dev, reg);
634}
635
636static int adau1761_codec_probe(struct snd_soc_codec *codec)
637{
638 struct adau1761_platform_data *pdata = codec->dev->platform_data;
639 struct adau *adau = snd_soc_codec_get_drvdata(codec);
640 int ret;
641
642 ret = adau17x1_add_widgets(codec);
643 if (ret < 0)
644 return ret;
645
646 if (pdata && pdata->input_differential) {
647 regmap_update_bits(adau->regmap, ADAU1761_LEFT_DIFF_INPUT_VOL,
648 ADAU1761_DIFF_INPUT_VOL_LDEN,
649 ADAU1761_DIFF_INPUT_VOL_LDEN);
650 regmap_update_bits(adau->regmap, ADAU1761_RIGHT_DIFF_INPUT_VOL,
651 ADAU1761_DIFF_INPUT_VOL_LDEN,
652 ADAU1761_DIFF_INPUT_VOL_LDEN);
653 ret = snd_soc_add_codec_controls(codec,
654 adau1761_differential_mode_controls,
655 ARRAY_SIZE(adau1761_differential_mode_controls));
656 if (ret)
657 return ret;
658 } else {
659 ret = snd_soc_add_codec_controls(codec,
660 adau1761_single_mode_controls,
661 ARRAY_SIZE(adau1761_single_mode_controls));
662 if (ret)
663 return ret;
664 }
665
666 switch (adau1761_get_lineout_mode(codec)) {
667 case ADAU1761_OUTPUT_MODE_LINE:
668 break;
669 case ADAU1761_OUTPUT_MODE_HEADPHONE:
670 regmap_update_bits(adau->regmap, ADAU1761_PLAY_LINE_LEFT_VOL,
671 ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP,
672 ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP);
673 regmap_update_bits(adau->regmap, ADAU1761_PLAY_LINE_RIGHT_VOL,
674 ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP,
675 ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP);
676 break;
677 default:
678 return -EINVAL;
679 }
680
681 ret = adau1761_setup_headphone_mode(codec);
682 if (ret)
683 return ret;
684
685 ret = adau1761_setup_digmic_jackdetect(codec);
686 if (ret)
687 return ret;
688
689 if (adau->type == ADAU1761) {
690 ret = snd_soc_dapm_new_controls(&codec->dapm,
691 adau1761_dapm_widgets,
692 ARRAY_SIZE(adau1761_dapm_widgets));
693 if (ret)
694 return ret;
695
696 ret = snd_soc_dapm_add_routes(&codec->dapm,
697 adau1761_dapm_routes,
698 ARRAY_SIZE(adau1761_dapm_routes));
699 if (ret)
700 return ret;
701
702 ret = adau17x1_load_firmware(adau, codec->dev,
703 ADAU1761_FIRMWARE);
704 if (ret)
705 dev_warn(codec->dev, "Failed to firmware\n");
706 }
707
708 ret = adau17x1_add_routes(codec);
709 if (ret < 0)
710 return ret;
711
712 return 0;
713}
714
715static const struct snd_soc_codec_driver adau1761_codec_driver = {
716 .probe = adau1761_codec_probe,
717 .suspend = adau17x1_suspend,
718 .resume = adau17x1_resume,
719 .set_bias_level = adau1761_set_bias_level,
720
721 .controls = adau1761_controls,
722 .num_controls = ARRAY_SIZE(adau1761_controls),
723 .dapm_widgets = adau1x61_dapm_widgets,
724 .num_dapm_widgets = ARRAY_SIZE(adau1x61_dapm_widgets),
725 .dapm_routes = adau1x61_dapm_routes,
726 .num_dapm_routes = ARRAY_SIZE(adau1x61_dapm_routes),
727};
728
729#define ADAU1761_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
730 SNDRV_PCM_FMTBIT_S32_LE)
731
732static struct snd_soc_dai_driver adau1361_dai_driver = {
733 .name = "adau-hifi",
734 .playback = {
735 .stream_name = "Playback",
736 .channels_min = 2,
737 .channels_max = 4,
738 .rates = SNDRV_PCM_RATE_8000_96000,
739 .formats = ADAU1761_FORMATS,
740 },
741 .capture = {
742 .stream_name = "Capture",
743 .channels_min = 2,
744 .channels_max = 4,
745 .rates = SNDRV_PCM_RATE_8000_96000,
746 .formats = ADAU1761_FORMATS,
747 },
748 .ops = &adau17x1_dai_ops,
749};
750
751static struct snd_soc_dai_driver adau1761_dai_driver = {
752 .name = "adau-hifi",
753 .playback = {
754 .stream_name = "Playback",
755 .channels_min = 2,
756 .channels_max = 8,
757 .rates = SNDRV_PCM_RATE_8000_96000,
758 .formats = ADAU1761_FORMATS,
759 },
760 .capture = {
761 .stream_name = "Capture",
762 .channels_min = 2,
763 .channels_max = 8,
764 .rates = SNDRV_PCM_RATE_8000_96000,
765 .formats = ADAU1761_FORMATS,
766 },
767 .ops = &adau17x1_dai_ops,
768};
769
770int adau1761_probe(struct device *dev, struct regmap *regmap,
771 enum adau17x1_type type, void (*switch_mode)(struct device *dev))
772{
773 struct snd_soc_dai_driver *dai_drv;
774 int ret;
775
776 ret = adau17x1_probe(dev, regmap, type, switch_mode);
777 if (ret)
778 return ret;
779
780 if (type == ADAU1361)
781 dai_drv = &adau1361_dai_driver;
782 else
783 dai_drv = &adau1761_dai_driver;
784
785 return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1);
786}
787EXPORT_SYMBOL_GPL(adau1761_probe);
788
789const struct regmap_config adau1761_regmap_config = {
790 .val_bits = 8,
791 .reg_bits = 16,
792 .max_register = 0x40fa,
793 .reg_defaults = adau1761_reg_defaults,
794 .num_reg_defaults = ARRAY_SIZE(adau1761_reg_defaults),
795 .readable_reg = adau1761_readable_register,
796 .volatile_reg = adau17x1_volatile_register,
797 .cache_type = REGCACHE_RBTREE,
798};
799EXPORT_SYMBOL_GPL(adau1761_regmap_config);
800
801MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC driver");
802MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
803MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1761.h b/sound/soc/codecs/adau1761.h
new file mode 100644
index 000000000000..a9e0d288301e
--- /dev/null
+++ b/sound/soc/codecs/adau1761.h
@@ -0,0 +1,23 @@
1/*
2 * ADAU1361/ADAU1461/ADAU1761/ADAU1961 driver
3 *
4 * Copyright 2014 Analog Devices Inc.
5 * Author: Lars-Peter Clausen <lars@metafoo.de>
6 *
7 * Licensed under the GPL-2.
8 */
9
10#ifndef __SOUND_SOC_CODECS_ADAU1761_H__
11#define __SOUND_SOC_CODECS_ADAU1761_H__
12
13#include <linux/regmap.h>
14#include "adau17x1.h"
15
16struct device;
17
18int adau1761_probe(struct device *dev, struct regmap *regmap,
19 enum adau17x1_type type, void (*switch_mode)(struct device *dev));
20
21extern const struct regmap_config adau1761_regmap_config;
22
23#endif