diff options
author | Dmitry Artamonow <mad_soft@inbox.ru> | 2011-05-18 11:25:09 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-05-19 17:10:45 -0400 |
commit | 00d2701070c91728988bbfa414a346a23acd8275 (patch) | |
tree | 56ea07afd0a1772fbcfa7b5847e26c6bb3920992 /sound/soc/codecs | |
parent | 539494253547d078089cc15490e83f6e5f2e7213 (diff) |
ASoC: Asahi Kasei AK4641 codec driver
A driver for the AK4641 codec used in iPAQ hx4700 and Glofiish M800
among others.
Signed-off-by: Harald Welte <laforge@gnumonks.org>
Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
Signed-off-by: Dmitry Artamonow <mad_soft@inbox.ru>
Acked-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r-- | sound/soc/codecs/Kconfig | 4 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/codecs/ak4641.c | 664 | ||||
-rw-r--r-- | sound/soc/codecs/ak4641.h | 47 |
4 files changed, 717 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 2a6971891d31..98175a096df2 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -20,6 +20,7 @@ config SND_SOC_ALL_CODECS | |||
20 | select SND_SOC_ADS117X | 20 | select SND_SOC_ADS117X |
21 | select SND_SOC_AK4104 if SPI_MASTER | 21 | select SND_SOC_AK4104 if SPI_MASTER |
22 | select SND_SOC_AK4535 if I2C | 22 | select SND_SOC_AK4535 if I2C |
23 | select SND_SOC_AK4641 if I2C | ||
23 | select SND_SOC_AK4642 if I2C | 24 | select SND_SOC_AK4642 if I2C |
24 | select SND_SOC_AK4671 if I2C | 25 | select SND_SOC_AK4671 if I2C |
25 | select SND_SOC_ALC5623 if I2C | 26 | select SND_SOC_ALC5623 if I2C |
@@ -139,6 +140,9 @@ config SND_SOC_AK4104 | |||
139 | config SND_SOC_AK4535 | 140 | config SND_SOC_AK4535 |
140 | tristate | 141 | tristate |
141 | 142 | ||
143 | config SND_SOC_AK4641 | ||
144 | tristate | ||
145 | |||
142 | config SND_SOC_AK4642 | 146 | config SND_SOC_AK4642 |
143 | tristate | 147 | tristate |
144 | 148 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 4cb2f42dbffa..fd8558406ef0 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -7,6 +7,7 @@ snd-soc-ad73311-objs := ad73311.o | |||
7 | snd-soc-ads117x-objs := ads117x.o | 7 | snd-soc-ads117x-objs := ads117x.o |
8 | snd-soc-ak4104-objs := ak4104.o | 8 | snd-soc-ak4104-objs := ak4104.o |
9 | snd-soc-ak4535-objs := ak4535.o | 9 | snd-soc-ak4535-objs := ak4535.o |
10 | snd-soc-ak4641-objs := ak4641.o | ||
10 | snd-soc-ak4642-objs := ak4642.o | 11 | snd-soc-ak4642-objs := ak4642.o |
11 | snd-soc-ak4671-objs := ak4671.o | 12 | snd-soc-ak4671-objs := ak4671.o |
12 | snd-soc-cq93vc-objs := cq93vc.o | 13 | snd-soc-cq93vc-objs := cq93vc.o |
@@ -97,6 +98,7 @@ obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o | |||
97 | obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o | 98 | obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o |
98 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o | 99 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o |
99 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | 100 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o |
101 | obj-$(CONFIG_SND_SOC_AK4641) += snd-soc-ak4641.o | ||
100 | obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o | 102 | obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o |
101 | obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o | 103 | obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o |
102 | obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o | 104 | obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o |
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c new file mode 100644 index 000000000000..ed96f247c2da --- /dev/null +++ b/sound/soc/codecs/ak4641.c | |||
@@ -0,0 +1,664 @@ | |||
1 | /* | ||
2 | * ak4641.c -- AK4641 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright (C) 2008 Harald Welte <laforge@gnufiish.org> | ||
5 | * Copyright (C) 2011 Dmitry Artamonow <mad_soft@inbox.ru> | ||
6 | * | ||
7 | * Based on ak4535.c by Richard Purdie | ||
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 version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/pm.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <sound/tlv.h> | ||
28 | #include <sound/ak4641.h> | ||
29 | |||
30 | #include "ak4641.h" | ||
31 | |||
32 | /* codec private data */ | ||
33 | struct ak4641_priv { | ||
34 | struct snd_soc_codec *codec; | ||
35 | unsigned int sysclk; | ||
36 | int deemph; | ||
37 | int playback_fs; | ||
38 | }; | ||
39 | |||
40 | /* | ||
41 | * ak4641 register cache | ||
42 | */ | ||
43 | static const u8 ak4641_reg[AK4641_CACHEREGNUM] = { | ||
44 | 0x00, 0x80, 0x00, 0x80, | ||
45 | 0x02, 0x00, 0x11, 0x05, | ||
46 | 0x00, 0x00, 0x36, 0x10, | ||
47 | 0x00, 0x00, 0x57, 0x00, | ||
48 | 0x88, 0x88, 0x08, 0x08 | ||
49 | }; | ||
50 | |||
51 | static const int deemph_settings[] = {44100, 0, 48000, 32000}; | ||
52 | |||
53 | static int ak4641_set_deemph(struct snd_soc_codec *codec) | ||
54 | { | ||
55 | struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); | ||
56 | int i, best = 0; | ||
57 | |||
58 | for (i = 0 ; i < ARRAY_SIZE(deemph_settings); i++) { | ||
59 | /* if deemphasis is on, select the nearest available rate */ | ||
60 | if (ak4641->deemph && deemph_settings[i] != 0 && | ||
61 | abs(deemph_settings[i] - ak4641->playback_fs) < | ||
62 | abs(deemph_settings[best] - ak4641->playback_fs)) | ||
63 | best = i; | ||
64 | |||
65 | if (!ak4641->deemph && deemph_settings[i] == 0) | ||
66 | best = i; | ||
67 | } | ||
68 | |||
69 | dev_dbg(codec->dev, "Set deemphasis %d\n", best); | ||
70 | |||
71 | return snd_soc_update_bits(codec, AK4641_DAC, 0x3, best); | ||
72 | } | ||
73 | |||
74 | static int ak4641_put_deemph(struct snd_kcontrol *kcontrol, | ||
75 | struct snd_ctl_elem_value *ucontrol) | ||
76 | { | ||
77 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
78 | struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); | ||
79 | int deemph = ucontrol->value.enumerated.item[0]; | ||
80 | |||
81 | if (deemph > 1) | ||
82 | return -EINVAL; | ||
83 | |||
84 | ak4641->deemph = deemph; | ||
85 | |||
86 | return ak4641_set_deemph(codec); | ||
87 | } | ||
88 | |||
89 | static int ak4641_get_deemph(struct snd_kcontrol *kcontrol, | ||
90 | struct snd_ctl_elem_value *ucontrol) | ||
91 | { | ||
92 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
93 | struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); | ||
94 | |||
95 | ucontrol->value.enumerated.item[0] = ak4641->deemph; | ||
96 | return 0; | ||
97 | }; | ||
98 | |||
99 | static const char *ak4641_mono_out[] = {"(L + R)/2", "Hi-Z"}; | ||
100 | static const char *ak4641_hp_out[] = {"Stereo", "Mono"}; | ||
101 | static const char *ak4641_mic_select[] = {"Internal", "External"}; | ||
102 | static const char *ak4641_mic_or_dac[] = {"Microphone", "Voice DAC"}; | ||
103 | |||
104 | |||
105 | static const DECLARE_TLV_DB_SCALE(mono_gain_tlv, -1700, 2300, 0); | ||
106 | static const DECLARE_TLV_DB_SCALE(mic_boost_tlv, 0, 2000, 0); | ||
107 | static const DECLARE_TLV_DB_SCALE(eq_tlv, -1050, 150, 0); | ||
108 | static const DECLARE_TLV_DB_SCALE(master_tlv, -12750, 50, 0); | ||
109 | static const DECLARE_TLV_DB_SCALE(mic_stereo_sidetone_tlv, -2700, 300, 0); | ||
110 | static const DECLARE_TLV_DB_SCALE(mic_mono_sidetone_tlv, -400, 400, 0); | ||
111 | static const DECLARE_TLV_DB_SCALE(capture_tlv, -800, 50, 0); | ||
112 | static const DECLARE_TLV_DB_SCALE(alc_tlv, -800, 50, 0); | ||
113 | static const DECLARE_TLV_DB_SCALE(aux_in_tlv, -2100, 300, 0); | ||
114 | |||
115 | |||
116 | static const struct soc_enum ak4641_mono_out_enum = | ||
117 | SOC_ENUM_SINGLE(AK4641_SIG1, 6, 2, ak4641_mono_out); | ||
118 | static const struct soc_enum ak4641_hp_out_enum = | ||
119 | SOC_ENUM_SINGLE(AK4641_MODE2, 2, 2, ak4641_hp_out); | ||
120 | static const struct soc_enum ak4641_mic_select_enum = | ||
121 | SOC_ENUM_SINGLE(AK4641_MIC, 1, 2, ak4641_mic_select); | ||
122 | static const struct soc_enum ak4641_mic_or_dac_enum = | ||
123 | SOC_ENUM_SINGLE(AK4641_BTIF, 4, 2, ak4641_mic_or_dac); | ||
124 | |||
125 | static const struct snd_kcontrol_new ak4641_snd_controls[] = { | ||
126 | SOC_ENUM("Mono 1 Output", ak4641_mono_out_enum), | ||
127 | SOC_SINGLE_TLV("Mono 1 Gain Volume", AK4641_SIG1, 7, 1, 1, | ||
128 | mono_gain_tlv), | ||
129 | SOC_ENUM("Headphone Output", ak4641_hp_out_enum), | ||
130 | SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0, | ||
131 | ak4641_get_deemph, ak4641_put_deemph), | ||
132 | |||
133 | SOC_SINGLE_TLV("Mic Boost Volume", AK4641_MIC, 0, 1, 0, mic_boost_tlv), | ||
134 | |||
135 | SOC_SINGLE("ALC Operation Time", AK4641_TIMER, 0, 3, 0), | ||
136 | SOC_SINGLE("ALC Recovery Time", AK4641_TIMER, 2, 3, 0), | ||
137 | SOC_SINGLE("ALC ZC Time", AK4641_TIMER, 4, 3, 0), | ||
138 | |||
139 | SOC_SINGLE("ALC 1 Switch", AK4641_ALC1, 5, 1, 0), | ||
140 | |||
141 | SOC_SINGLE_TLV("ALC Volume", AK4641_ALC2, 0, 71, 0, alc_tlv), | ||
142 | SOC_SINGLE("Left Out Enable Switch", AK4641_SIG2, 1, 1, 0), | ||
143 | SOC_SINGLE("Right Out Enable Switch", AK4641_SIG2, 0, 1, 0), | ||
144 | |||
145 | SOC_SINGLE_TLV("Capture Volume", AK4641_PGA, 0, 71, 0, capture_tlv), | ||
146 | |||
147 | SOC_DOUBLE_R_TLV("Master Playback Volume", AK4641_LATT, | ||
148 | AK4641_RATT, 0, 255, 1, master_tlv), | ||
149 | |||
150 | SOC_SINGLE_TLV("AUX In Volume", AK4641_VOL, 0, 15, 0, aux_in_tlv), | ||
151 | |||
152 | SOC_SINGLE("Equalizer Switch", AK4641_DAC, 2, 1, 0), | ||
153 | SOC_SINGLE_TLV("EQ1 100 Hz Volume", AK4641_EQLO, 0, 15, 1, eq_tlv), | ||
154 | SOC_SINGLE_TLV("EQ2 250 Hz Volume", AK4641_EQLO, 4, 15, 1, eq_tlv), | ||
155 | SOC_SINGLE_TLV("EQ3 1 kHz Volume", AK4641_EQMID, 0, 15, 1, eq_tlv), | ||
156 | SOC_SINGLE_TLV("EQ4 3.5 kHz Volume", AK4641_EQMID, 4, 15, 1, eq_tlv), | ||
157 | SOC_SINGLE_TLV("EQ5 10 kHz Volume", AK4641_EQHI, 0, 15, 1, eq_tlv), | ||
158 | }; | ||
159 | |||
160 | /* Mono 1 Mixer */ | ||
161 | static const struct snd_kcontrol_new ak4641_mono1_mixer_controls[] = { | ||
162 | SOC_DAPM_SINGLE_TLV("Mic Mono Sidetone Volume", AK4641_VOL, 7, 1, 0, | ||
163 | mic_mono_sidetone_tlv), | ||
164 | SOC_DAPM_SINGLE("Mic Mono Sidetone Switch", AK4641_SIG1, 4, 1, 0), | ||
165 | SOC_DAPM_SINGLE("Mono Playback Switch", AK4641_SIG1, 5, 1, 0), | ||
166 | }; | ||
167 | |||
168 | /* Stereo Mixer */ | ||
169 | static const struct snd_kcontrol_new ak4641_stereo_mixer_controls[] = { | ||
170 | SOC_DAPM_SINGLE_TLV("Mic Sidetone Volume", AK4641_VOL, 4, 7, 0, | ||
171 | mic_stereo_sidetone_tlv), | ||
172 | SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4641_SIG2, 4, 1, 0), | ||
173 | SOC_DAPM_SINGLE("Playback Switch", AK4641_SIG2, 7, 1, 0), | ||
174 | SOC_DAPM_SINGLE("Aux Bypass Switch", AK4641_SIG2, 5, 1, 0), | ||
175 | }; | ||
176 | |||
177 | /* Input Mixer */ | ||
178 | static const struct snd_kcontrol_new ak4641_input_mixer_controls[] = { | ||
179 | SOC_DAPM_SINGLE("Mic Capture Switch", AK4641_MIC, 2, 1, 0), | ||
180 | SOC_DAPM_SINGLE("Aux Capture Switch", AK4641_MIC, 5, 1, 0), | ||
181 | }; | ||
182 | |||
183 | /* Mic mux */ | ||
184 | static const struct snd_kcontrol_new ak4641_mic_mux_control = | ||
185 | SOC_DAPM_ENUM("Mic Select", ak4641_mic_select_enum); | ||
186 | |||
187 | /* Input mux */ | ||
188 | static const struct snd_kcontrol_new ak4641_input_mux_control = | ||
189 | SOC_DAPM_ENUM("Input Select", ak4641_mic_or_dac_enum); | ||
190 | |||
191 | /* mono 2 switch */ | ||
192 | static const struct snd_kcontrol_new ak4641_mono2_control = | ||
193 | SOC_DAPM_SINGLE("Switch", AK4641_SIG1, 0, 1, 0); | ||
194 | |||
195 | /* ak4641 dapm widgets */ | ||
196 | static const struct snd_soc_dapm_widget ak4641_dapm_widgets[] = { | ||
197 | SND_SOC_DAPM_MIXER("Stereo Mixer", SND_SOC_NOPM, 0, 0, | ||
198 | &ak4641_stereo_mixer_controls[0], | ||
199 | ARRAY_SIZE(ak4641_stereo_mixer_controls)), | ||
200 | SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0, | ||
201 | &ak4641_mono1_mixer_controls[0], | ||
202 | ARRAY_SIZE(ak4641_mono1_mixer_controls)), | ||
203 | SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, | ||
204 | &ak4641_input_mixer_controls[0], | ||
205 | ARRAY_SIZE(ak4641_input_mixer_controls)), | ||
206 | SND_SOC_DAPM_MUX("Mic Mux", SND_SOC_NOPM, 0, 0, | ||
207 | &ak4641_mic_mux_control), | ||
208 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, | ||
209 | &ak4641_input_mux_control), | ||
210 | SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0, | ||
211 | &ak4641_mono2_control), | ||
212 | |||
213 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
214 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
215 | SND_SOC_DAPM_OUTPUT("MOUT1"), | ||
216 | SND_SOC_DAPM_OUTPUT("MOUT2"), | ||
217 | SND_SOC_DAPM_OUTPUT("MICOUT"), | ||
218 | |||
219 | SND_SOC_DAPM_ADC("ADC", "HiFi Capture", AK4641_PM1, 0, 0), | ||
220 | SND_SOC_DAPM_PGA("Mic", AK4641_PM1, 1, 0, NULL, 0), | ||
221 | SND_SOC_DAPM_PGA("AUX In", AK4641_PM1, 2, 0, NULL, 0), | ||
222 | SND_SOC_DAPM_PGA("Mono Out", AK4641_PM1, 3, 0, NULL, 0), | ||
223 | SND_SOC_DAPM_PGA("Line Out", AK4641_PM1, 4, 0, NULL, 0), | ||
224 | |||
225 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", AK4641_PM2, 0, 0), | ||
226 | SND_SOC_DAPM_PGA("Mono Out 2", AK4641_PM2, 3, 0, NULL, 0), | ||
227 | |||
228 | SND_SOC_DAPM_ADC("Voice ADC", "Voice Capture", AK4641_BTIF, 0, 0), | ||
229 | SND_SOC_DAPM_ADC("Voice DAC", "Voice Playback", AK4641_BTIF, 1, 0), | ||
230 | |||
231 | SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4641_MIC, 3, 0), | ||
232 | SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4641_MIC, 4, 0), | ||
233 | |||
234 | SND_SOC_DAPM_INPUT("MICIN"), | ||
235 | SND_SOC_DAPM_INPUT("MICEXT"), | ||
236 | SND_SOC_DAPM_INPUT("AUX"), | ||
237 | SND_SOC_DAPM_INPUT("AIN"), | ||
238 | }; | ||
239 | |||
240 | static const struct snd_soc_dapm_route ak4641_audio_map[] = { | ||
241 | /* Stereo Mixer */ | ||
242 | {"Stereo Mixer", "Playback Switch", "DAC"}, | ||
243 | {"Stereo Mixer", "Mic Sidetone Switch", "Input Mux"}, | ||
244 | {"Stereo Mixer", "Aux Bypass Switch", "AUX In"}, | ||
245 | |||
246 | /* Mono 1 Mixer */ | ||
247 | {"Mono1 Mixer", "Mic Mono Sidetone Switch", "Input Mux"}, | ||
248 | {"Mono1 Mixer", "Mono Playback Switch", "DAC"}, | ||
249 | |||
250 | /* Mic */ | ||
251 | {"Mic", NULL, "AIN"}, | ||
252 | {"Mic Mux", "Internal", "Mic Int Bias"}, | ||
253 | {"Mic Mux", "External", "Mic Ext Bias"}, | ||
254 | {"Mic Int Bias", NULL, "MICIN"}, | ||
255 | {"Mic Ext Bias", NULL, "MICEXT"}, | ||
256 | {"MICOUT", NULL, "Mic Mux"}, | ||
257 | |||
258 | /* Input Mux */ | ||
259 | {"Input Mux", "Microphone", "Mic"}, | ||
260 | {"Input Mux", "Voice DAC", "Voice DAC"}, | ||
261 | |||
262 | /* Line Out */ | ||
263 | {"LOUT", NULL, "Line Out"}, | ||
264 | {"ROUT", NULL, "Line Out"}, | ||
265 | {"Line Out", NULL, "Stereo Mixer"}, | ||
266 | |||
267 | /* Mono 1 Out */ | ||
268 | {"MOUT1", NULL, "Mono Out"}, | ||
269 | {"Mono Out", NULL, "Mono1 Mixer"}, | ||
270 | |||
271 | /* Mono 2 Out */ | ||
272 | {"MOUT2", NULL, "Mono 2 Enable"}, | ||
273 | {"Mono 2 Enable", "Switch", "Mono Out 2"}, | ||
274 | {"Mono Out 2", NULL, "Stereo Mixer"}, | ||
275 | |||
276 | {"Voice ADC", NULL, "Mono 2 Enable"}, | ||
277 | |||
278 | /* Aux In */ | ||
279 | {"AUX In", NULL, "AUX"}, | ||
280 | |||
281 | /* ADC */ | ||
282 | {"ADC", NULL, "Input Mixer"}, | ||
283 | {"Input Mixer", "Mic Capture Switch", "Mic"}, | ||
284 | {"Input Mixer", "Aux Capture Switch", "AUX In"}, | ||
285 | }; | ||
286 | |||
287 | static int ak4641_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
288 | int clk_id, unsigned int freq, int dir) | ||
289 | { | ||
290 | struct snd_soc_codec *codec = codec_dai->codec; | ||
291 | struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); | ||
292 | |||
293 | ak4641->sysclk = freq; | ||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int ak4641_i2s_hw_params(struct snd_pcm_substream *substream, | ||
298 | struct snd_pcm_hw_params *params, | ||
299 | struct snd_soc_dai *dai) | ||
300 | { | ||
301 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
302 | struct snd_soc_codec *codec = rtd->codec; | ||
303 | struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec); | ||
304 | int rate = params_rate(params), fs = 256; | ||
305 | u8 mode2; | ||
306 | |||
307 | if (rate) | ||
308 | fs = ak4641->sysclk / rate; | ||
309 | else | ||
310 | return -EINVAL; | ||
311 | |||
312 | /* set fs */ | ||
313 | switch (fs) { | ||
314 | case 1024: | ||
315 | mode2 = (0x2 << 5); | ||
316 | break; | ||
317 | case 512: | ||
318 | mode2 = (0x1 << 5); | ||
319 | break; | ||
320 | case 256: | ||
321 | mode2 = (0x0 << 5); | ||
322 | break; | ||
323 | default: | ||
324 | dev_err(codec->dev, "Error: unsupported fs=%d\n", fs); | ||
325 | return -EINVAL; | ||
326 | } | ||
327 | |||
328 | snd_soc_update_bits(codec, AK4641_MODE2, (0x3 << 5), mode2); | ||
329 | |||
330 | /* Update de-emphasis filter for the new rate */ | ||
331 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
332 | ak4641->playback_fs = rate; | ||
333 | ak4641_set_deemph(codec); | ||
334 | }; | ||
335 | |||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | static int ak4641_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
340 | unsigned int fmt) | ||
341 | { | ||
342 | struct snd_soc_codec *codec = codec_dai->codec; | ||
343 | u8 btif; | ||
344 | |||
345 | /* interface format */ | ||
346 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
347 | case SND_SOC_DAIFMT_I2S: | ||
348 | btif = (0x3 << 5); | ||
349 | break; | ||
350 | case SND_SOC_DAIFMT_LEFT_J: | ||
351 | btif = (0x2 << 5); | ||
352 | break; | ||
353 | case SND_SOC_DAIFMT_DSP_A: /* MSB after FRM */ | ||
354 | btif = (0x0 << 5); | ||
355 | break; | ||
356 | case SND_SOC_DAIFMT_DSP_B: /* MSB during FRM */ | ||
357 | btif = (0x1 << 5); | ||
358 | break; | ||
359 | default: | ||
360 | return -EINVAL; | ||
361 | } | ||
362 | |||
363 | return snd_soc_update_bits(codec, AK4641_BTIF, (0x3 << 5), btif); | ||
364 | } | ||
365 | |||
366 | static int ak4641_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
367 | unsigned int fmt) | ||
368 | { | ||
369 | struct snd_soc_codec *codec = codec_dai->codec; | ||
370 | u8 mode1 = 0; | ||
371 | |||
372 | /* interface format */ | ||
373 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
374 | case SND_SOC_DAIFMT_I2S: | ||
375 | mode1 = 0x02; | ||
376 | break; | ||
377 | case SND_SOC_DAIFMT_LEFT_J: | ||
378 | mode1 = 0x01; | ||
379 | break; | ||
380 | default: | ||
381 | return -EINVAL; | ||
382 | } | ||
383 | |||
384 | return snd_soc_write(codec, AK4641_MODE1, mode1); | ||
385 | } | ||
386 | |||
387 | static int ak4641_mute(struct snd_soc_dai *dai, int mute) | ||
388 | { | ||
389 | struct snd_soc_codec *codec = dai->codec; | ||
390 | |||
391 | return snd_soc_update_bits(codec, AK4641_DAC, 0x20, mute ? 0x20 : 0); | ||
392 | } | ||
393 | |||
394 | static int ak4641_set_bias_level(struct snd_soc_codec *codec, | ||
395 | enum snd_soc_bias_level level) | ||
396 | { | ||
397 | struct ak4641_platform_data *pdata = codec->dev->platform_data; | ||
398 | int ret; | ||
399 | |||
400 | switch (level) { | ||
401 | case SND_SOC_BIAS_ON: | ||
402 | /* unmute */ | ||
403 | snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0); | ||
404 | break; | ||
405 | case SND_SOC_BIAS_PREPARE: | ||
406 | /* mute */ | ||
407 | snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0x20); | ||
408 | break; | ||
409 | case SND_SOC_BIAS_STANDBY: | ||
410 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | ||
411 | if (pdata && gpio_is_valid(pdata->gpio_power)) | ||
412 | gpio_set_value(pdata->gpio_power, 1); | ||
413 | mdelay(1); | ||
414 | if (pdata && gpio_is_valid(pdata->gpio_npdn)) | ||
415 | gpio_set_value(pdata->gpio_npdn, 1); | ||
416 | mdelay(1); | ||
417 | |||
418 | ret = snd_soc_cache_sync(codec); | ||
419 | if (ret) { | ||
420 | dev_err(codec->dev, | ||
421 | "Failed to sync cache: %d\n", ret); | ||
422 | return ret; | ||
423 | } | ||
424 | } | ||
425 | snd_soc_update_bits(codec, AK4641_PM1, 0x80, 0x80); | ||
426 | snd_soc_update_bits(codec, AK4641_PM2, 0x80, 0); | ||
427 | break; | ||
428 | case SND_SOC_BIAS_OFF: | ||
429 | snd_soc_update_bits(codec, AK4641_PM1, 0x80, 0); | ||
430 | if (pdata && gpio_is_valid(pdata->gpio_npdn)) | ||
431 | gpio_set_value(pdata->gpio_npdn, 0); | ||
432 | if (pdata && gpio_is_valid(pdata->gpio_power)) | ||
433 | gpio_set_value(pdata->gpio_power, 0); | ||
434 | codec->cache_sync = 1; | ||
435 | break; | ||
436 | } | ||
437 | codec->dapm.bias_level = level; | ||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | #define AK4641_RATES (SNDRV_PCM_RATE_8000_48000) | ||
442 | #define AK4641_RATES_BT (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
443 | SNDRV_PCM_RATE_16000) | ||
444 | #define AK4641_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) | ||
445 | |||
446 | static struct snd_soc_dai_ops ak4641_i2s_dai_ops = { | ||
447 | .hw_params = ak4641_i2s_hw_params, | ||
448 | .set_fmt = ak4641_i2s_set_dai_fmt, | ||
449 | .digital_mute = ak4641_mute, | ||
450 | .set_sysclk = ak4641_set_dai_sysclk, | ||
451 | }; | ||
452 | |||
453 | static struct snd_soc_dai_ops ak4641_pcm_dai_ops = { | ||
454 | .hw_params = NULL, /* rates are controlled by BT chip */ | ||
455 | .set_fmt = ak4641_pcm_set_dai_fmt, | ||
456 | .digital_mute = ak4641_mute, | ||
457 | .set_sysclk = ak4641_set_dai_sysclk, | ||
458 | }; | ||
459 | |||
460 | struct snd_soc_dai_driver ak4641_dai[] = { | ||
461 | { | ||
462 | .name = "ak4641-hifi", | ||
463 | .id = 1, | ||
464 | .playback = { | ||
465 | .stream_name = "HiFi Playback", | ||
466 | .channels_min = 1, | ||
467 | .channels_max = 2, | ||
468 | .rates = AK4641_RATES, | ||
469 | .formats = AK4641_FORMATS, | ||
470 | }, | ||
471 | .capture = { | ||
472 | .stream_name = "HiFi Capture", | ||
473 | .channels_min = 1, | ||
474 | .channels_max = 2, | ||
475 | .rates = AK4641_RATES, | ||
476 | .formats = AK4641_FORMATS, | ||
477 | }, | ||
478 | .ops = &ak4641_i2s_dai_ops, | ||
479 | .symmetric_rates = 1, | ||
480 | }, | ||
481 | { | ||
482 | .name = "ak4641-voice", | ||
483 | .id = 1, | ||
484 | .playback = { | ||
485 | .stream_name = "Voice Playback", | ||
486 | .channels_min = 1, | ||
487 | .channels_max = 1, | ||
488 | .rates = AK4641_RATES_BT, | ||
489 | .formats = AK4641_FORMATS, | ||
490 | }, | ||
491 | .capture = { | ||
492 | .stream_name = "Voice Capture", | ||
493 | .channels_min = 1, | ||
494 | .channels_max = 1, | ||
495 | .rates = AK4641_RATES_BT, | ||
496 | .formats = AK4641_FORMATS, | ||
497 | }, | ||
498 | .ops = &ak4641_pcm_dai_ops, | ||
499 | .symmetric_rates = 1, | ||
500 | }, | ||
501 | }; | ||
502 | |||
503 | static int ak4641_suspend(struct snd_soc_codec *codec, pm_message_t state) | ||
504 | { | ||
505 | ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | static int ak4641_resume(struct snd_soc_codec *codec) | ||
510 | { | ||
511 | ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | static int ak4641_probe(struct snd_soc_codec *codec) | ||
516 | { | ||
517 | struct ak4641_platform_data *pdata = codec->dev->platform_data; | ||
518 | int ret; | ||
519 | |||
520 | |||
521 | if (pdata) { | ||
522 | if (gpio_is_valid(pdata->gpio_power)) { | ||
523 | ret = gpio_request_one(pdata->gpio_power, | ||
524 | GPIOF_OUT_INIT_LOW, "ak4641 power"); | ||
525 | if (ret) | ||
526 | goto err_out; | ||
527 | } | ||
528 | if (gpio_is_valid(pdata->gpio_npdn)) { | ||
529 | ret = gpio_request_one(pdata->gpio_npdn, | ||
530 | GPIOF_OUT_INIT_LOW, "ak4641 npdn"); | ||
531 | if (ret) | ||
532 | goto err_gpio; | ||
533 | |||
534 | udelay(1); /* > 150 ns */ | ||
535 | gpio_set_value(pdata->gpio_npdn, 1); | ||
536 | } | ||
537 | } | ||
538 | |||
539 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); | ||
540 | if (ret != 0) { | ||
541 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
542 | goto err_register; | ||
543 | } | ||
544 | |||
545 | /* power on device */ | ||
546 | ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
547 | |||
548 | return 0; | ||
549 | |||
550 | err_register: | ||
551 | if (pdata) { | ||
552 | if (gpio_is_valid(pdata->gpio_power)) | ||
553 | gpio_set_value(pdata->gpio_power, 0); | ||
554 | if (gpio_is_valid(pdata->gpio_npdn)) | ||
555 | gpio_free(pdata->gpio_npdn); | ||
556 | } | ||
557 | err_gpio: | ||
558 | if (pdata && gpio_is_valid(pdata->gpio_power)) | ||
559 | gpio_free(pdata->gpio_power); | ||
560 | err_out: | ||
561 | return ret; | ||
562 | } | ||
563 | |||
564 | static int ak4641_remove(struct snd_soc_codec *codec) | ||
565 | { | ||
566 | struct ak4641_platform_data *pdata = codec->dev->platform_data; | ||
567 | |||
568 | ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
569 | |||
570 | if (pdata) { | ||
571 | if (gpio_is_valid(pdata->gpio_power)) { | ||
572 | gpio_set_value(pdata->gpio_power, 0); | ||
573 | gpio_free(pdata->gpio_power); | ||
574 | } | ||
575 | if (gpio_is_valid(pdata->gpio_npdn)) | ||
576 | gpio_free(pdata->gpio_npdn); | ||
577 | } | ||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | |||
582 | static struct snd_soc_codec_driver soc_codec_dev_ak4641 = { | ||
583 | .probe = ak4641_probe, | ||
584 | .remove = ak4641_remove, | ||
585 | .suspend = ak4641_suspend, | ||
586 | .resume = ak4641_resume, | ||
587 | .controls = ak4641_snd_controls, | ||
588 | .num_controls = ARRAY_SIZE(ak4641_snd_controls), | ||
589 | .dapm_widgets = ak4641_dapm_widgets, | ||
590 | .num_dapm_widgets = ARRAY_SIZE(ak4641_dapm_widgets), | ||
591 | .dapm_routes = ak4641_audio_map, | ||
592 | .num_dapm_routes = ARRAY_SIZE(ak4641_audio_map), | ||
593 | .set_bias_level = ak4641_set_bias_level, | ||
594 | .reg_cache_size = ARRAY_SIZE(ak4641_reg), | ||
595 | .reg_word_size = sizeof(u8), | ||
596 | .reg_cache_default = ak4641_reg, | ||
597 | .reg_cache_step = 1, | ||
598 | }; | ||
599 | |||
600 | |||
601 | static int __devinit ak4641_i2c_probe(struct i2c_client *i2c, | ||
602 | const struct i2c_device_id *id) | ||
603 | { | ||
604 | struct ak4641_priv *ak4641; | ||
605 | int ret; | ||
606 | |||
607 | ak4641 = kzalloc(sizeof(struct ak4641_priv), GFP_KERNEL); | ||
608 | if (!ak4641) | ||
609 | return -ENOMEM; | ||
610 | |||
611 | i2c_set_clientdata(i2c, ak4641); | ||
612 | |||
613 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ak4641, | ||
614 | ak4641_dai, ARRAY_SIZE(ak4641_dai)); | ||
615 | if (ret < 0) | ||
616 | kfree(ak4641); | ||
617 | |||
618 | return ret; | ||
619 | } | ||
620 | |||
621 | static int __devexit ak4641_i2c_remove(struct i2c_client *i2c) | ||
622 | { | ||
623 | snd_soc_unregister_codec(&i2c->dev); | ||
624 | kfree(i2c_get_clientdata(i2c)); | ||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | static const struct i2c_device_id ak4641_i2c_id[] = { | ||
629 | { "ak4641", 0 }, | ||
630 | { } | ||
631 | }; | ||
632 | MODULE_DEVICE_TABLE(i2c, ak4641_i2c_id); | ||
633 | |||
634 | static struct i2c_driver ak4641_i2c_driver = { | ||
635 | .driver = { | ||
636 | .name = "ak4641", | ||
637 | .owner = THIS_MODULE, | ||
638 | }, | ||
639 | .probe = ak4641_i2c_probe, | ||
640 | .remove = __devexit_p(ak4641_i2c_remove), | ||
641 | .id_table = ak4641_i2c_id, | ||
642 | }; | ||
643 | |||
644 | static int __init ak4641_modinit(void) | ||
645 | { | ||
646 | int ret; | ||
647 | |||
648 | ret = i2c_add_driver(&ak4641_i2c_driver); | ||
649 | if (ret != 0) | ||
650 | pr_err("Failed to register AK4641 I2C driver: %d\n", ret); | ||
651 | |||
652 | return ret; | ||
653 | } | ||
654 | module_init(ak4641_modinit); | ||
655 | |||
656 | static void __exit ak4641_exit(void) | ||
657 | { | ||
658 | i2c_del_driver(&ak4641_i2c_driver); | ||
659 | } | ||
660 | module_exit(ak4641_exit); | ||
661 | |||
662 | MODULE_DESCRIPTION("SoC AK4641 driver"); | ||
663 | MODULE_AUTHOR("Harald Welte <laforge@gnufiish.org>"); | ||
664 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ak4641.h b/sound/soc/codecs/ak4641.h new file mode 100644 index 000000000000..4a263248efea --- /dev/null +++ b/sound/soc/codecs/ak4641.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * ak4641.h -- AK4641 SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2008 Harald Welte <laforge@gnufiish.org> | ||
5 | * | ||
6 | * Based on ak4535.h | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef _AK4641_H | ||
14 | #define _AK4641_H | ||
15 | |||
16 | /* AK4641 register space */ | ||
17 | |||
18 | #define AK4641_PM1 0x00 | ||
19 | #define AK4641_PM2 0x01 | ||
20 | #define AK4641_SIG1 0x02 | ||
21 | #define AK4641_SIG2 0x03 | ||
22 | #define AK4641_MODE1 0x04 | ||
23 | #define AK4641_MODE2 0x05 | ||
24 | #define AK4641_DAC 0x06 | ||
25 | #define AK4641_MIC 0x07 | ||
26 | #define AK4641_TIMER 0x08 | ||
27 | #define AK4641_ALC1 0x09 | ||
28 | #define AK4641_ALC2 0x0a | ||
29 | #define AK4641_PGA 0x0b | ||
30 | #define AK4641_LATT 0x0c | ||
31 | #define AK4641_RATT 0x0d | ||
32 | #define AK4641_VOL 0x0e | ||
33 | #define AK4641_STATUS 0x0f | ||
34 | #define AK4641_EQLO 0x10 | ||
35 | #define AK4641_EQMID 0x11 | ||
36 | #define AK4641_EQHI 0x12 | ||
37 | #define AK4641_BTIF 0x13 | ||
38 | |||
39 | #define AK4641_CACHEREGNUM 0x14 | ||
40 | |||
41 | |||
42 | |||
43 | #define AK4641_DAI_HIFI 0 | ||
44 | #define AK4641_DAI_VOICE 1 | ||
45 | |||
46 | |||
47 | #endif | ||