diff options
author | Baoyou Xie <baoyou.xie@linaro.org> | 2017-06-22 02:51:58 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-06-23 07:41:56 -0400 |
commit | 0e15bdfd8b1e3a94862522580161a2d1bb3882a7 (patch) | |
tree | 6712c88cf50d76aeac2103cef4cddcfb66ecad5d | |
parent | 7de35c122e2dd8dc4d74b3782ced9c03115dc268 (diff) |
ASoC: zx_aud96p22: add ZTE ZX AUD96P22 codec driver
It adds ASoC driver for AUD96P22 stereo audio codec integrated on ZTE
ZX family SoCs. The driver includes the support for a number of volume
and mute controls, and power bits for various playback and recording
components.
Due to that the board for testing only supports playback, recording
support is untested.
Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | sound/soc/codecs/Kconfig | 5 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/codecs/zx_aud96p22.c | 403 |
3 files changed, 410 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 883ed4c8a551..3425bbcea2d1 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -1114,6 +1114,11 @@ config SND_SOC_WM9713 | |||
1114 | tristate | 1114 | tristate |
1115 | select REGMAP_AC97 | 1115 | select REGMAP_AC97 |
1116 | 1116 | ||
1117 | config SND_SOC_ZX_AUD96P22 | ||
1118 | tristate "ZTE ZX AUD96P22 CODEC" | ||
1119 | depends on I2C | ||
1120 | select REGMAP_I2C | ||
1121 | |||
1117 | # Amp | 1122 | # Amp |
1118 | config SND_SOC_LM4857 | 1123 | config SND_SOC_LM4857 |
1119 | tristate | 1124 | tristate |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 28a63fdaf982..d9858be7796a 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -224,6 +224,7 @@ snd-soc-wm9705-objs := wm9705.o | |||
224 | snd-soc-wm9712-objs := wm9712.o | 224 | snd-soc-wm9712-objs := wm9712.o |
225 | snd-soc-wm9713-objs := wm9713.o | 225 | snd-soc-wm9713-objs := wm9713.o |
226 | snd-soc-wm-hubs-objs := wm_hubs.o | 226 | snd-soc-wm-hubs-objs := wm_hubs.o |
227 | snd-soc-zx-aud96p22-objs := zx_aud96p22.o | ||
227 | # Amp | 228 | # Amp |
228 | snd-soc-dio2125-objs := dio2125.o | 229 | snd-soc-dio2125-objs := dio2125.o |
229 | snd-soc-max9877-objs := max9877.o | 230 | snd-soc-max9877-objs := max9877.o |
@@ -455,6 +456,7 @@ obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o | |||
455 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o | 456 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o |
456 | obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o | 457 | obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o |
457 | obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o | 458 | obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o |
459 | obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o | ||
458 | 460 | ||
459 | # Amp | 461 | # Amp |
460 | obj-$(CONFIG_SND_SOC_DIO2125) += snd-soc-dio2125.o | 462 | obj-$(CONFIG_SND_SOC_DIO2125) += snd-soc-dio2125.o |
diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c new file mode 100644 index 000000000000..032fb7cf6cbd --- /dev/null +++ b/sound/soc/codecs/zx_aud96p22.c | |||
@@ -0,0 +1,403 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Sanechips Technology Co., Ltd. | ||
3 | * Copyright 2017 Linaro Ltd. | ||
4 | * | ||
5 | * Author: Baoyou Xie <baoyou.xie@linaro.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/gpio/consumer.h> | ||
13 | #include <linux/i2c.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/regmap.h> | ||
16 | #include <sound/pcm.h> | ||
17 | #include <sound/pcm_params.h> | ||
18 | #include <sound/soc.h> | ||
19 | #include <sound/soc-dai.h> | ||
20 | #include <sound/tlv.h> | ||
21 | |||
22 | #define AUD96P22_RESET 0x00 | ||
23 | #define RST_DAC_DPZ BIT(0) | ||
24 | #define RST_ADC_DPZ BIT(1) | ||
25 | #define AUD96P22_I2S1_CONFIG_0 0x03 | ||
26 | #define I2S1_MS_MODE BIT(3) | ||
27 | #define I2S1_MODE_MASK 0x7 | ||
28 | #define I2S1_MODE_RIGHT_J 0x0 | ||
29 | #define I2S1_MODE_I2S 0x1 | ||
30 | #define I2S1_MODE_LEFT_J 0x2 | ||
31 | #define AUD96P22_PD_0 0x15 | ||
32 | #define AUD96P22_PD_1 0x16 | ||
33 | #define AUD96P22_PD_3 0x18 | ||
34 | #define AUD96P22_PD_4 0x19 | ||
35 | #define AUD96P22_MUTE_0 0x1d | ||
36 | #define AUD96P22_MUTE_2 0x1f | ||
37 | #define AUD96P22_MUTE_4 0x21 | ||
38 | #define AUD96P22_RECVOL_0 0x24 | ||
39 | #define AUD96P22_RECVOL_1 0x25 | ||
40 | #define AUD96P22_PGA1VOL_0 0x26 | ||
41 | #define AUD96P22_PGA1VOL_1 0x27 | ||
42 | #define AUD96P22_LMVOL_0 0x34 | ||
43 | #define AUD96P22_LMVOL_1 0x35 | ||
44 | #define AUD96P22_HS1VOL_0 0x38 | ||
45 | #define AUD96P22_HS1VOL_1 0x39 | ||
46 | #define AUD96P22_PGA1SEL_0 0x47 | ||
47 | #define AUD96P22_PGA1SEL_1 0x48 | ||
48 | #define AUD96P22_LDR1SEL_0 0x59 | ||
49 | #define AUD96P22_LDR1SEL_1 0x60 | ||
50 | #define AUD96P22_LDR2SEL_0 0x5d | ||
51 | #define AUD96P22_REG_MAX 0xfb | ||
52 | |||
53 | struct aud96p22_priv { | ||
54 | struct regmap *regmap; | ||
55 | }; | ||
56 | |||
57 | static int aud96p22_adc_event(struct snd_soc_dapm_widget *w, | ||
58 | struct snd_kcontrol *kcontrol, int event) | ||
59 | { | ||
60 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
61 | struct aud96p22_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
62 | struct regmap *regmap = priv->regmap; | ||
63 | |||
64 | if (event != SND_SOC_DAPM_POST_PMU) | ||
65 | return -EINVAL; | ||
66 | |||
67 | /* Assert/de-assert the bit to reset ADC data path */ | ||
68 | regmap_update_bits(regmap, AUD96P22_RESET, RST_ADC_DPZ, 0); | ||
69 | regmap_update_bits(regmap, AUD96P22_RESET, RST_ADC_DPZ, RST_ADC_DPZ); | ||
70 | |||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static int aud96p22_dac_event(struct snd_soc_dapm_widget *w, | ||
75 | struct snd_kcontrol *kcontrol, int event) | ||
76 | { | ||
77 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
78 | struct aud96p22_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
79 | struct regmap *regmap = priv->regmap; | ||
80 | |||
81 | if (event != SND_SOC_DAPM_POST_PMU) | ||
82 | return -EINVAL; | ||
83 | |||
84 | /* Assert/de-assert the bit to reset DAC data path */ | ||
85 | regmap_update_bits(regmap, AUD96P22_RESET, RST_DAC_DPZ, 0); | ||
86 | regmap_update_bits(regmap, AUD96P22_RESET, RST_DAC_DPZ, RST_DAC_DPZ); | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static const DECLARE_TLV_DB_SCALE(lm_tlv, -11550, 50, 0); | ||
92 | static const DECLARE_TLV_DB_SCALE(hs_tlv, -3900, 300, 0); | ||
93 | static const DECLARE_TLV_DB_SCALE(rec_tlv, -9550, 50, 0); | ||
94 | static const DECLARE_TLV_DB_SCALE(pga_tlv, -1800, 100, 0); | ||
95 | |||
96 | static const struct snd_kcontrol_new aud96p22_snd_controls[] = { | ||
97 | /* Volume control */ | ||
98 | SOC_DOUBLE_R_TLV("Master Playback Volume", AUD96P22_LMVOL_0, | ||
99 | AUD96P22_LMVOL_1, 0, 0xff, 0, lm_tlv), | ||
100 | SOC_DOUBLE_R_TLV("Headphone Volume", AUD96P22_HS1VOL_0, | ||
101 | AUD96P22_HS1VOL_1, 0, 0xf, 0, hs_tlv), | ||
102 | SOC_DOUBLE_R_TLV("Master Capture Volume", AUD96P22_RECVOL_0, | ||
103 | AUD96P22_RECVOL_1, 0, 0xff, 0, rec_tlv), | ||
104 | SOC_DOUBLE_R_TLV("Analogue Capture Volume", AUD96P22_PGA1VOL_0, | ||
105 | AUD96P22_PGA1VOL_1, 0, 0x37, 0, pga_tlv), | ||
106 | |||
107 | /* Mute control */ | ||
108 | SOC_DOUBLE("Master Playback Switch", AUD96P22_MUTE_2, 0, 1, 1, 1), | ||
109 | SOC_DOUBLE("Headphone Switch", AUD96P22_MUTE_2, 4, 5, 1, 1), | ||
110 | SOC_DOUBLE("Line Out Switch", AUD96P22_MUTE_4, 0, 1, 1, 1), | ||
111 | SOC_DOUBLE("Speaker Switch", AUD96P22_MUTE_4, 2, 3, 1, 1), | ||
112 | SOC_DOUBLE("Master Capture Switch", AUD96P22_MUTE_0, 0, 1, 1, 1), | ||
113 | SOC_DOUBLE("Analogue Capture Switch", AUD96P22_MUTE_0, 2, 3, 1, 1), | ||
114 | }; | ||
115 | |||
116 | /* Input mux kcontrols */ | ||
117 | static const unsigned int ain_mux_values[] = { | ||
118 | 0, 1, 3, 4, 5, | ||
119 | }; | ||
120 | |||
121 | static const char * const ainl_mux_texts[] = { | ||
122 | "AINL1 differential", | ||
123 | "AINL1 single-ended", | ||
124 | "AINL3 single-ended", | ||
125 | "AINL2 differential", | ||
126 | "AINL2 single-ended", | ||
127 | }; | ||
128 | |||
129 | static const char * const ainr_mux_texts[] = { | ||
130 | "AINR1 differential", | ||
131 | "AINR1 single-ended", | ||
132 | "AINR3 single-ended", | ||
133 | "AINR2 differential", | ||
134 | "AINR2 single-ended", | ||
135 | }; | ||
136 | |||
137 | static SOC_VALUE_ENUM_SINGLE_DECL(ainl_mux_enum, AUD96P22_PGA1SEL_0, | ||
138 | 0, 0x7, ainl_mux_texts, ain_mux_values); | ||
139 | static SOC_VALUE_ENUM_SINGLE_DECL(ainr_mux_enum, AUD96P22_PGA1SEL_1, | ||
140 | 0, 0x7, ainr_mux_texts, ain_mux_values); | ||
141 | |||
142 | static const struct snd_kcontrol_new ainl_mux_kcontrol = | ||
143 | SOC_DAPM_ENUM("AINL Mux", ainl_mux_enum); | ||
144 | static const struct snd_kcontrol_new ainr_mux_kcontrol = | ||
145 | SOC_DAPM_ENUM("AINR Mux", ainr_mux_enum); | ||
146 | |||
147 | /* Output mixer kcontrols */ | ||
148 | static const struct snd_kcontrol_new ld1_left_kcontrols[] = { | ||
149 | SOC_DAPM_SINGLE("DACL LD1L Switch", AUD96P22_LDR1SEL_0, 0, 1, 0), | ||
150 | SOC_DAPM_SINGLE("AINL LD1L Switch", AUD96P22_LDR1SEL_0, 1, 1, 0), | ||
151 | SOC_DAPM_SINGLE("AINR LD1L Switch", AUD96P22_LDR1SEL_0, 2, 1, 0), | ||
152 | }; | ||
153 | |||
154 | static const struct snd_kcontrol_new ld1_right_kcontrols[] = { | ||
155 | SOC_DAPM_SINGLE("DACR LD1R Switch", AUD96P22_LDR1SEL_1, 8, 1, 0), | ||
156 | SOC_DAPM_SINGLE("AINR LD1R Switch", AUD96P22_LDR1SEL_1, 9, 1, 0), | ||
157 | SOC_DAPM_SINGLE("AINL LD1R Switch", AUD96P22_LDR1SEL_1, 10, 1, 0), | ||
158 | }; | ||
159 | |||
160 | static const struct snd_kcontrol_new ld2_kcontrols[] = { | ||
161 | SOC_DAPM_SINGLE("DACL LD2 Switch", AUD96P22_LDR2SEL_0, 0, 1, 0), | ||
162 | SOC_DAPM_SINGLE("AINL LD2 Switch", AUD96P22_LDR2SEL_0, 1, 1, 0), | ||
163 | SOC_DAPM_SINGLE("DACR LD2 Switch", AUD96P22_LDR2SEL_0, 2, 1, 0), | ||
164 | }; | ||
165 | |||
166 | static const struct snd_soc_dapm_widget aud96p22_dapm_widgets[] = { | ||
167 | /* Overall power bit */ | ||
168 | SND_SOC_DAPM_SUPPLY("POWER", AUD96P22_PD_0, 0, 0, NULL, 0), | ||
169 | |||
170 | /* Input pins */ | ||
171 | SND_SOC_DAPM_INPUT("AINL1P"), | ||
172 | SND_SOC_DAPM_INPUT("AINL2P"), | ||
173 | SND_SOC_DAPM_INPUT("AINL3"), | ||
174 | SND_SOC_DAPM_INPUT("AINL1N"), | ||
175 | SND_SOC_DAPM_INPUT("AINL2N"), | ||
176 | SND_SOC_DAPM_INPUT("AINR2N"), | ||
177 | SND_SOC_DAPM_INPUT("AINR1N"), | ||
178 | SND_SOC_DAPM_INPUT("AINR3"), | ||
179 | SND_SOC_DAPM_INPUT("AINR2P"), | ||
180 | SND_SOC_DAPM_INPUT("AINR1P"), | ||
181 | |||
182 | /* Input muxes */ | ||
183 | SND_SOC_DAPM_MUX("AINLMUX", AUD96P22_PD_1, 2, 0, &ainl_mux_kcontrol), | ||
184 | SND_SOC_DAPM_MUX("AINRMUX", AUD96P22_PD_1, 3, 0, &ainr_mux_kcontrol), | ||
185 | |||
186 | /* ADCs */ | ||
187 | SND_SOC_DAPM_ADC_E("ADCL", "Capture Left", AUD96P22_PD_1, 0, 0, | ||
188 | aud96p22_adc_event, SND_SOC_DAPM_POST_PMU), | ||
189 | SND_SOC_DAPM_ADC_E("ADCR", "Capture Right", AUD96P22_PD_1, 1, 0, | ||
190 | aud96p22_adc_event, SND_SOC_DAPM_POST_PMU), | ||
191 | |||
192 | /* DACs */ | ||
193 | SND_SOC_DAPM_DAC_E("DACL", "Playback Left", AUD96P22_PD_3, 0, 0, | ||
194 | aud96p22_dac_event, SND_SOC_DAPM_POST_PMU), | ||
195 | SND_SOC_DAPM_DAC_E("DACR", "Playback Right", AUD96P22_PD_3, 1, 0, | ||
196 | aud96p22_dac_event, SND_SOC_DAPM_POST_PMU), | ||
197 | |||
198 | /* Output mixers */ | ||
199 | SND_SOC_DAPM_MIXER("LD1L", AUD96P22_PD_3, 6, 0, ld1_left_kcontrols, | ||
200 | ARRAY_SIZE(ld1_left_kcontrols)), | ||
201 | SND_SOC_DAPM_MIXER("LD1R", AUD96P22_PD_3, 7, 0, ld1_right_kcontrols, | ||
202 | ARRAY_SIZE(ld1_right_kcontrols)), | ||
203 | SND_SOC_DAPM_MIXER("LD2", AUD96P22_PD_4, 2, 0, ld2_kcontrols, | ||
204 | ARRAY_SIZE(ld2_kcontrols)), | ||
205 | |||
206 | /* Headset power switch */ | ||
207 | SND_SOC_DAPM_SUPPLY("HS1L", AUD96P22_PD_3, 4, 0, NULL, 0), | ||
208 | SND_SOC_DAPM_SUPPLY("HS1R", AUD96P22_PD_3, 5, 0, NULL, 0), | ||
209 | |||
210 | /* Output pins */ | ||
211 | SND_SOC_DAPM_OUTPUT("HSOUTL"), | ||
212 | SND_SOC_DAPM_OUTPUT("LINEOUTL"), | ||
213 | SND_SOC_DAPM_OUTPUT("LINEOUTMP"), | ||
214 | SND_SOC_DAPM_OUTPUT("LINEOUTMN"), | ||
215 | SND_SOC_DAPM_OUTPUT("LINEOUTR"), | ||
216 | SND_SOC_DAPM_OUTPUT("HSOUTR"), | ||
217 | }; | ||
218 | |||
219 | static const struct snd_soc_dapm_route aud96p22_dapm_routes[] = { | ||
220 | { "AINLMUX", "AINL1 differential", "AINL1N" }, | ||
221 | { "AINLMUX", "AINL1 single-ended", "AINL1P" }, | ||
222 | { "AINLMUX", "AINL3 single-ended", "AINL3" }, | ||
223 | { "AINLMUX", "AINL2 differential", "AINL2N" }, | ||
224 | { "AINLMUX", "AINL2 single-ended", "AINL2P" }, | ||
225 | |||
226 | { "AINRMUX", "AINR1 differential", "AINR1N" }, | ||
227 | { "AINRMUX", "AINR1 single-ended", "AINR1P" }, | ||
228 | { "AINRMUX", "AINR3 single-ended", "AINR3" }, | ||
229 | { "AINRMUX", "AINR2 differential", "AINR2N" }, | ||
230 | { "AINRMUX", "AINR2 single-ended", "AINR2P" }, | ||
231 | |||
232 | { "ADCL", NULL, "AINLMUX" }, | ||
233 | { "ADCR", NULL, "AINRMUX" }, | ||
234 | |||
235 | { "ADCL", NULL, "POWER" }, | ||
236 | { "ADCR", NULL, "POWER" }, | ||
237 | { "DACL", NULL, "POWER" }, | ||
238 | { "DACR", NULL, "POWER" }, | ||
239 | |||
240 | { "LD1L", "DACL LD1L Switch", "DACL" }, | ||
241 | { "LD1L", "AINL LD1L Switch", "AINLMUX" }, | ||
242 | { "LD1L", "AINR LD1L Switch", "AINRMUX" }, | ||
243 | |||
244 | { "LD1R", "DACR LD1R Switch", "DACR" }, | ||
245 | { "LD1R", "AINR LD1R Switch", "AINRMUX" }, | ||
246 | { "LD1R", "AINL LD1R Switch", "AINLMUX" }, | ||
247 | |||
248 | { "LD2", "DACL LD2 Switch", "DACL" }, | ||
249 | { "LD2", "AINL LD2 Switch", "AINLMUX" }, | ||
250 | { "LD2", "DACR LD2 Switch", "DACR" }, | ||
251 | |||
252 | { "HSOUTL", NULL, "LD1L" }, | ||
253 | { "HSOUTR", NULL, "LD1R" }, | ||
254 | { "HSOUTL", NULL, "HS1L" }, | ||
255 | { "HSOUTR", NULL, "HS1R" }, | ||
256 | |||
257 | { "LINEOUTL", NULL, "LD1L" }, | ||
258 | { "LINEOUTR", NULL, "LD1R" }, | ||
259 | |||
260 | { "LINEOUTMP", NULL, "LD2" }, | ||
261 | { "LINEOUTMN", NULL, "LD2" }, | ||
262 | }; | ||
263 | |||
264 | static struct snd_soc_codec_driver aud96p22_driver = { | ||
265 | .component_driver = { | ||
266 | .controls = aud96p22_snd_controls, | ||
267 | .num_controls = ARRAY_SIZE(aud96p22_snd_controls), | ||
268 | .dapm_widgets = aud96p22_dapm_widgets, | ||
269 | .num_dapm_widgets = ARRAY_SIZE(aud96p22_dapm_widgets), | ||
270 | .dapm_routes = aud96p22_dapm_routes, | ||
271 | .num_dapm_routes = ARRAY_SIZE(aud96p22_dapm_routes), | ||
272 | }, | ||
273 | }; | ||
274 | |||
275 | static int aud96p22_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
276 | { | ||
277 | struct aud96p22_priv *priv = snd_soc_codec_get_drvdata(dai->codec); | ||
278 | struct regmap *regmap = priv->regmap; | ||
279 | unsigned int val; | ||
280 | |||
281 | /* Master/slave mode */ | ||
282 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
283 | case SND_SOC_DAIFMT_CBS_CFS: | ||
284 | val = 0; | ||
285 | break; | ||
286 | case SND_SOC_DAIFMT_CBM_CFM: | ||
287 | val = I2S1_MS_MODE; | ||
288 | break; | ||
289 | default: | ||
290 | return -EINVAL; | ||
291 | } | ||
292 | |||
293 | regmap_update_bits(regmap, AUD96P22_I2S1_CONFIG_0, I2S1_MS_MODE, val); | ||
294 | |||
295 | /* Audio format */ | ||
296 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
297 | case SND_SOC_DAIFMT_RIGHT_J: | ||
298 | val = I2S1_MODE_RIGHT_J; | ||
299 | break; | ||
300 | case SND_SOC_DAIFMT_I2S: | ||
301 | val = I2S1_MODE_I2S; | ||
302 | break; | ||
303 | case SND_SOC_DAIFMT_LEFT_J: | ||
304 | val = I2S1_MODE_LEFT_J; | ||
305 | break; | ||
306 | default: | ||
307 | return -EINVAL; | ||
308 | } | ||
309 | |||
310 | regmap_update_bits(regmap, AUD96P22_I2S1_CONFIG_0, I2S1_MODE_MASK, val); | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static struct snd_soc_dai_ops aud96p22_dai_ops = { | ||
316 | .set_fmt = aud96p22_set_fmt, | ||
317 | }; | ||
318 | |||
319 | #define AUD96P22_RATES SNDRV_PCM_RATE_8000_192000 | ||
320 | #define AUD96P22_FORMATS (\ | ||
321 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ | ||
322 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) | ||
323 | |||
324 | static struct snd_soc_dai_driver aud96p22_dai = { | ||
325 | .name = "aud96p22-dai", | ||
326 | .playback = { | ||
327 | .stream_name = "Playback", | ||
328 | .channels_min = 1, | ||
329 | .channels_max = 2, | ||
330 | .rates = AUD96P22_RATES, | ||
331 | .formats = AUD96P22_FORMATS, | ||
332 | }, | ||
333 | .capture = { | ||
334 | .stream_name = "Capture", | ||
335 | .channels_min = 1, | ||
336 | .channels_max = 2, | ||
337 | .rates = AUD96P22_RATES, | ||
338 | .formats = AUD96P22_FORMATS, | ||
339 | }, | ||
340 | .ops = &aud96p22_dai_ops, | ||
341 | }; | ||
342 | |||
343 | static const struct regmap_config aud96p22_regmap = { | ||
344 | .reg_bits = 8, | ||
345 | .val_bits = 8, | ||
346 | .max_register = AUD96P22_REG_MAX, | ||
347 | .cache_type = REGCACHE_RBTREE, | ||
348 | }; | ||
349 | |||
350 | static int aud96p22_i2c_probe(struct i2c_client *i2c, | ||
351 | const struct i2c_device_id *id) | ||
352 | { | ||
353 | struct device *dev = &i2c->dev; | ||
354 | struct aud96p22_priv *priv; | ||
355 | int ret; | ||
356 | |||
357 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
358 | if (priv == NULL) | ||
359 | return -ENOMEM; | ||
360 | |||
361 | priv->regmap = devm_regmap_init_i2c(i2c, &aud96p22_regmap); | ||
362 | if (IS_ERR(priv->regmap)) { | ||
363 | ret = PTR_ERR(priv->regmap); | ||
364 | dev_err(dev, "failed to init i2c regmap: %d\n", ret); | ||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | i2c_set_clientdata(i2c, priv); | ||
369 | |||
370 | ret = snd_soc_register_codec(dev, &aud96p22_driver, &aud96p22_dai, 1); | ||
371 | if (ret) { | ||
372 | dev_err(dev, "failed to register codec: %d\n", ret); | ||
373 | return ret; | ||
374 | } | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | static int aud96p22_i2c_remove(struct i2c_client *i2c) | ||
380 | { | ||
381 | snd_soc_unregister_codec(&i2c->dev); | ||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | const struct of_device_id aud96p22_dt_ids[] = { | ||
386 | { .compatible = "zte,zx-aud96p22", }, | ||
387 | { } | ||
388 | }; | ||
389 | MODULE_DEVICE_TABLE(of, aud96p22_dt_ids); | ||
390 | |||
391 | static struct i2c_driver aud96p22_i2c_driver = { | ||
392 | .driver = { | ||
393 | .name = "zx_aud96p22", | ||
394 | .of_match_table = aud96p22_dt_ids, | ||
395 | }, | ||
396 | .probe = aud96p22_i2c_probe, | ||
397 | .remove = aud96p22_i2c_remove, | ||
398 | }; | ||
399 | module_i2c_driver(aud96p22_i2c_driver); | ||
400 | |||
401 | MODULE_DESCRIPTION("ZTE ASoC AUD96P22 CODEC driver"); | ||
402 | MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>"); | ||
403 | MODULE_LICENSE("GPL v2"); | ||