diff options
author | Vinod Koul <vinod.koul@intel.com> | 2011-01-04 09:46:07 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-01-06 08:47:15 -0500 |
commit | 4dc69be22163bab880384858f30cb8cc76ad47f9 (patch) | |
tree | 55b39383d706335370ee9dc4fb549818c09bd69f | |
parent | f6c2ed5dd6ab43447dacc136585fc894e3f3a82d (diff) |
ASoC: sst v2: Add sn95031 codec driver
This patch adds the sn95031 asoc codec driver. This driver currently
supports only playback. Capture and jack detection to be added later
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Harsha Priya <priya.harsha@intel.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | sound/soc/codecs/Kconfig | 4 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/codecs/sn95031.c | 495 | ||||
-rw-r--r-- | sound/soc/codecs/sn95031.h | 99 |
4 files changed, 600 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 054191ed08ef..fa42be529a73 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -32,6 +32,7 @@ config SND_SOC_ALL_CODECS | |||
32 | select SND_SOC_MAX98088 if I2C | 32 | select SND_SOC_MAX98088 if I2C |
33 | select SND_SOC_MAX9877 if I2C | 33 | select SND_SOC_MAX9877 if I2C |
34 | select SND_SOC_PCM3008 | 34 | select SND_SOC_PCM3008 |
35 | select SND_SOC_SN95031 if INTEL_SCU_IPC | ||
35 | select SND_SOC_SPDIF | 36 | select SND_SOC_SPDIF |
36 | select SND_SOC_SSM2602 if I2C | 37 | select SND_SOC_SSM2602 if I2C |
37 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS | 38 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS |
@@ -173,6 +174,9 @@ config SND_SOC_MAX98088 | |||
173 | config SND_SOC_PCM3008 | 174 | config SND_SOC_PCM3008 |
174 | tristate | 175 | tristate |
175 | 176 | ||
177 | config SND_SOC_SN95031 | ||
178 | tristate | ||
179 | |||
176 | config SND_SOC_SPDIF | 180 | config SND_SOC_SPDIF |
177 | tristate | 181 | tristate |
178 | 182 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 6a1e17bbbf83..76304d478912 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -18,6 +18,7 @@ snd-soc-l3-objs := l3.o | |||
18 | snd-soc-max98088-objs := max98088.o | 18 | snd-soc-max98088-objs := max98088.o |
19 | snd-soc-pcm3008-objs := pcm3008.o | 19 | snd-soc-pcm3008-objs := pcm3008.o |
20 | snd-soc-alc5623-objs := alc5623.o | 20 | snd-soc-alc5623-objs := alc5623.o |
21 | snd-soc-sn95031-objs := sn95031.o | ||
21 | snd-soc-spdif-objs := spdif_transciever.o | 22 | snd-soc-spdif-objs := spdif_transciever.o |
22 | snd-soc-ssm2602-objs := ssm2602.o | 23 | snd-soc-ssm2602-objs := ssm2602.o |
23 | snd-soc-stac9766-objs := stac9766.o | 24 | snd-soc-stac9766-objs := stac9766.o |
@@ -97,6 +98,7 @@ obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o | |||
97 | obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o | 98 | obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o |
98 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o | 99 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o |
99 | obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o | 100 | obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o |
101 | obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o | ||
100 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o | 102 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o |
101 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o | 103 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o |
102 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o | 104 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o |
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c new file mode 100644 index 000000000000..146b74467ae7 --- /dev/null +++ b/sound/soc/codecs/sn95031.c | |||
@@ -0,0 +1,495 @@ | |||
1 | /* | ||
2 | * sn95031.c - TI sn95031 Codec driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Intel Corp | ||
5 | * Author: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Author: Harsha Priya <priya.harsha@intel.com> | ||
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
21 | * | ||
22 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
23 | * | ||
24 | * | ||
25 | */ | ||
26 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
27 | |||
28 | #include <linux/platform_device.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <asm/intel_scu_ipc.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/pcm_params.h> | ||
33 | #include <sound/soc.h> | ||
34 | #include <sound/soc-dapm.h> | ||
35 | #include <sound/initval.h> | ||
36 | #include "sn95031.h" | ||
37 | |||
38 | #define SN95031_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100) | ||
39 | #define SN95031_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) | ||
40 | |||
41 | /* | ||
42 | * todo: | ||
43 | * capture paths | ||
44 | * jack detection | ||
45 | * PM functions | ||
46 | */ | ||
47 | |||
48 | static inline unsigned int sn95031_read(struct snd_soc_codec *codec, | ||
49 | unsigned int reg) | ||
50 | { | ||
51 | u8 value = 0; | ||
52 | int ret; | ||
53 | |||
54 | ret = intel_scu_ipc_ioread8(reg, &value); | ||
55 | if (ret) | ||
56 | pr_err("read of %x failed, err %d\n", reg, ret); | ||
57 | return value; | ||
58 | |||
59 | } | ||
60 | |||
61 | static inline int sn95031_write(struct snd_soc_codec *codec, | ||
62 | unsigned int reg, unsigned int value) | ||
63 | { | ||
64 | int ret; | ||
65 | |||
66 | ret = intel_scu_ipc_iowrite8(reg, value); | ||
67 | if (ret) | ||
68 | pr_err("write of %x failed, err %d\n", reg, ret); | ||
69 | return ret; | ||
70 | } | ||
71 | |||
72 | static int sn95031_set_vaud_bias(struct snd_soc_codec *codec, | ||
73 | enum snd_soc_bias_level level) | ||
74 | { | ||
75 | switch (level) { | ||
76 | case SND_SOC_BIAS_ON: | ||
77 | break; | ||
78 | |||
79 | case SND_SOC_BIAS_PREPARE: | ||
80 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { | ||
81 | pr_debug("vaud_bias powering up pll\n"); | ||
82 | /* power up the pll */ | ||
83 | snd_soc_write(codec, SN95031_AUDPLLCTRL, BIT(5)); | ||
84 | /* enable pcm 2 */ | ||
85 | snd_soc_update_bits(codec, SN95031_PCM2C2, | ||
86 | BIT(0), BIT(0)); | ||
87 | } | ||
88 | break; | ||
89 | |||
90 | case SND_SOC_BIAS_STANDBY: | ||
91 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | ||
92 | pr_debug("vaud_bias power up rail\n"); | ||
93 | /* power up the rail */ | ||
94 | snd_soc_write(codec, SN95031_VAUD, | ||
95 | BIT(2)|BIT(1)|BIT(0)); | ||
96 | msleep(1); | ||
97 | } else if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) { | ||
98 | /* turn off pcm */ | ||
99 | pr_debug("vaud_bias power dn pcm\n"); | ||
100 | snd_soc_update_bits(codec, SN95031_PCM2C2, BIT(0), 0); | ||
101 | snd_soc_write(codec, SN95031_AUDPLLCTRL, 0); | ||
102 | } | ||
103 | break; | ||
104 | |||
105 | |||
106 | case SND_SOC_BIAS_OFF: | ||
107 | pr_debug("vaud_bias _OFF doing rail shutdown\n"); | ||
108 | snd_soc_write(codec, SN95031_VAUD, BIT(3)); | ||
109 | break; | ||
110 | } | ||
111 | |||
112 | codec->dapm.bias_level = level; | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int sn95031_vhs_event(struct snd_soc_dapm_widget *w, | ||
117 | struct snd_kcontrol *kcontrol, int event) | ||
118 | { | ||
119 | if (SND_SOC_DAPM_EVENT_ON(event)) { | ||
120 | pr_debug("VHS SND_SOC_DAPM_EVENT_ON doing rail startup now\n"); | ||
121 | /* power up the rail */ | ||
122 | snd_soc_write(w->codec, SN95031_VHSP, 0x3D); | ||
123 | snd_soc_write(w->codec, SN95031_VHSN, 0x3F); | ||
124 | msleep(1); | ||
125 | } else if (SND_SOC_DAPM_EVENT_OFF(event)) { | ||
126 | pr_debug("VHS SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n"); | ||
127 | snd_soc_write(w->codec, SN95031_VHSP, 0xC4); | ||
128 | snd_soc_write(w->codec, SN95031_VHSN, 0x04); | ||
129 | } | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int sn95031_vihf_event(struct snd_soc_dapm_widget *w, | ||
134 | struct snd_kcontrol *kcontrol, int event) | ||
135 | { | ||
136 | if (SND_SOC_DAPM_EVENT_ON(event)) { | ||
137 | pr_debug("VIHF SND_SOC_DAPM_EVENT_ON doing rail startup now\n"); | ||
138 | /* power up the rail */ | ||
139 | snd_soc_write(w->codec, SN95031_VIHF, 0x27); | ||
140 | msleep(1); | ||
141 | } else if (SND_SOC_DAPM_EVENT_OFF(event)) { | ||
142 | pr_debug("VIHF SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n"); | ||
143 | snd_soc_write(w->codec, SN95031_VIHF, 0x24); | ||
144 | } | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | /* DAPM widgets */ | ||
149 | static const struct snd_soc_dapm_widget sn95031_dapm_widgets[] = { | ||
150 | |||
151 | /* all end points mic, hs etc */ | ||
152 | SND_SOC_DAPM_OUTPUT("HPOUTL"), | ||
153 | SND_SOC_DAPM_OUTPUT("HPOUTR"), | ||
154 | SND_SOC_DAPM_OUTPUT("EPOUT"), | ||
155 | SND_SOC_DAPM_OUTPUT("IHFOUTL"), | ||
156 | SND_SOC_DAPM_OUTPUT("IHFOUTR"), | ||
157 | SND_SOC_DAPM_OUTPUT("LINEOUTL"), | ||
158 | SND_SOC_DAPM_OUTPUT("LINEOUTR"), | ||
159 | SND_SOC_DAPM_OUTPUT("VIB1OUT"), | ||
160 | SND_SOC_DAPM_OUTPUT("VIB2OUT"), | ||
161 | |||
162 | SND_SOC_DAPM_SUPPLY("Headset Rail", SND_SOC_NOPM, 0, 0, | ||
163 | sn95031_vhs_event, | ||
164 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
165 | SND_SOC_DAPM_SUPPLY("Speaker Rail", SND_SOC_NOPM, 0, 0, | ||
166 | sn95031_vihf_event, | ||
167 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
168 | |||
169 | /* playback path driver enables */ | ||
170 | SND_SOC_DAPM_PGA("Headset Left Playback", | ||
171 | SN95031_DRIVEREN, 0, 0, NULL, 0), | ||
172 | SND_SOC_DAPM_PGA("Headset Right Playback", | ||
173 | SN95031_DRIVEREN, 1, 0, NULL, 0), | ||
174 | SND_SOC_DAPM_PGA("Speaker Left Playback", | ||
175 | SN95031_DRIVEREN, 2, 0, NULL, 0), | ||
176 | SND_SOC_DAPM_PGA("Speaker Right Playback", | ||
177 | SN95031_DRIVEREN, 3, 0, NULL, 0), | ||
178 | SND_SOC_DAPM_PGA("Vibra1 Playback", | ||
179 | SN95031_DRIVEREN, 4, 0, NULL, 0), | ||
180 | SND_SOC_DAPM_PGA("Vibra2 Playback", | ||
181 | SN95031_DRIVEREN, 5, 0, NULL, 0), | ||
182 | SND_SOC_DAPM_PGA("Earpiece Playback", | ||
183 | SN95031_DRIVEREN, 6, 0, NULL, 0), | ||
184 | SND_SOC_DAPM_PGA("Lineout Left Playback", | ||
185 | SN95031_LOCTL, 0, 0, NULL, 0), | ||
186 | SND_SOC_DAPM_PGA("Lineout Right Playback", | ||
187 | SN95031_LOCTL, 4, 0, NULL, 0), | ||
188 | |||
189 | /* playback path filter enable */ | ||
190 | SND_SOC_DAPM_PGA("Headset Left Filter", | ||
191 | SN95031_HSEPRXCTRL, 4, 0, NULL, 0), | ||
192 | SND_SOC_DAPM_PGA("Headset Right Filter", | ||
193 | SN95031_HSEPRXCTRL, 5, 0, NULL, 0), | ||
194 | SND_SOC_DAPM_PGA("Speaker Left Filter", | ||
195 | SN95031_IHFRXCTRL, 0, 0, NULL, 0), | ||
196 | SND_SOC_DAPM_PGA("Speaker Right Filter", | ||
197 | SN95031_IHFRXCTRL, 1, 0, NULL, 0), | ||
198 | |||
199 | /* DACs */ | ||
200 | SND_SOC_DAPM_DAC("HSDAC Left", "Headset", | ||
201 | SN95031_DACCONFIG, 0, 0), | ||
202 | SND_SOC_DAPM_DAC("HSDAC Right", "Headset", | ||
203 | SN95031_DACCONFIG, 1, 0), | ||
204 | SND_SOC_DAPM_DAC("IHFDAC Left", "Speaker", | ||
205 | SN95031_DACCONFIG, 2, 0), | ||
206 | SND_SOC_DAPM_DAC("IHFDAC Right", "Speaker", | ||
207 | SN95031_DACCONFIG, 3, 0), | ||
208 | SND_SOC_DAPM_DAC("Vibra1 DAC", "Vibra1", | ||
209 | SN95031_VIB1C5, 1, 0), | ||
210 | SND_SOC_DAPM_DAC("Vibra2 DAC", "Vibra2", | ||
211 | SN95031_VIB2C5, 1, 0), | ||
212 | }; | ||
213 | |||
214 | static const struct snd_soc_dapm_route sn95031_audio_map[] = { | ||
215 | /* headset and earpiece map */ | ||
216 | { "HPOUTL", NULL, "Headset Left Playback" }, | ||
217 | { "HPOUTR", NULL, "Headset Right Playback" }, | ||
218 | { "EPOUT", NULL, "Earpiece Playback" }, | ||
219 | { "Headset Left Playback", NULL, "Headset Left Filter"}, | ||
220 | { "Headset Right Playback", NULL, "Headset Right Filter"}, | ||
221 | { "Earpiece Playback", NULL, "Headset Left Filter"}, | ||
222 | { "Headset Left Filter", NULL, "HSDAC Left"}, | ||
223 | { "Headset Right Filter", NULL, "HSDAC Right"}, | ||
224 | { "HSDAC Left", NULL, "Headset Rail"}, | ||
225 | { "HSDAC Right", NULL, "Headset Rail"}, | ||
226 | |||
227 | /* speaker map */ | ||
228 | { "IHFOUTL", "NULL", "Speaker Left Playback"}, | ||
229 | { "IHFOUTR", "NULL", "Speaker Right Playback"}, | ||
230 | { "Speaker Left Playback", NULL, "Speaker Left Filter"}, | ||
231 | { "Speaker Right Playback", NULL, "Speaker Right Filter"}, | ||
232 | { "Speaker Left Filter", NULL, "IHFDAC Left"}, | ||
233 | { "Speaker Right Filter", NULL, "IHFDAC Right"}, | ||
234 | { "IHFDAC Left", NULL, "Speaker Rail"}, | ||
235 | { "IHFDAC Right", NULL, "Speaker Rail"}, | ||
236 | |||
237 | /* vibra map */ | ||
238 | {"VIB1OUT", NULL, "Vibra1 Playback"}, | ||
239 | {"Vibra1 Playback", NULL, "Vibra1 DAC"}, | ||
240 | |||
241 | {"VIB2OUT", NULL, "Vibra2 Playback"}, | ||
242 | {"Vibra2 Playback", NULL, "Vibra2 DAC"}, | ||
243 | |||
244 | /* lineout */ | ||
245 | {"LINEOUTL", NULL, "Lineout Left Playback"}, | ||
246 | {"LINEOUTR", NULL, "Lineout Right Playback"}, | ||
247 | {"Lineout Left Playback", NULL, "Headset Left Filter"}, | ||
248 | {"Lineout Left Playback", NULL, "Speaker Left Filter"}, | ||
249 | {"Lineout Left Playback", NULL, "Vibra1 DAC"}, | ||
250 | {"Lineout Right Playback", NULL, "Headset Right Filter"}, | ||
251 | {"Lineout Right Playback", NULL, "Speaker Right Filter"}, | ||
252 | {"Lineout Right Playback", NULL, "Vibra2 DAC"}, | ||
253 | }; | ||
254 | |||
255 | /* speaker and headset mutes, for audio pops and clicks */ | ||
256 | static int sn95031_pcm_hs_mute(struct snd_soc_dai *dai, int mute) | ||
257 | { | ||
258 | snd_soc_update_bits(dai->codec, | ||
259 | SN95031_HSLVOLCTRL, BIT(7), (!mute << 7)); | ||
260 | snd_soc_update_bits(dai->codec, | ||
261 | SN95031_HSRVOLCTRL, BIT(7), (!mute << 7)); | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static int sn95031_pcm_spkr_mute(struct snd_soc_dai *dai, int mute) | ||
266 | { | ||
267 | snd_soc_update_bits(dai->codec, | ||
268 | SN95031_IHFLVOLCTRL, BIT(7), (!mute << 7)); | ||
269 | snd_soc_update_bits(dai->codec, | ||
270 | SN95031_IHFRVOLCTRL, BIT(7), (!mute << 7)); | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | int sn95031_pcm_hw_params(struct snd_pcm_substream *substream, | ||
275 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | ||
276 | { | ||
277 | unsigned int format, rate; | ||
278 | |||
279 | switch (params_format(params)) { | ||
280 | case SNDRV_PCM_FORMAT_S16_LE: | ||
281 | format = BIT(4)|BIT(5); | ||
282 | break; | ||
283 | |||
284 | case SNDRV_PCM_FORMAT_S24_LE: | ||
285 | format = 0; | ||
286 | break; | ||
287 | default: | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | snd_soc_update_bits(dai->codec, SN95031_PCM2C2, | ||
291 | BIT(4)|BIT(5), format); | ||
292 | |||
293 | switch (params_rate(params)) { | ||
294 | case 48000: | ||
295 | pr_debug("RATE_48000\n"); | ||
296 | rate = 0; | ||
297 | break; | ||
298 | |||
299 | case 44100: | ||
300 | pr_debug("RATE_44100\n"); | ||
301 | rate = BIT(7); | ||
302 | break; | ||
303 | |||
304 | default: | ||
305 | pr_err("ERR rate %d\n", params_rate(params)); | ||
306 | return -EINVAL; | ||
307 | } | ||
308 | snd_soc_update_bits(dai->codec, SN95031_PCM1C1, BIT(7), rate); | ||
309 | |||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | /* Codec DAI section */ | ||
314 | static struct snd_soc_dai_ops sn95031_headset_dai_ops = { | ||
315 | .digital_mute = sn95031_pcm_hs_mute, | ||
316 | .hw_params = sn95031_pcm_hw_params, | ||
317 | }; | ||
318 | |||
319 | static struct snd_soc_dai_ops sn95031_speaker_dai_ops = { | ||
320 | .digital_mute = sn95031_pcm_spkr_mute, | ||
321 | .hw_params = sn95031_pcm_hw_params, | ||
322 | }; | ||
323 | |||
324 | static struct snd_soc_dai_ops sn95031_vib1_dai_ops = { | ||
325 | .hw_params = sn95031_pcm_hw_params, | ||
326 | }; | ||
327 | |||
328 | static struct snd_soc_dai_ops sn95031_vib2_dai_ops = { | ||
329 | .hw_params = sn95031_pcm_hw_params, | ||
330 | }; | ||
331 | |||
332 | struct snd_soc_dai_driver sn95031_dais[] = { | ||
333 | { | ||
334 | .name = "SN95031 Headset", | ||
335 | .playback = { | ||
336 | .stream_name = "Headset", | ||
337 | .channels_min = 2, | ||
338 | .channels_max = 2, | ||
339 | .rates = SN95031_RATES, | ||
340 | .formats = SN95031_FORMATS, | ||
341 | }, | ||
342 | .ops = &sn95031_headset_dai_ops, | ||
343 | }, | ||
344 | { .name = "SN95031 Speaker", | ||
345 | .playback = { | ||
346 | .stream_name = "Speaker", | ||
347 | .channels_min = 2, | ||
348 | .channels_max = 2, | ||
349 | .rates = SN95031_RATES, | ||
350 | .formats = SN95031_FORMATS, | ||
351 | }, | ||
352 | .ops = &sn95031_speaker_dai_ops, | ||
353 | }, | ||
354 | { .name = "SN95031 Vibra1", | ||
355 | .playback = { | ||
356 | .stream_name = "Vibra1", | ||
357 | .channels_min = 1, | ||
358 | .channels_max = 1, | ||
359 | .rates = SN95031_RATES, | ||
360 | .formats = SN95031_FORMATS, | ||
361 | }, | ||
362 | .ops = &sn95031_vib1_dai_ops, | ||
363 | }, | ||
364 | { .name = "SN95031 Vibra2", | ||
365 | .playback = { | ||
366 | .stream_name = "Vibra2", | ||
367 | .channels_min = 1, | ||
368 | .channels_max = 1, | ||
369 | .rates = SN95031_RATES, | ||
370 | .formats = SN95031_FORMATS, | ||
371 | }, | ||
372 | .ops = &sn95031_vib2_dai_ops, | ||
373 | }, | ||
374 | }; | ||
375 | |||
376 | /* codec registration */ | ||
377 | static int sn95031_codec_probe(struct snd_soc_codec *codec) | ||
378 | { | ||
379 | int ret; | ||
380 | |||
381 | pr_debug("codec_probe called\n"); | ||
382 | |||
383 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; | ||
384 | codec->dapm.idle_bias_off = 1; | ||
385 | |||
386 | /* PCM interface config | ||
387 | * This sets the pcm rx slot conguration to max 6 slots | ||
388 | * for max 4 dais (2 stereo and 2 mono) | ||
389 | */ | ||
390 | snd_soc_write(codec, SN95031_PCM2RXSLOT01, 0x10); | ||
391 | snd_soc_write(codec, SN95031_PCM2RXSLOT23, 0x32); | ||
392 | snd_soc_write(codec, SN95031_PCM2RXSLOT45, 0x54); | ||
393 | /* pcm port setting | ||
394 | * This sets the pcm port to slave and clock at 19.2Mhz which | ||
395 | * can support 6slots, sampling rate set per stream in hw-params | ||
396 | */ | ||
397 | snd_soc_write(codec, SN95031_PCM1C1, 0x00); | ||
398 | snd_soc_write(codec, SN95031_PCM2C1, 0x01); | ||
399 | snd_soc_write(codec, SN95031_PCM2C2, 0x0A); | ||
400 | snd_soc_write(codec, SN95031_HSMIXER, BIT(0)|BIT(4)); | ||
401 | /* vendor vibra workround, the vibras are muted by | ||
402 | * custom register so unmute them | ||
403 | */ | ||
404 | snd_soc_write(codec, SN95031_SSR5, 0x80); | ||
405 | snd_soc_write(codec, SN95031_SSR6, 0x80); | ||
406 | snd_soc_write(codec, SN95031_VIB1C5, 0x00); | ||
407 | snd_soc_write(codec, SN95031_VIB2C5, 0x00); | ||
408 | /* configure vibras for pcm port */ | ||
409 | snd_soc_write(codec, SN95031_VIB1C3, 0x00); | ||
410 | snd_soc_write(codec, SN95031_VIB2C3, 0x00); | ||
411 | |||
412 | /* soft mute ramp time */ | ||
413 | snd_soc_write(codec, SN95031_SOFTMUTE, 0x3); | ||
414 | /* fix the initial volume at 1dB, | ||
415 | * default in +9dB, | ||
416 | * 1dB give optimal swing on DAC, amps | ||
417 | */ | ||
418 | snd_soc_write(codec, SN95031_HSLVOLCTRL, 0x08); | ||
419 | snd_soc_write(codec, SN95031_HSRVOLCTRL, 0x08); | ||
420 | snd_soc_write(codec, SN95031_IHFLVOLCTRL, 0x08); | ||
421 | snd_soc_write(codec, SN95031_IHFRVOLCTRL, 0x08); | ||
422 | /* dac mode and lineout workaround */ | ||
423 | snd_soc_write(codec, SN95031_SSR2, 0x10); | ||
424 | snd_soc_write(codec, SN95031_SSR3, 0x40); | ||
425 | |||
426 | ret = snd_soc_dapm_new_controls(&codec->dapm, sn95031_dapm_widgets, | ||
427 | ARRAY_SIZE(sn95031_dapm_widgets)); | ||
428 | if (ret) | ||
429 | pr_err("soc_dapm_new_control failed %d", ret); | ||
430 | ret = snd_soc_dapm_add_routes(&codec->dapm, sn95031_audio_map, | ||
431 | ARRAY_SIZE(sn95031_audio_map)); | ||
432 | if (ret) | ||
433 | pr_err("soc_dapm_add_routes failed %d", ret); | ||
434 | |||
435 | return ret; | ||
436 | } | ||
437 | |||
438 | static int sn95031_codec_remove(struct snd_soc_codec *codec) | ||
439 | { | ||
440 | pr_debug("codec_remove called\n"); | ||
441 | sn95031_set_vaud_bias(codec, SND_SOC_BIAS_OFF); | ||
442 | |||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | struct snd_soc_codec_driver sn95031_codec = { | ||
447 | .probe = sn95031_codec_probe, | ||
448 | .remove = sn95031_codec_remove, | ||
449 | .read = sn95031_read, | ||
450 | .write = sn95031_write, | ||
451 | .set_bias_level = sn95031_set_vaud_bias, | ||
452 | }; | ||
453 | |||
454 | static int __devinit sn95031_device_probe(struct platform_device *pdev) | ||
455 | { | ||
456 | pr_debug("codec device probe called for %s\n", dev_name(&pdev->dev)); | ||
457 | return snd_soc_register_codec(&pdev->dev, &sn95031_codec, | ||
458 | sn95031_dais, ARRAY_SIZE(sn95031_dais)); | ||
459 | } | ||
460 | |||
461 | static int __devexit sn95031_device_remove(struct platform_device *pdev) | ||
462 | { | ||
463 | pr_debug("codec device remove called\n"); | ||
464 | snd_soc_unregister_codec(&pdev->dev); | ||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | static struct platform_driver sn95031_codec_driver = { | ||
469 | .driver = { | ||
470 | .name = "sn95031", | ||
471 | .owner = THIS_MODULE, | ||
472 | }, | ||
473 | .probe = sn95031_device_probe, | ||
474 | .remove = sn95031_device_remove, | ||
475 | }; | ||
476 | |||
477 | static int __init sn95031_init(void) | ||
478 | { | ||
479 | pr_debug("driver init called\n"); | ||
480 | return platform_driver_register(&sn95031_codec_driver); | ||
481 | } | ||
482 | module_init(sn95031_init); | ||
483 | |||
484 | static void __exit sn95031_exit(void) | ||
485 | { | ||
486 | pr_debug("driver exit called\n"); | ||
487 | platform_driver_unregister(&sn95031_codec_driver); | ||
488 | } | ||
489 | module_exit(sn95031_exit); | ||
490 | |||
491 | MODULE_DESCRIPTION("ASoC Intel(R) SN95031 codec driver"); | ||
492 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); | ||
493 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); | ||
494 | MODULE_LICENSE("GPL v2"); | ||
495 | MODULE_ALIAS("platform:sn95031"); | ||
diff --git a/sound/soc/codecs/sn95031.h b/sound/soc/codecs/sn95031.h new file mode 100644 index 000000000000..b17a39b2aef5 --- /dev/null +++ b/sound/soc/codecs/sn95031.h | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * sn95031.h - TI sn95031 Codec driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Intel Corp | ||
5 | * Author: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Author: Harsha Priya <priya.harsha@intel.com> | ||
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
21 | * | ||
22 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
23 | * | ||
24 | * | ||
25 | */ | ||
26 | #ifndef _SN95031_H | ||
27 | #define _SN95031_H | ||
28 | |||
29 | /*register map*/ | ||
30 | #define SN95031_VAUD 0xDB | ||
31 | #define SN95031_VHSP 0xDC | ||
32 | #define SN95031_VHSN 0xDD | ||
33 | #define SN95031_VIHF 0xC9 | ||
34 | |||
35 | #define SN95031_AUDPLLCTRL 0x240 | ||
36 | #define SN95031_DMICBUF0123 0x241 | ||
37 | #define SN95031_DMICBUF45 0x242 | ||
38 | #define SN95031_DMICGPO 0x244 | ||
39 | #define SN95031_DMICMUX 0x245 | ||
40 | #define SN95031_DMICLK 0x246 | ||
41 | #define SN95031_MICBIAS 0x247 | ||
42 | #define SN95031_ADCCONFIG 0x248 | ||
43 | #define SN95031_MICAMP1 0x249 | ||
44 | #define SN95031_MICAMP2 0x24A | ||
45 | #define SN95031_NOISEMUX 0x24B | ||
46 | #define SN95031_AUDIOMUX12 0x24C | ||
47 | #define SN95031_AUDIOMUX34 0x24D | ||
48 | #define SN95031_AUDIOSINC 0x24E | ||
49 | #define SN95031_AUDIOTXEN 0x24F | ||
50 | #define SN95031_HSEPRXCTRL 0x250 | ||
51 | #define SN95031_IHFRXCTRL 0x251 | ||
52 | #define SN95031_HSMIXER 0x256 | ||
53 | #define SN95031_DACCONFIG 0x257 | ||
54 | #define SN95031_SOFTMUTE 0x258 | ||
55 | #define SN95031_HSLVOLCTRL 0x259 | ||
56 | #define SN95031_HSRVOLCTRL 0x25A | ||
57 | #define SN95031_IHFLVOLCTRL 0x25B | ||
58 | #define SN95031_IHFRVOLCTRL 0x25C | ||
59 | #define SN95031_DRIVEREN 0x25D | ||
60 | #define SN95031_LOCTL 0x25E | ||
61 | #define SN95031_VIB1C1 0x25F | ||
62 | #define SN95031_VIB1C2 0x260 | ||
63 | #define SN95031_VIB1C3 0x261 | ||
64 | #define SN95031_VIB1SPIPCM1 0x262 | ||
65 | #define SN95031_VIB1SPIPCM2 0x263 | ||
66 | #define SN95031_VIB1C5 0x264 | ||
67 | #define SN95031_VIB2C1 0x265 | ||
68 | #define SN95031_VIB2C2 0x266 | ||
69 | #define SN95031_VIB2C3 0x267 | ||
70 | #define SN95031_VIB2SPIPCM1 0x268 | ||
71 | #define SN95031_VIB2SPIPCM2 0x269 | ||
72 | #define SN95031_VIB2C5 0x26A | ||
73 | #define SN95031_BTNCTRL1 0x26B | ||
74 | #define SN95031_BTNCTRL2 0x26C | ||
75 | #define SN95031_PCM1TXSLOT01 0x26D | ||
76 | #define SN95031_PCM1TXSLOT23 0x26E | ||
77 | #define SN95031_PCM1TXSLOT45 0x26F | ||
78 | #define SN95031_PCM1RXSLOT0_3 0x270 | ||
79 | #define SN95031_PCM1RXSLOT45 0x271 | ||
80 | #define SN95031_PCM2TXSLOT01 0x272 | ||
81 | #define SN95031_PCM2TXSLOT23 0x273 | ||
82 | #define SN95031_PCM2TXSLOT45 0x274 | ||
83 | #define SN95031_PCM2RXSLOT01 0x275 | ||
84 | #define SN95031_PCM2RXSLOT23 0x276 | ||
85 | #define SN95031_PCM2RXSLOT45 0x277 | ||
86 | #define SN95031_PCM1C1 0x278 | ||
87 | #define SN95031_PCM1C2 0x279 | ||
88 | #define SN95031_PCM1C3 0x27A | ||
89 | #define SN95031_PCM2C1 0x27B | ||
90 | #define SN95031_PCM2C2 0x27C | ||
91 | /*end codec register defn*/ | ||
92 | |||
93 | /*vendor defn these are not part of avp*/ | ||
94 | #define SN95031_SSR2 0x381 | ||
95 | #define SN95031_SSR3 0x382 | ||
96 | #define SN95031_SSR5 0x384 | ||
97 | #define SN95031_SSR6 0x385 | ||
98 | |||
99 | #endif | ||