aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRongjun Ying <rongjun.ying@csr.com>2014-03-05 03:34:34 -0500
committerMark Brown <broonie@linaro.org>2014-03-06 02:59:19 -0500
commitf516e368dcb5eb5fbe23246c09bf69573d67cd18 (patch)
tree94780f5f04dc098de366adf41506214ac659ec9e
parent38dbfb59d1175ef458d006556061adeaa8751b72 (diff)
ASoC: sirf: Add SiRF internal audio codec driver
SiRF internal audio codec is integrated in SiRF atlas6 and prima2 SoC. Features include: 1. Stereo DAC and ADC with 16-bit resolution amd 48KHz sample rate 2. Support headphone and/or speaker output 3. Integrate headphone and speaker output amp 4. Support LINE and MIC input 5. Support single ended and differential input mode Signed-off-by: Rongjun Ying <rongjun.ying@csr.com> --v5: 1. Drop all inlines. 2. Reordering the Kconfig and Makefile 3. Remove the sirf_audio_codec_reg_bits struct, use the new controls instead it. 4. Add some SND_SOC_DAPM_OUT_DRV instead of HP and SPK enable driver 5. Add audio codec clock supply instead of adc event callback 6. Fixed playback and capture can't concurrent work bug. -- .../devicetree/bindings/sound/sirf-audio-codec.txt | 17 + sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 1 + sound/soc/codecs/sirf-audio-codec.c | 533 ++++++++++++++++++++ sound/soc/codecs/sirf-audio-codec.h | 75 +++ 5 files changed, 631 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/sirf-audio-codec.txt create mode 100644 sound/soc/codecs/sirf-audio-codec.c create mode 100644 sound/soc/codecs/sirf-audio-codec.h Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r--Documentation/devicetree/bindings/sound/sirf-audio-codec.txt17
-rw-r--r--sound/soc/codecs/Kconfig5
-rw-r--r--sound/soc/codecs/Makefile1
-rw-r--r--sound/soc/codecs/sirf-audio-codec.c533
-rw-r--r--sound/soc/codecs/sirf-audio-codec.h75
5 files changed, 631 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt b/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt
new file mode 100644
index 000000000000..062f5ec36f9b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt
@@ -0,0 +1,17 @@
1SiRF internal audio CODEC
2
3Required properties:
4
5 - compatible : "sirf,atlas6-audio-codec" or "sirf,prima2-audio-codec"
6
7 - reg : the register address of the device.
8
9 - clocks: the clock of SiRF internal audio codec
10
11Example:
12
13audiocodec: audiocodec@b0040000 {
14 compatible = "sirf,atlas6-audio-codec";
15 reg = <0xb0040000 0x10000>;
16 clocks = <&clks 27>;
17};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 983d087aa92a..bf9b12c1a9c0 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -63,6 +63,7 @@ config SND_SOC_ALL_CODECS
63 select SND_SOC_RT5640 if I2C 63 select SND_SOC_RT5640 if I2C
64 select SND_SOC_SGTL5000 if I2C 64 select SND_SOC_SGTL5000 if I2C
65 select SND_SOC_SI476X if MFD_SI476X_CORE 65 select SND_SOC_SI476X if MFD_SI476X_CORE
66 select SND_SOC_SIRF_AUDIO_CODEC
66 select SND_SOC_SN95031 if INTEL_SCU_IPC 67 select SND_SOC_SN95031 if INTEL_SCU_IPC
67 select SND_SOC_SPDIF 68 select SND_SOC_SPDIF
68 select SND_SOC_SSM2518 if I2C 69 select SND_SOC_SSM2518 if I2C
@@ -330,6 +331,10 @@ config SND_SOC_SIGMADSP
330 tristate 331 tristate
331 select CRC32 332 select CRC32
332 333
334config SND_SOC_SIRF_AUDIO_CODEC
335 tristate "SiRF SoC internal audio codec"
336 select REGMAP_MMIO
337
333config SND_SOC_SN95031 338config SND_SOC_SN95031
334 tristate 339 tristate
335 340
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index bc126764a44d..de6d7f81b5f6 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -53,6 +53,7 @@ snd-soc-alc5623-objs := alc5623.o
53snd-soc-alc5632-objs := alc5632.o 53snd-soc-alc5632-objs := alc5632.o
54snd-soc-sigmadsp-objs := sigmadsp.o 54snd-soc-sigmadsp-objs := sigmadsp.o
55snd-soc-si476x-objs := si476x.o 55snd-soc-si476x-objs := si476x.o
56snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o
56snd-soc-sn95031-objs := sn95031.o 57snd-soc-sn95031-objs := sn95031.o
57snd-soc-spdif-tx-objs := spdif_transmitter.o 58snd-soc-spdif-tx-objs := spdif_transmitter.o
58snd-soc-spdif-rx-objs := spdif_receiver.o 59snd-soc-spdif-rx-objs := spdif_receiver.o
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c
new file mode 100644
index 000000000000..90e3a228bae4
--- /dev/null
+++ b/sound/soc/codecs/sirf-audio-codec.c
@@ -0,0 +1,533 @@
1/*
2 * SiRF audio codec driver
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#include <linux/module.h>
10#include <linux/platform_device.h>
11#include <linux/pm_runtime.h>
12#include <linux/of.h>
13#include <linux/of_device.h>
14#include <linux/clk.h>
15#include <linux/delay.h>
16#include <linux/io.h>
17#include <linux/regmap.h>
18#include <sound/core.h>
19#include <sound/pcm.h>
20#include <sound/pcm_params.h>
21#include <sound/initval.h>
22#include <sound/tlv.h>
23#include <sound/soc.h>
24#include <sound/dmaengine_pcm.h>
25
26#include "sirf-audio-codec.h"
27
28struct sirf_audio_codec {
29 struct clk *clk;
30 struct regmap *regmap;
31 u32 reg_ctrl0, reg_ctrl1;
32};
33
34static const char * const input_mode_mux[] = {"Single-ended",
35 "Differential"};
36
37static const struct soc_enum input_mode_mux_enum =
38 SOC_ENUM_SINGLE(AUDIO_IC_CODEC_CTRL1, 4, 2, input_mode_mux);
39
40static const struct snd_kcontrol_new sirf_audio_codec_input_mode_control =
41 SOC_DAPM_ENUM("Route", input_mode_mux_enum);
42
43static const DECLARE_TLV_DB_SCALE(playback_vol_tlv, -12400, 100, 0);
44static const DECLARE_TLV_DB_SCALE(capture_vol_tlv_prima2, 500, 100, 0);
45static const DECLARE_TLV_DB_RANGE(capture_vol_tlv_atlas6,
46 0, 7, TLV_DB_SCALE_ITEM(-100, 100, 0),
47 0x22, 0x3F, TLV_DB_SCALE_ITEM(700, 100, 0),
48);
49
50static struct snd_kcontrol_new volume_controls_atlas6[] = {
51 SOC_DOUBLE_TLV("Playback Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
52 0x7F, 0, playback_vol_tlv),
53 SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 16, 10,
54 0x3F, 0, capture_vol_tlv_atlas6),
55};
56
57static struct snd_kcontrol_new volume_controls_prima2[] = {
58 SOC_DOUBLE_TLV("Speaker Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
59 0x7F, 0, playback_vol_tlv),
60 SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 15, 10,
61 0x1F, 0, capture_vol_tlv_prima2),
62};
63
64static struct snd_kcontrol_new left_input_path_controls[] = {
65 SOC_DAPM_SINGLE("Line Left Switch", AUDIO_IC_CODEC_CTRL1, 6, 1, 0),
66 SOC_DAPM_SINGLE("Mic Left Switch", AUDIO_IC_CODEC_CTRL1, 3, 1, 0),
67};
68
69static struct snd_kcontrol_new right_input_path_controls[] = {
70 SOC_DAPM_SINGLE("Line Right Switch", AUDIO_IC_CODEC_CTRL1, 5, 1, 0),
71 SOC_DAPM_SINGLE("Mic Right Switch", AUDIO_IC_CODEC_CTRL1, 2, 1, 0),
72};
73
74static struct snd_kcontrol_new left_dac_to_hp_left_amp_switch_control =
75 SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 9, 1, 0);
76
77static struct snd_kcontrol_new left_dac_to_hp_right_amp_switch_control =
78 SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 8, 1, 0);
79
80static struct snd_kcontrol_new right_dac_to_hp_left_amp_switch_control =
81 SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 7, 1, 0);
82
83static struct snd_kcontrol_new right_dac_to_hp_right_amp_switch_control =
84 SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 6, 1, 0);
85
86static struct snd_kcontrol_new left_dac_to_speaker_lineout_switch_control =
87 SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 11, 1, 0);
88
89static struct snd_kcontrol_new right_dac_to_speaker_lineout_switch_control =
90 SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 10, 1, 0);
91
92/* After enable adc, Delay 200ms to avoid pop noise */
93static int adc_enable_delay_event(struct snd_soc_dapm_widget *w,
94 struct snd_kcontrol *kcontrol, int event)
95{
96 switch (event) {
97 case SND_SOC_DAPM_POST_PMU:
98 msleep(200);
99 break;
100 default:
101 break;
102 }
103
104 return 0;
105}
106
107static void enable_and_reset_codec(struct regmap *regmap,
108 u32 codec_enable_bits, u32 codec_reset_bits)
109{
110 regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
111 codec_enable_bits | codec_reset_bits,
112 codec_enable_bits | ~codec_reset_bits);
113 msleep(20);
114 regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
115 codec_reset_bits, codec_reset_bits);
116}
117
118static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
119 struct snd_kcontrol *kcontrol, int event)
120{
121#define ATLAS6_CODEC_ENABLE_BITS (1 << 29)
122#define ATLAS6_CODEC_RESET_BITS (1 << 28)
123 struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev);
124 switch (event) {
125 case SND_SOC_DAPM_PRE_PMU:
126 enable_and_reset_codec(sirf_audio_codec->regmap,
127 ATLAS6_CODEC_ENABLE_BITS, ATLAS6_CODEC_RESET_BITS);
128 break;
129 case SND_SOC_DAPM_POST_PMD:
130 regmap_update_bits(sirf_audio_codec->regmap,
131 AUDIO_IC_CODEC_CTRL1, ATLAS6_CODEC_ENABLE_BITS,
132 ~ATLAS6_CODEC_ENABLE_BITS);
133 break;
134 default:
135 break;
136 }
137
138 return 0;
139}
140
141static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
142 struct snd_kcontrol *kcontrol, int event)
143{
144#define PRIMA2_CODEC_ENABLE_BITS (1 << 27)
145#define PRIMA2_CODEC_RESET_BITS (1 << 26)
146 struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev);
147 switch (event) {
148 case SND_SOC_DAPM_POST_PMU:
149 enable_and_reset_codec(sirf_audio_codec->regmap,
150 PRIMA2_CODEC_ENABLE_BITS, PRIMA2_CODEC_RESET_BITS);
151 break;
152 case SND_SOC_DAPM_POST_PMD:
153 regmap_update_bits(sirf_audio_codec->regmap,
154 AUDIO_IC_CODEC_CTRL1, PRIMA2_CODEC_ENABLE_BITS,
155 ~PRIMA2_CODEC_ENABLE_BITS);
156 break;
157 default:
158 break;
159 }
160
161 return 0;
162}
163
164static const struct snd_soc_dapm_widget atlas6_output_driver_dapm_widgets[] = {
165 SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1,
166 25, 0, NULL, 0),
167 SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1,
168 26, 0, NULL, 0),
169 SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1,
170 27, 0, NULL, 0),
171};
172
173static const struct snd_soc_dapm_widget prima2_output_driver_dapm_widgets[] = {
174 SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1,
175 23, 0, NULL, 0),
176 SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1,
177 24, 0, NULL, 0),
178 SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1,
179 25, 0, NULL, 0),
180};
181
182static const struct snd_soc_dapm_widget atlas6_codec_clock_dapm_widget =
183 SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0,
184 atlas6_codec_enable_and_reset_event,
185 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
186
187static const struct snd_soc_dapm_widget prima2_codec_clock_dapm_widget =
188 SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0,
189 prima2_codec_enable_and_reset_event,
190 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
191
192static const struct snd_soc_dapm_widget sirf_audio_codec_dapm_widgets[] = {
193 SND_SOC_DAPM_DAC("DAC left", NULL, AUDIO_IC_CODEC_CTRL0, 1, 0),
194 SND_SOC_DAPM_DAC("DAC right", NULL, AUDIO_IC_CODEC_CTRL0, 0, 0),
195 SND_SOC_DAPM_SWITCH("Left dac to hp left amp", SND_SOC_NOPM, 0, 0,
196 &left_dac_to_hp_left_amp_switch_control),
197 SND_SOC_DAPM_SWITCH("Left dac to hp right amp", SND_SOC_NOPM, 0, 0,
198 &left_dac_to_hp_right_amp_switch_control),
199 SND_SOC_DAPM_SWITCH("Right dac to hp left amp", SND_SOC_NOPM, 0, 0,
200 &right_dac_to_hp_left_amp_switch_control),
201 SND_SOC_DAPM_SWITCH("Right dac to hp right amp", SND_SOC_NOPM, 0, 0,
202 &right_dac_to_hp_right_amp_switch_control),
203 SND_SOC_DAPM_OUT_DRV("HP amp left driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
204 NULL, 0),
205 SND_SOC_DAPM_OUT_DRV("HP amp right driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
206 NULL, 0),
207
208 SND_SOC_DAPM_SWITCH("Left dac to speaker lineout", SND_SOC_NOPM, 0, 0,
209 &left_dac_to_speaker_lineout_switch_control),
210 SND_SOC_DAPM_SWITCH("Right dac to speaker lineout", SND_SOC_NOPM, 0, 0,
211 &right_dac_to_speaker_lineout_switch_control),
212 SND_SOC_DAPM_OUT_DRV("Speaker amp driver", AUDIO_IC_CODEC_CTRL0, 4, 0,
213 NULL, 0),
214
215 SND_SOC_DAPM_OUTPUT("HPOUTL"),
216 SND_SOC_DAPM_OUTPUT("HPOUTR"),
217 SND_SOC_DAPM_OUTPUT("SPKOUT"),
218
219 SND_SOC_DAPM_ADC_E("ADC left", NULL, AUDIO_IC_CODEC_CTRL1, 8, 0,
220 adc_enable_delay_event, SND_SOC_DAPM_POST_PMU),
221 SND_SOC_DAPM_ADC_E("ADC right", NULL, AUDIO_IC_CODEC_CTRL1, 7, 0,
222 adc_enable_delay_event, SND_SOC_DAPM_POST_PMU),
223 SND_SOC_DAPM_MIXER("Left PGA mixer", AUDIO_IC_CODEC_CTRL1, 1, 0,
224 &left_input_path_controls[0],
225 ARRAY_SIZE(left_input_path_controls)),
226 SND_SOC_DAPM_MIXER("Right PGA mixer", AUDIO_IC_CODEC_CTRL1, 0, 0,
227 &right_input_path_controls[0],
228 ARRAY_SIZE(right_input_path_controls)),
229
230 SND_SOC_DAPM_MUX("Mic input mode mux", SND_SOC_NOPM, 0, 0,
231 &sirf_audio_codec_input_mode_control),
232 SND_SOC_DAPM_MICBIAS("Mic Bias", AUDIO_IC_CODEC_PWR, 3, 0),
233 SND_SOC_DAPM_INPUT("MICIN1"),
234 SND_SOC_DAPM_INPUT("MICIN2"),
235 SND_SOC_DAPM_INPUT("LINEIN1"),
236 SND_SOC_DAPM_INPUT("LINEIN2"),
237
238 SND_SOC_DAPM_SUPPLY("HSL Phase Opposite", AUDIO_IC_CODEC_CTRL0,
239 30, 0, NULL, 0),
240};
241
242static const struct snd_soc_dapm_route sirf_audio_codec_map[] = {
243 {"SPKOUT", NULL, "Speaker Driver"},
244 {"Speaker Driver", NULL, "Speaker amp driver"},
245 {"Speaker amp driver", NULL, "Left dac to speaker lineout"},
246 {"Speaker amp driver", NULL, "Right dac to speaker lineout"},
247 {"Left dac to speaker lineout", "Switch", "DAC left"},
248 {"Right dac to speaker lineout", "Switch", "DAC right"},
249 {"HPOUTL", NULL, "HP Left Driver"},
250 {"HPOUTR", NULL, "HP Right Driver"},
251 {"HP Left Driver", NULL, "HP amp left driver"},
252 {"HP Right Driver", NULL, "HP amp right driver"},
253 {"HP amp left driver", NULL, "Right dac to hp left amp"},
254 {"HP amp right driver", NULL , "Right dac to hp right amp"},
255 {"HP amp left driver", NULL, "Left dac to hp left amp"},
256 {"HP amp right driver", NULL , "Right dac to hp right amp"},
257 {"Right dac to hp left amp", "Switch", "DAC left"},
258 {"Right dac to hp right amp", "Switch", "DAC right"},
259 {"Left dac to hp left amp", "Switch", "DAC left"},
260 {"Left dac to hp right amp", "Switch", "DAC right"},
261 {"DAC left", NULL, "codecclk"},
262 {"DAC right", NULL, "codecclk"},
263 {"DAC left", NULL, "Playback"},
264 {"DAC right", NULL, "Playback"},
265 {"DAC left", NULL, "HSL Phase Opposite"},
266 {"DAC right", NULL, "HSL Phase Opposite"},
267
268 {"Capture", NULL, "ADC left"},
269 {"Capture", NULL, "ADC right"},
270 {"ADC left", NULL, "codecclk"},
271 {"ADC right", NULL, "codecclk"},
272 {"ADC left", NULL, "Left PGA mixer"},
273 {"ADC right", NULL, "Right PGA mixer"},
274 {"Left PGA mixer", "Line Left Switch", "LINEIN2"},
275 {"Right PGA mixer", "Line Right Switch", "LINEIN1"},
276 {"Left PGA mixer", "Mic Left Switch", "MICIN2"},
277 {"Right PGA mixer", "Mic Right Switch", "Mic input mode mux"},
278 {"Mic input mode mux", "Single-ended", "MICIN1"},
279 {"Mic input mode mux", "Differential", "MICIN1"},
280};
281
282static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream,
283 int cmd,
284 struct snd_soc_dai *dai)
285{
286 int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
287 struct snd_soc_codec *codec = dai->codec;
288 u32 val = 0;
289
290 /*
291 * This is a workaround, When stop playback,
292 * need disable HP amp, avoid the current noise.
293 */
294 switch (cmd) {
295 case SNDRV_PCM_TRIGGER_STOP:
296 case SNDRV_PCM_TRIGGER_SUSPEND:
297 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
298 break;
299 case SNDRV_PCM_TRIGGER_START:
300 case SNDRV_PCM_TRIGGER_RESUME:
301 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
302 if (playback)
303 val = IC_HSLEN | IC_HSREN;
304 break;
305 default:
306 return -EINVAL;
307 }
308
309 if (playback)
310 snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0,
311 IC_HSLEN | IC_HSREN, val);
312 return 0;
313}
314
315struct snd_soc_dai_ops sirf_audio_codec_dai_ops = {
316 .trigger = sirf_audio_codec_trigger,
317};
318
319struct snd_soc_dai_driver sirf_audio_codec_dai = {
320 .name = "sirf-audio-codec",
321 .playback = {
322 .stream_name = "Playback",
323 .channels_min = 2,
324 .channels_max = 2,
325 .rates = SNDRV_PCM_RATE_48000,
326 .formats = SNDRV_PCM_FMTBIT_S16_LE,
327 },
328 .capture = {
329 .stream_name = "Capture",
330 .channels_min = 1,
331 .channels_max = 2,
332 .rates = SNDRV_PCM_RATE_48000,
333 .formats = SNDRV_PCM_FMTBIT_S16_LE,
334 },
335 .ops = &sirf_audio_codec_dai_ops,
336};
337
338static int sirf_audio_codec_probe(struct snd_soc_codec *codec)
339{
340 int ret;
341 struct snd_soc_dapm_context *dapm = &codec->dapm;
342 struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
343
344 pm_runtime_enable(codec->dev);
345 codec->control_data = sirf_audio_codec->regmap;
346
347 ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
348 if (ret != 0) {
349 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
350 return ret;
351 }
352
353 if (of_device_is_compatible(codec->dev->of_node, "sirf,prima2-audio-codec")) {
354 snd_soc_dapm_new_controls(dapm,
355 prima2_output_driver_dapm_widgets,
356 ARRAY_SIZE(prima2_output_driver_dapm_widgets));
357 snd_soc_dapm_new_controls(dapm,
358 &prima2_codec_clock_dapm_widget, 1);
359 return snd_soc_add_codec_controls(codec,
360 volume_controls_prima2,
361 ARRAY_SIZE(volume_controls_prima2));
362 }
363 if (of_device_is_compatible(codec->dev->of_node, "sirf,atlas6-audio-codec")) {
364 snd_soc_dapm_new_controls(dapm,
365 atlas6_output_driver_dapm_widgets,
366 ARRAY_SIZE(atlas6_output_driver_dapm_widgets));
367 snd_soc_dapm_new_controls(dapm,
368 &atlas6_codec_clock_dapm_widget, 1);
369 return snd_soc_add_codec_controls(codec,
370 volume_controls_atlas6,
371 ARRAY_SIZE(volume_controls_atlas6));
372 }
373
374 return -EINVAL;
375}
376
377static int sirf_audio_codec_remove(struct snd_soc_codec *codec)
378{
379 pm_runtime_disable(codec->dev);
380 return 0;
381}
382
383static struct snd_soc_codec_driver soc_codec_device_sirf_audio_codec = {
384 .probe = sirf_audio_codec_probe,
385 .remove = sirf_audio_codec_remove,
386 .dapm_widgets = sirf_audio_codec_dapm_widgets,
387 .num_dapm_widgets = ARRAY_SIZE(sirf_audio_codec_dapm_widgets),
388 .dapm_routes = sirf_audio_codec_map,
389 .num_dapm_routes = ARRAY_SIZE(sirf_audio_codec_map),
390 .idle_bias_off = true,
391};
392
393static const struct of_device_id sirf_audio_codec_of_match[] = {
394 { .compatible = "sirf,prima2-audio-codec" },
395 { .compatible = "sirf,atlas6-audio-codec" },
396 {}
397};
398MODULE_DEVICE_TABLE(of, sirf_audio_codec_of_match);
399
400static const struct regmap_config sirf_audio_codec_regmap_config = {
401 .reg_bits = 32,
402 .reg_stride = 4,
403 .val_bits = 32,
404 .max_register = AUDIO_IC_CODEC_CTRL3,
405 .cache_type = REGCACHE_NONE,
406};
407
408static int sirf_audio_codec_driver_probe(struct platform_device *pdev)
409{
410 int ret;
411 struct sirf_audio_codec *sirf_audio_codec;
412 void __iomem *base;
413 struct resource *mem_res;
414 const struct of_device_id *match;
415
416 match = of_match_node(sirf_audio_codec_of_match, pdev->dev.of_node);
417
418 sirf_audio_codec = devm_kzalloc(&pdev->dev,
419 sizeof(struct sirf_audio_codec), GFP_KERNEL);
420 if (!sirf_audio_codec)
421 return -ENOMEM;
422
423 platform_set_drvdata(pdev, sirf_audio_codec);
424
425 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
426 base = devm_ioremap_resource(&pdev->dev, mem_res);
427 if (base == NULL)
428 return -ENOMEM;
429
430 sirf_audio_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
431 &sirf_audio_codec_regmap_config);
432 if (IS_ERR(sirf_audio_codec->regmap))
433 return PTR_ERR(sirf_audio_codec->regmap);
434
435 sirf_audio_codec->clk = devm_clk_get(&pdev->dev, NULL);
436 if (IS_ERR(sirf_audio_codec->clk)) {
437 dev_err(&pdev->dev, "Get clock failed.\n");
438 return PTR_ERR(sirf_audio_codec->clk);
439 }
440
441 ret = clk_prepare_enable(sirf_audio_codec->clk);
442 if (ret) {
443 dev_err(&pdev->dev, "Enable clock failed.\n");
444 return ret;
445 }
446
447 ret = snd_soc_register_codec(&(pdev->dev),
448 &soc_codec_device_sirf_audio_codec,
449 &sirf_audio_codec_dai, 1);
450 if (ret) {
451 dev_err(&pdev->dev, "Register Audio Codec dai failed.\n");
452 goto err_clk_put;
453 }
454
455 /*
456 * Always open charge pump, if not, when the charge pump closed the
457 * adc will not stable
458 */
459 regmap_update_bits(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
460 IC_CPFREQ, IC_CPFREQ);
461
462 if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas6-audio-codec"))
463 regmap_update_bits(sirf_audio_codec->regmap,
464 AUDIO_IC_CODEC_CTRL0, IC_CPEN, IC_CPEN);
465 return 0;
466
467err_clk_put:
468 clk_disable_unprepare(sirf_audio_codec->clk);
469 return ret;
470}
471
472static int sirf_audio_codec_driver_remove(struct platform_device *pdev)
473{
474 struct sirf_audio_codec *sirf_audio_codec = platform_get_drvdata(pdev);
475
476 clk_disable_unprepare(sirf_audio_codec->clk);
477 snd_soc_unregister_codec(&(pdev->dev));
478
479 return 0;
480}
481
482#ifdef CONFIG_PM_SLEEP
483static int sirf_audio_codec_suspend(struct device *dev)
484{
485 struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev);
486
487 regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
488 &sirf_audio_codec->reg_ctrl0);
489 regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1,
490 &sirf_audio_codec->reg_ctrl1);
491 clk_disable_unprepare(sirf_audio_codec->clk);
492
493 return 0;
494}
495
496static int sirf_audio_codec_resume(struct device *dev)
497{
498 struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev);
499 int ret;
500
501 ret = clk_prepare_enable(sirf_audio_codec->clk);
502 if (ret)
503 return ret;
504
505 regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
506 sirf_audio_codec->reg_ctrl0);
507 regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1,
508 sirf_audio_codec->reg_ctrl1);
509
510 return 0;
511}
512#endif
513
514static const struct dev_pm_ops sirf_audio_codec_pm_ops = {
515 SET_SYSTEM_SLEEP_PM_OPS(sirf_audio_codec_suspend, sirf_audio_codec_resume)
516};
517
518static struct platform_driver sirf_audio_codec_driver = {
519 .driver = {
520 .name = "sirf-audio-codec",
521 .owner = THIS_MODULE,
522 .of_match_table = sirf_audio_codec_of_match,
523 .pm = &sirf_audio_codec_pm_ops,
524 },
525 .probe = sirf_audio_codec_driver_probe,
526 .remove = sirf_audio_codec_driver_remove,
527};
528
529module_platform_driver(sirf_audio_codec_driver);
530
531MODULE_DESCRIPTION("SiRF audio codec driver");
532MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
533MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/sirf-audio-codec.h b/sound/soc/codecs/sirf-audio-codec.h
new file mode 100644
index 000000000000..d4c187b8e54a
--- /dev/null
+++ b/sound/soc/codecs/sirf-audio-codec.h
@@ -0,0 +1,75 @@
1/*
2 * SiRF inner codec controllers define
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#ifndef _SIRF_AUDIO_CODEC_H
10#define _SIRF_AUDIO_CODEC_H
11
12
13#define AUDIO_IC_CODEC_PWR (0x00E0)
14#define AUDIO_IC_CODEC_CTRL0 (0x00E4)
15#define AUDIO_IC_CODEC_CTRL1 (0x00E8)
16#define AUDIO_IC_CODEC_CTRL2 (0x00EC)
17#define AUDIO_IC_CODEC_CTRL3 (0x00F0)
18
19#define MICBIASEN (1 << 3)
20
21#define IC_RDACEN (1 << 0)
22#define IC_LDACEN (1 << 1)
23#define IC_HSREN (1 << 2)
24#define IC_HSLEN (1 << 3)
25#define IC_SPEN (1 << 4)
26#define IC_CPEN (1 << 5)
27
28#define IC_HPRSELR (1 << 6)
29#define IC_HPLSELR (1 << 7)
30#define IC_HPRSELL (1 << 8)
31#define IC_HPLSELL (1 << 9)
32#define IC_SPSELR (1 << 10)
33#define IC_SPSELL (1 << 11)
34
35#define IC_MONOR (1 << 12)
36#define IC_MONOL (1 << 13)
37
38#define IC_RXOSRSEL (1 << 28)
39#define IC_CPFREQ (1 << 29)
40#define IC_HSINVEN (1 << 30)
41
42#define IC_MICINREN (1 << 0)
43#define IC_MICINLEN (1 << 1)
44#define IC_MICIN1SEL (1 << 2)
45#define IC_MICIN2SEL (1 << 3)
46#define IC_MICDIFSEL (1 << 4)
47#define IC_LINEIN1SEL (1 << 5)
48#define IC_LINEIN2SEL (1 << 6)
49#define IC_RADCEN (1 << 7)
50#define IC_LADCEN (1 << 8)
51#define IC_ALM (1 << 9)
52
53#define IC_DIGMICEN (1 << 22)
54#define IC_DIGMICFREQ (1 << 23)
55#define IC_ADC14B_12 (1 << 24)
56#define IC_FIRDAC_HSL_EN (1 << 25)
57#define IC_FIRDAC_HSR_EN (1 << 26)
58#define IC_FIRDAC_LOUT_EN (1 << 27)
59#define IC_POR (1 << 28)
60#define IC_CODEC_CLK_EN (1 << 29)
61#define IC_HP_3DB_BOOST (1 << 30)
62
63#define IC_ADC_LEFT_GAIN_SHIFT 16
64#define IC_ADC_RIGHT_GAIN_SHIFT 10
65#define IC_ADC_GAIN_MASK 0x3F
66#define IC_MIC_MAX_GAIN 0x39
67
68#define IC_RXPGAR_MASK 0x3F
69#define IC_RXPGAR_SHIFT 14
70#define IC_RXPGAL_MASK 0x3F
71#define IC_RXPGAL_SHIFT 21
72#define IC_RXPGAR 0x7B
73#define IC_RXPGAL 0x7B
74
75#endif /*__SIRF_AUDIO_CODEC_H*/