aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorRichard Purdie <richard@openedhand.com>2008-06-23 09:51:28 -0400
committerJaroslav Kysela <perex@perex.cz>2008-06-26 03:01:58 -0400
commit796d2ca84859d1fdb11ff06cd9707ffab5642fca (patch)
tree720b4ddfb75243601774bf5d9f617c6dcf4711a2 /sound/soc
parent627d3e7abca30d6e86787c98dd7cbac0233bc5a9 (diff)
ALSA: ASoC: Add AK4535 driver
The AK4535 codec is included in some HP iPAQ systems. This driver was originally written by Richard Purdie and with some bug fixes from Milan Plzik. While out of tree it has also had some mechanical updates for new APIs and current best practices from Liam Girdwood, Graeme Gregory and Mark Brown. Signed-off-by: Richard Purdie <richard@openedhand.com> Signed-off-by: Milan Plzik <milan.plzik@gmail.com> Signed-off-by: Liam Girdwood <lg@opensource.wolfsonmicro.com> Signed-off-by: Graeme Gregory <gg@opensource.wolfsonmicro.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/codecs/Kconfig3
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/ak4535.c696
-rw-r--r--sound/soc/codecs/ak4535.h46
4 files changed, 747 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index f439138db843..1db04a28a53d 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -2,6 +2,9 @@ config SND_SOC_AC97_CODEC
2 tristate 2 tristate
3 select SND_AC97_CODEC 3 select SND_AC97_CODEC
4 4
5config SND_SOC_AK4535
6 tristate
7
5config SND_SOC_UDA1380 8config SND_SOC_UDA1380
6 tristate 9 tristate
7 10
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index d9826f35d8c0..d7b97abcf729 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,4 +1,5 @@
1snd-soc-ac97-objs := ac97.o 1snd-soc-ac97-objs := ac97.o
2snd-soc-ak4535-objs := ak4535.o
2snd-soc-uda1380-objs := uda1380.o 3snd-soc-uda1380-objs := uda1380.o
3snd-soc-wm8510-objs := wm8510.o 4snd-soc-wm8510-objs := wm8510.o
4snd-soc-wm8731-objs := wm8731.o 5snd-soc-wm8731-objs := wm8731.o
@@ -11,6 +12,7 @@ snd-soc-cs4270-objs := cs4270.o
11snd-soc-tlv320aic3x-objs := tlv320aic3x.o 12snd-soc-tlv320aic3x-objs := tlv320aic3x.o
12 13
13obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o 14obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
15obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
14obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o 16obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
15obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o 17obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o
16obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o 18obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
new file mode 100644
index 000000000000..469266e881d8
--- /dev/null
+++ b/sound/soc/codecs/ak4535.c
@@ -0,0 +1,696 @@
1/*
2 * ak4535.c -- AK4535 ALSA Soc Audio driver
3 *
4 * Copyright 2005 Openedhand Ltd.
5 *
6 * Author: Richard Purdie <richard@openedhand.com>
7 *
8 * Based on wm8753.c by Liam Girdwood
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/init.h>
18#include <linux/delay.h>
19#include <linux/pm.h>
20#include <linux/i2c.h>
21#include <linux/platform_device.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/soc-dapm.h>
27#include <sound/initval.h>
28
29#include "ak4535.h"
30
31#define AUDIO_NAME "ak4535"
32#define AK4535_VERSION "0.3"
33
34struct snd_soc_codec_device soc_codec_dev_ak4535;
35
36/* codec private data */
37struct ak4535_priv {
38 unsigned int sysclk;
39};
40
41/*
42 * ak4535 register cache
43 */
44static const u16 ak4535_reg[AK4535_CACHEREGNUM] = {
45 0x0000, 0x0080, 0x0000, 0x0003,
46 0x0002, 0x0000, 0x0011, 0x0001,
47 0x0000, 0x0040, 0x0036, 0x0010,
48 0x0000, 0x0000, 0x0057, 0x0000,
49};
50
51/*
52 * read ak4535 register cache
53 */
54static inline unsigned int ak4535_read_reg_cache(struct snd_soc_codec *codec,
55 unsigned int reg)
56{
57 u16 *cache = codec->reg_cache;
58 if (reg >= AK4535_CACHEREGNUM)
59 return -1;
60 return cache[reg];
61}
62
63static inline unsigned int ak4535_read(struct snd_soc_codec *codec,
64 unsigned int reg)
65{
66 u8 data;
67 data = reg;
68
69 if (codec->hw_write(codec->control_data, &data, 1) != 1)
70 return -EIO;
71
72 if (codec->hw_read(codec->control_data, &data, 1) != 1)
73 return -EIO;
74
75 return data;
76};
77
78/*
79 * write ak4535 register cache
80 */
81static inline void ak4535_write_reg_cache(struct snd_soc_codec *codec,
82 u16 reg, unsigned int value)
83{
84 u16 *cache = codec->reg_cache;
85 if (reg >= AK4535_CACHEREGNUM)
86 return;
87 cache[reg] = value;
88}
89
90/*
91 * write to the AK4535 register space
92 */
93static int ak4535_write(struct snd_soc_codec *codec, unsigned int reg,
94 unsigned int value)
95{
96 u8 data[2];
97
98 /* data is
99 * D15..D8 AK4535 register offset
100 * D7...D0 register data
101 */
102 data[0] = reg & 0xff;
103 data[1] = value & 0xff;
104
105 ak4535_write_reg_cache(codec, reg, value);
106 if (codec->hw_write(codec->control_data, data, 2) == 2)
107 return 0;
108 else
109 return -EIO;
110}
111
112static int ak4535_sync(struct snd_soc_codec *codec)
113{
114 u16 *cache = codec->reg_cache;
115 int i, r = 0;
116
117 for (i = 0; i < AK4535_CACHEREGNUM; i++)
118 r |= ak4535_write(codec, i, cache[i]);
119
120 return r;
121};
122
123static const char *ak4535_mono_gain[] = {"+6dB", "-17dB"};
124static const char *ak4535_mono_out[] = {"(L + R)/2", "Hi-Z"};
125static const char *ak4535_hp_out[] = {"Stereo", "Mono"};
126static const char *ak4535_deemp[] = {"44.1kHz", "Off", "48kHz", "32kHz"};
127static const char *ak4535_mic_select[] = {"Internal", "External"};
128
129static const struct soc_enum ak4535_enum[] = {
130 SOC_ENUM_SINGLE(AK4535_SIG1, 7, 2, ak4535_mono_gain),
131 SOC_ENUM_SINGLE(AK4535_SIG1, 6, 2, ak4535_mono_out),
132 SOC_ENUM_SINGLE(AK4535_MODE2, 2, 2, ak4535_hp_out),
133 SOC_ENUM_SINGLE(AK4535_DAC, 0, 4, ak4535_deemp),
134 SOC_ENUM_SINGLE(AK4535_MIC, 1, 2, ak4535_mic_select),
135};
136
137static const struct snd_kcontrol_new ak4535_snd_controls[] = {
138 SOC_SINGLE("ALC2 Switch", AK4535_SIG1, 1, 1, 0),
139 SOC_ENUM("Mono 1 Output", ak4535_enum[1]),
140 SOC_ENUM("Mono 1 Gain", ak4535_enum[0]),
141 SOC_ENUM("Headphone Output", ak4535_enum[2]),
142 SOC_ENUM("Playback Deemphasis", ak4535_enum[3]),
143 SOC_SINGLE("Bass Volume", AK4535_DAC, 2, 3, 0),
144 SOC_SINGLE("Mic Boost (+20dB) Switch", AK4535_MIC, 0, 1, 0),
145 SOC_ENUM("Mic Select", ak4535_enum[4]),
146 SOC_SINGLE("ALC Operation Time", AK4535_TIMER, 0, 3, 0),
147 SOC_SINGLE("ALC Recovery Time", AK4535_TIMER, 2, 3, 0),
148 SOC_SINGLE("ALC ZC Time", AK4535_TIMER, 4, 3, 0),
149 SOC_SINGLE("ALC 1 Switch", AK4535_ALC1, 5, 1, 0),
150 SOC_SINGLE("ALC 2 Switch", AK4535_ALC1, 6, 1, 0),
151 SOC_SINGLE("ALC Volume", AK4535_ALC2, 0, 127, 0),
152 SOC_SINGLE("Capture Volume", AK4535_PGA, 0, 127, 0),
153 SOC_SINGLE("Left Playback Volume", AK4535_LATT, 0, 127, 1),
154 SOC_SINGLE("Right Playback Volume", AK4535_RATT, 0, 127, 1),
155 SOC_SINGLE("AUX Bypass Volume", AK4535_VOL, 0, 15, 0),
156 SOC_SINGLE("Mic Sidetone Volume", AK4535_VOL, 4, 7, 0),
157};
158
159/* add non dapm controls */
160static int ak4535_add_controls(struct snd_soc_codec *codec)
161{
162 int err, i;
163
164 for (i = 0; i < ARRAY_SIZE(ak4535_snd_controls); i++) {
165 err = snd_ctl_add(codec->card,
166 snd_soc_cnew(&ak4535_snd_controls[i], codec, NULL));
167 if (err < 0)
168 return err;
169 }
170
171 return 0;
172}
173
174/* Mono 1 Mixer */
175static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = {
176 SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG1, 4, 1, 0),
177 SOC_DAPM_SINGLE("Mono Playback Switch", AK4535_SIG1, 5, 1, 0),
178};
179
180/* Stereo Mixer */
181static const struct snd_kcontrol_new ak4535_stereo_mixer_controls[] = {
182 SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG2, 4, 1, 0),
183 SOC_DAPM_SINGLE("Playback Switch", AK4535_SIG2, 7, 1, 0),
184 SOC_DAPM_SINGLE("Aux Bypass Switch", AK4535_SIG2, 5, 1, 0),
185};
186
187/* Input Mixer */
188static const struct snd_kcontrol_new ak4535_input_mixer_controls[] = {
189 SOC_DAPM_SINGLE("Mic Capture Switch", AK4535_MIC, 2, 1, 0),
190 SOC_DAPM_SINGLE("Aux Capture Switch", AK4535_MIC, 5, 1, 0),
191};
192
193/* Input mux */
194static const struct snd_kcontrol_new ak4535_input_mux_control =
195 SOC_DAPM_ENUM("Input Select", ak4535_enum[4]);
196
197/* HP L switch */
198static const struct snd_kcontrol_new ak4535_hpl_control =
199 SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 1, 1, 1);
200
201/* HP R switch */
202static const struct snd_kcontrol_new ak4535_hpr_control =
203 SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 0, 1, 1);
204
205/* mono 2 switch */
206static const struct snd_kcontrol_new ak4535_mono2_control =
207 SOC_DAPM_SINGLE("Switch", AK4535_SIG1, 0, 1, 0);
208
209/* Line out switch */
210static const struct snd_kcontrol_new ak4535_line_control =
211 SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 6, 1, 0);
212
213/* ak4535 dapm widgets */
214static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = {
215 SND_SOC_DAPM_MIXER("Stereo Mixer", SND_SOC_NOPM, 0, 0,
216 &ak4535_stereo_mixer_controls[0],
217 ARRAY_SIZE(ak4535_stereo_mixer_controls)),
218 SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0,
219 &ak4535_mono1_mixer_controls[0],
220 ARRAY_SIZE(ak4535_mono1_mixer_controls)),
221 SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0,
222 &ak4535_input_mixer_controls[0],
223 ARRAY_SIZE(ak4535_input_mixer_controls)),
224 SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
225 &ak4535_input_mux_control),
226 SND_SOC_DAPM_DAC("DAC", "Playback", AK4535_PM2, 0, 0),
227 SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0,
228 &ak4535_mono2_control),
229 /* speaker powersave bit */
230 SND_SOC_DAPM_PGA("Speaker Enable", AK4535_MODE2, 0, 0, NULL, 0),
231 SND_SOC_DAPM_SWITCH("Line Out Enable", SND_SOC_NOPM, 0, 0,
232 &ak4535_line_control),
233 SND_SOC_DAPM_SWITCH("Left HP Enable", SND_SOC_NOPM, 0, 0,
234 &ak4535_hpl_control),
235 SND_SOC_DAPM_SWITCH("Right HP Enable", SND_SOC_NOPM, 0, 0,
236 &ak4535_hpr_control),
237 SND_SOC_DAPM_OUTPUT("LOUT"),
238 SND_SOC_DAPM_OUTPUT("HPL"),
239 SND_SOC_DAPM_OUTPUT("ROUT"),
240 SND_SOC_DAPM_OUTPUT("HPR"),
241 SND_SOC_DAPM_OUTPUT("SPP"),
242 SND_SOC_DAPM_OUTPUT("SPN"),
243 SND_SOC_DAPM_OUTPUT("MOUT1"),
244 SND_SOC_DAPM_OUTPUT("MOUT2"),
245 SND_SOC_DAPM_OUTPUT("MICOUT"),
246 SND_SOC_DAPM_ADC("ADC", "Capture", AK4535_PM1, 0, 0),
247 SND_SOC_DAPM_PGA("Spk Amp", AK4535_PM2, 3, 0, NULL, 0),
248 SND_SOC_DAPM_PGA("HP R Amp", AK4535_PM2, 1, 0, NULL, 0),
249 SND_SOC_DAPM_PGA("HP L Amp", AK4535_PM2, 2, 0, NULL, 0),
250 SND_SOC_DAPM_PGA("Mic", AK4535_PM1, 1, 0, NULL, 0),
251 SND_SOC_DAPM_PGA("Line Out", AK4535_PM1, 4, 0, NULL, 0),
252 SND_SOC_DAPM_PGA("Mono Out", AK4535_PM1, 3, 0, NULL, 0),
253 SND_SOC_DAPM_PGA("AUX In", AK4535_PM1, 2, 0, NULL, 0),
254
255 SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4535_MIC, 3, 0),
256 SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4535_MIC, 4, 0),
257 SND_SOC_DAPM_INPUT("MICIN"),
258 SND_SOC_DAPM_INPUT("MICEXT"),
259 SND_SOC_DAPM_INPUT("AUX"),
260 SND_SOC_DAPM_INPUT("MIN"),
261 SND_SOC_DAPM_INPUT("AIN"),
262};
263
264static const struct snd_soc_dapm_route audio_map[] = {
265 /*stereo mixer */
266 {"Stereo Mixer", "Playback Switch", "DAC"},
267 {"Stereo Mixer", "Mic Sidetone Switch", "Mic"},
268 {"Stereo Mixer", "Aux Bypass Switch", "AUX In"},
269
270 /* mono1 mixer */
271 {"Mono1 Mixer", "Mic Sidetone Switch", "Mic"},
272 {"Mono1 Mixer", "Mono Playback Switch", "DAC"},
273
274 /* Mic */
275 {"Mic", NULL, "AIN"},
276 {"Input Mux", "Internal", "Mic Int Bias"},
277 {"Input Mux", "External", "Mic Ext Bias"},
278 {"Mic Int Bias", NULL, "MICIN"},
279 {"Mic Ext Bias", NULL, "MICEXT"},
280 {"MICOUT", NULL, "Input Mux"},
281
282 /* line out */
283 {"LOUT", NULL, "Line Out Enable"},
284 {"ROUT", NULL, "Line Out Enable"},
285 {"Line Out Enable", "Switch", "Line Out"},
286 {"Line Out", NULL, "Stereo Mixer"},
287
288 /* mono1 out */
289 {"MOUT1", NULL, "Mono Out"},
290 {"Mono Out", NULL, "Mono1 Mixer"},
291
292 /* left HP */
293 {"HPL", NULL, "Left HP Enable"},
294 {"Left HP Enable", "Switch", "HP L Amp"},
295 {"HP L Amp", NULL, "Stereo Mixer"},
296
297 /* right HP */
298 {"HPR", NULL, "Right HP Enable"},
299 {"Right HP Enable", "Switch", "HP R Amp"},
300 {"HP R Amp", NULL, "Stereo Mixer"},
301
302 /* speaker */
303 {"SPP", NULL, "Speaker Enable"},
304 {"SPN", NULL, "Speaker Enable"},
305 {"Speaker Enable", "Switch", "Spk Amp"},
306 {"Spk Amp", NULL, "MIN"},
307
308 /* mono 2 */
309 {"MOUT2", NULL, "Mono 2 Enable"},
310 {"Mono 2 Enable", "Switch", "Stereo Mixer"},
311
312 /* Aux In */
313 {"Aux In", NULL, "AUX"},
314
315 /* ADC */
316 {"ADC", NULL, "Input Mixer"},
317 {"Input Mixer", "Mic Capture Switch", "Mic"},
318 {"Input Mixer", "Aux Capture Switch", "Aux In"},
319};
320
321static int ak4535_add_widgets(struct snd_soc_codec *codec)
322{
323 snd_soc_dapm_new_controls(codec, ak4535_dapm_widgets,
324 ARRAY_SIZE(ak4535_dapm_widgets));
325
326 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
327
328 snd_soc_dapm_new_widgets(codec);
329 return 0;
330}
331
332static int ak4535_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
333 int clk_id, unsigned int freq, int dir)
334{
335 struct snd_soc_codec *codec = codec_dai->codec;
336 struct ak4535_priv *ak4535 = codec->private_data;
337
338 ak4535->sysclk = freq;
339 return 0;
340}
341
342static int ak4535_hw_params(struct snd_pcm_substream *substream,
343 struct snd_pcm_hw_params *params)
344{
345 struct snd_soc_pcm_runtime *rtd = substream->private_data;
346 struct snd_soc_device *socdev = rtd->socdev;
347 struct snd_soc_codec *codec = socdev->codec;
348 struct ak4535_priv *ak4535 = codec->private_data;
349 u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5);
350 int rate = params_rate(params), fs = 256;
351
352 if (rate)
353 fs = ak4535->sysclk / rate;
354
355 /* set fs */
356 switch (fs) {
357 case 1024:
358 mode2 |= (0x2 << 5);
359 break;
360 case 512:
361 mode2 |= (0x1 << 5);
362 break;
363 case 256:
364 break;
365 }
366
367 /* set rate */
368 ak4535_write(codec, AK4535_MODE2, mode2);
369 return 0;
370}
371
372static int ak4535_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
373 unsigned int fmt)
374{
375 struct snd_soc_codec *codec = codec_dai->codec;
376 u8 mode1 = 0;
377
378 /* interface format */
379 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
380 case SND_SOC_DAIFMT_I2S:
381 mode1 = 0x0002;
382 break;
383 case SND_SOC_DAIFMT_LEFT_J:
384 mode1 = 0x0001;
385 break;
386 default:
387 return -EINVAL;
388 }
389
390 /* use 32 fs for BCLK to save power */
391 mode1 |= 0x4;
392
393 ak4535_write(codec, AK4535_MODE1, mode1);
394 return 0;
395}
396
397static int ak4535_mute(struct snd_soc_codec_dai *dai, int mute)
398{
399 struct snd_soc_codec *codec = dai->codec;
400 u16 mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
401 if (!mute)
402 ak4535_write(codec, AK4535_DAC, mute_reg);
403 else
404 ak4535_write(codec, AK4535_DAC, mute_reg | 0x20);
405 return 0;
406}
407
408static int ak4535_set_bias_level(struct snd_soc_codec *codec,
409 enum snd_soc_bias_level level)
410{
411 u16 i;
412
413 switch (level) {
414 case SND_SOC_BIAS_ON:
415 ak4535_mute(codec->dai, 0);
416 break;
417 case SND_SOC_BIAS_PREPARE:
418 ak4535_mute(codec->dai, 1);
419 break;
420 case SND_SOC_BIAS_STANDBY:
421 i = ak4535_read_reg_cache(codec, AK4535_PM1);
422 ak4535_write(codec, AK4535_PM1, i | 0x80);
423 i = ak4535_read_reg_cache(codec, AK4535_PM2);
424 ak4535_write(codec, AK4535_PM2, i & (~0x80));
425 break;
426 case SND_SOC_BIAS_OFF:
427 i = ak4535_read_reg_cache(codec, AK4535_PM1);
428 ak4535_write(codec, AK4535_PM1, i & (~0x80));
429 break;
430 }
431 codec->bias_level = level;
432 return 0;
433}
434
435#define AK4535_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
436 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
437 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
438
439struct snd_soc_codec_dai ak4535_dai = {
440 .name = "AK4535",
441 .playback = {
442 .stream_name = "Playback",
443 .channels_min = 1,
444 .channels_max = 2,
445 .rates = AK4535_RATES,
446 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
447 .capture = {
448 .stream_name = "Capture",
449 .channels_min = 1,
450 .channels_max = 2,
451 .rates = AK4535_RATES,
452 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
453 .ops = {
454 .hw_params = ak4535_hw_params,
455 },
456 .dai_ops = {
457 .set_fmt = ak4535_set_dai_fmt,
458 .digital_mute = ak4535_mute,
459 .set_sysclk = ak4535_set_dai_sysclk,
460 },
461};
462EXPORT_SYMBOL_GPL(ak4535_dai);
463
464static int ak4535_suspend(struct platform_device *pdev, pm_message_t state)
465{
466 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
467 struct snd_soc_codec *codec = socdev->codec;
468
469 ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
470 return 0;
471}
472
473static int ak4535_resume(struct platform_device *pdev)
474{
475 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
476 struct snd_soc_codec *codec = socdev->codec;
477 ak4535_sync(codec);
478 ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
479 ak4535_set_bias_level(codec, codec->suspend_bias_level);
480 return 0;
481}
482
483/*
484 * initialise the AK4535 driver
485 * register the mixer and dsp interfaces with the kernel
486 */
487static int ak4535_init(struct snd_soc_device *socdev)
488{
489 struct snd_soc_codec *codec = socdev->codec;
490 int ret = 0;
491
492 codec->name = "AK4535";
493 codec->owner = THIS_MODULE;
494 codec->read = ak4535_read_reg_cache;
495 codec->write = ak4535_write;
496 codec->set_bias_level = ak4535_set_bias_level;
497 codec->dai = &ak4535_dai;
498 codec->num_dai = 1;
499 codec->reg_cache_size = ARRAY_SIZE(ak4535_reg);
500 codec->reg_cache = kmemdup(ak4535_reg, sizeof(ak4535_reg), GFP_KERNEL);
501
502 if (codec->reg_cache == NULL)
503 return -ENOMEM;
504
505 /* register pcms */
506 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
507 if (ret < 0) {
508 printk(KERN_ERR "ak4535: failed to create pcms\n");
509 goto pcm_err;
510 }
511
512 /* power on device */
513 ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
514
515 ak4535_add_controls(codec);
516 ak4535_add_widgets(codec);
517 ret = snd_soc_register_card(socdev);
518 if (ret < 0) {
519 printk(KERN_ERR "ak4535: failed to register card\n");
520 goto card_err;
521 }
522
523 return ret;
524
525card_err:
526 snd_soc_free_pcms(socdev);
527 snd_soc_dapm_free(socdev);
528pcm_err:
529 kfree(codec->reg_cache);
530
531 return ret;
532}
533
534static struct snd_soc_device *ak4535_socdev;
535
536#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
537
538#define I2C_DRIVERID_AK4535 0xfefe /* liam - need a proper id */
539
540static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
541
542/* Magic definition of all other variables and things */
543I2C_CLIENT_INSMOD;
544
545static struct i2c_driver ak4535_i2c_driver;
546static struct i2c_client client_template;
547
548/* If the i2c layer weren't so broken, we could pass this kind of data
549 around */
550static int ak4535_codec_probe(struct i2c_adapter *adap, int addr, int kind)
551{
552 struct snd_soc_device *socdev = ak4535_socdev;
553 struct ak4535_setup_data *setup = socdev->codec_data;
554 struct snd_soc_codec *codec = socdev->codec;
555 struct i2c_client *i2c;
556 int ret;
557
558 if (addr != setup->i2c_address)
559 return -ENODEV;
560
561 client_template.adapter = adap;
562 client_template.addr = addr;
563
564 i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
565 if (i2c == NULL) {
566 kfree(codec);
567 return -ENOMEM;
568 }
569 i2c_set_clientdata(i2c, codec);
570 codec->control_data = i2c;
571
572 ret = i2c_attach_client(i2c);
573 if (ret < 0) {
574 printk(KERN_ERR "failed to attach codec at addr %x\n", addr);
575 goto err;
576 }
577
578 ret = ak4535_init(socdev);
579 if (ret < 0) {
580 printk(KERN_ERR "failed to initialise AK4535\n");
581 goto err;
582 }
583 return ret;
584
585err:
586 kfree(codec);
587 kfree(i2c);
588 return ret;
589}
590
591static int ak4535_i2c_detach(struct i2c_client *client)
592{
593 struct snd_soc_codec *codec = i2c_get_clientdata(client);
594 i2c_detach_client(client);
595 kfree(codec->reg_cache);
596 kfree(client);
597 return 0;
598}
599
600static int ak4535_i2c_attach(struct i2c_adapter *adap)
601{
602 return i2c_probe(adap, &addr_data, ak4535_codec_probe);
603}
604
605/* corgi i2c codec control layer */
606static struct i2c_driver ak4535_i2c_driver = {
607 .driver = {
608 .name = "AK4535 I2C Codec",
609 .owner = THIS_MODULE,
610 },
611 .id = I2C_DRIVERID_AK4535,
612 .attach_adapter = ak4535_i2c_attach,
613 .detach_client = ak4535_i2c_detach,
614 .command = NULL,
615};
616
617static struct i2c_client client_template = {
618 .name = "AK4535",
619 .driver = &ak4535_i2c_driver,
620};
621#endif
622
623static int ak4535_probe(struct platform_device *pdev)
624{
625 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
626 struct ak4535_setup_data *setup;
627 struct snd_soc_codec *codec;
628 struct ak4535_priv *ak4535;
629 int ret = 0;
630
631 printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
632
633 setup = socdev->codec_data;
634 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
635 if (codec == NULL)
636 return -ENOMEM;
637
638 ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
639 if (ak4535 == NULL) {
640 kfree(codec);
641 return -ENOMEM;
642 }
643
644 codec->private_data = ak4535;
645 socdev->codec = codec;
646 mutex_init(&codec->mutex);
647 INIT_LIST_HEAD(&codec->dapm_widgets);
648 INIT_LIST_HEAD(&codec->dapm_paths);
649
650 ak4535_socdev = socdev;
651#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
652 if (setup->i2c_address) {
653 normal_i2c[0] = setup->i2c_address;
654 codec->hw_write = (hw_write_t)i2c_master_send;
655 codec->hw_read = (hw_read_t)i2c_master_recv;
656 ret = i2c_add_driver(&ak4535_i2c_driver);
657 if (ret != 0)
658 printk(KERN_ERR "can't add i2c driver");
659 }
660#else
661 /* Add other interfaces here */
662#endif
663 return ret;
664}
665
666/* power down chip */
667static int ak4535_remove(struct platform_device *pdev)
668{
669 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
670 struct snd_soc_codec *codec = socdev->codec;
671
672 if (codec->control_data)
673 ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
674
675 snd_soc_free_pcms(socdev);
676 snd_soc_dapm_free(socdev);
677#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
678 i2c_del_driver(&ak4535_i2c_driver);
679#endif
680 kfree(codec->private_data);
681 kfree(codec);
682
683 return 0;
684}
685
686struct snd_soc_codec_device soc_codec_dev_ak4535 = {
687 .probe = ak4535_probe,
688 .remove = ak4535_remove,
689 .suspend = ak4535_suspend,
690 .resume = ak4535_resume,
691};
692EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535);
693
694MODULE_DESCRIPTION("Soc AK4535 driver");
695MODULE_AUTHOR("Richard Purdie");
696MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ak4535.h b/sound/soc/codecs/ak4535.h
new file mode 100644
index 000000000000..fc686ddf753a
--- /dev/null
+++ b/sound/soc/codecs/ak4535.h
@@ -0,0 +1,46 @@
1/*
2 * ak4535.h -- AK4535 Soc Audio driver
3 *
4 * Copyright 2005 Openedhand Ltd.
5 *
6 * Author: Richard Purdie <richard@openedhand.com>
7 *
8 * Based on wm8753.h
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#ifndef _AK4535_H
16#define _AK4535_H
17
18/* AK4535 register space */
19
20#define AK4535_PM1 0x0
21#define AK4535_PM2 0x1
22#define AK4535_SIG1 0x2
23#define AK4535_SIG2 0x3
24#define AK4535_MODE1 0x4
25#define AK4535_MODE2 0x5
26#define AK4535_DAC 0x6
27#define AK4535_MIC 0x7
28#define AK4535_TIMER 0x8
29#define AK4535_ALC1 0x9
30#define AK4535_ALC2 0xa
31#define AK4535_PGA 0xb
32#define AK4535_LATT 0xc
33#define AK4535_RATT 0xd
34#define AK4535_VOL 0xe
35#define AK4535_STATUS 0xf
36
37#define AK4535_CACHEREGNUM 0x10
38
39struct ak4535_setup_data {
40 unsigned short i2c_address;
41};
42
43extern struct snd_soc_codec_dai ak4535_dai;
44extern struct snd_soc_codec_device soc_codec_dev_ak4535;
45
46#endif