diff options
author | Kuninori Morimoto <morimoto.kuninori@renesas.com> | 2009-08-20 21:23:41 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-08-21 05:54:02 -0400 |
commit | a3a83d9a7cb0ce3b1d100060d5ad777e7480b4f2 (patch) | |
tree | 2a54acafb3ceb482c9a7c6030940b2db4cc7c3b7 /sound/soc/codecs/ak4642.c | |
parent | b2ec22e2633996727f4f2abcd806aaeb0506dd6a (diff) |
ASoC: Add ak4642/ak4643 codec support
This is very simple driver for ALSA
It supprt headphone output and stereo input only
This patch is tested by ms7724se
Signed-off-by: Kuninori Morimoto <morimoto.kuninori@renesas.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/ak4642.c')
-rw-r--r-- | sound/soc/codecs/ak4642.c | 502 |
1 files changed, 502 insertions, 0 deletions
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c new file mode 100644 index 000000000000..e057c7b578df --- /dev/null +++ b/sound/soc/codecs/ak4642.c | |||
@@ -0,0 +1,502 @@ | |||
1 | /* | ||
2 | * ak4642.c -- AK4642/AK4643 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <morimoto.kuninori@renesas.com> | ||
6 | * | ||
7 | * Based on wm8731.c by Richard Purdie | ||
8 | * Based on ak4535.c by Richard Purdie | ||
9 | * Based on wm8753.c by Liam Girdwood | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | /* ** CAUTION ** | ||
17 | * | ||
18 | * This is very simple driver. | ||
19 | * It can use headphone output / stereo input only | ||
20 | * | ||
21 | * AK4642 is not tested. | ||
22 | * AK4643 is tested. | ||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/moduleparam.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/pm.h> | ||
30 | #include <linux/i2c.h> | ||
31 | #include <linux/platform_device.h> | ||
32 | #include <sound/core.h> | ||
33 | #include <sound/pcm.h> | ||
34 | #include <sound/pcm_params.h> | ||
35 | #include <sound/soc.h> | ||
36 | #include <sound/soc-dapm.h> | ||
37 | #include <sound/initval.h> | ||
38 | |||
39 | #include "ak4642.h" | ||
40 | |||
41 | #define AK4642_VERSION "0.0.1" | ||
42 | |||
43 | #define PW_MGMT1 0x00 | ||
44 | #define PW_MGMT2 0x01 | ||
45 | #define SG_SL1 0x02 | ||
46 | #define SG_SL2 0x03 | ||
47 | #define MD_CTL1 0x04 | ||
48 | #define MD_CTL2 0x05 | ||
49 | #define TIMER 0x06 | ||
50 | #define ALC_CTL1 0x07 | ||
51 | #define ALC_CTL2 0x08 | ||
52 | #define L_IVC 0x09 | ||
53 | #define L_DVC 0x0a | ||
54 | #define ALC_CTL3 0x0b | ||
55 | #define R_IVC 0x0c | ||
56 | #define R_DVC 0x0d | ||
57 | #define MD_CTL3 0x0e | ||
58 | #define MD_CTL4 0x0f | ||
59 | #define PW_MGMT3 0x10 | ||
60 | #define DF_S 0x11 | ||
61 | #define FIL3_0 0x12 | ||
62 | #define FIL3_1 0x13 | ||
63 | #define FIL3_2 0x14 | ||
64 | #define FIL3_3 0x15 | ||
65 | #define EQ_0 0x16 | ||
66 | #define EQ_1 0x17 | ||
67 | #define EQ_2 0x18 | ||
68 | #define EQ_3 0x19 | ||
69 | #define EQ_4 0x1a | ||
70 | #define EQ_5 0x1b | ||
71 | #define FIL1_0 0x1c | ||
72 | #define FIL1_1 0x1d | ||
73 | #define FIL1_2 0x1e | ||
74 | #define FIL1_3 0x1f | ||
75 | #define PW_MGMT4 0x20 | ||
76 | #define MD_CTL5 0x21 | ||
77 | #define LO_MS 0x22 | ||
78 | #define HP_MS 0x23 | ||
79 | #define SPK_MS 0x24 | ||
80 | |||
81 | #define AK4642_CACHEREGNUM 0x25 | ||
82 | |||
83 | struct snd_soc_codec_device soc_codec_dev_ak4642; | ||
84 | |||
85 | /* codec private data */ | ||
86 | struct ak4642_priv { | ||
87 | struct snd_soc_codec codec; | ||
88 | unsigned int sysclk; | ||
89 | }; | ||
90 | |||
91 | static struct snd_soc_codec *ak4642_codec; | ||
92 | |||
93 | /* | ||
94 | * ak4642 register cache | ||
95 | */ | ||
96 | static const u16 ak4642_reg[AK4642_CACHEREGNUM] = { | ||
97 | 0x0000, 0x0000, 0x0001, 0x0000, | ||
98 | 0x0002, 0x0000, 0x0000, 0x0000, | ||
99 | 0x00e1, 0x00e1, 0x0018, 0x0000, | ||
100 | 0x00e1, 0x0018, 0x0011, 0x0008, | ||
101 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
102 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
103 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
104 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
105 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
106 | 0x0000, | ||
107 | }; | ||
108 | |||
109 | /* | ||
110 | * read ak4642 register cache | ||
111 | */ | ||
112 | static inline unsigned int ak4642_read_reg_cache(struct snd_soc_codec *codec, | ||
113 | unsigned int reg) | ||
114 | { | ||
115 | u16 *cache = codec->reg_cache; | ||
116 | if (reg >= AK4642_CACHEREGNUM) | ||
117 | return -1; | ||
118 | return cache[reg]; | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * write ak4642 register cache | ||
123 | */ | ||
124 | static inline void ak4642_write_reg_cache(struct snd_soc_codec *codec, | ||
125 | u16 reg, unsigned int value) | ||
126 | { | ||
127 | u16 *cache = codec->reg_cache; | ||
128 | if (reg >= AK4642_CACHEREGNUM) | ||
129 | return; | ||
130 | |||
131 | cache[reg] = value; | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * write to the AK4642 register space | ||
136 | */ | ||
137 | static int ak4642_write(struct snd_soc_codec *codec, unsigned int reg, | ||
138 | unsigned int value) | ||
139 | { | ||
140 | u8 data[2]; | ||
141 | |||
142 | /* data is | ||
143 | * D15..D8 AK4642 register offset | ||
144 | * D7...D0 register data | ||
145 | */ | ||
146 | data[0] = reg & 0xff; | ||
147 | data[1] = value & 0xff; | ||
148 | |||
149 | if (codec->hw_write(codec->control_data, data, 2) == 2) { | ||
150 | ak4642_write_reg_cache(codec, reg, value); | ||
151 | return 0; | ||
152 | } else | ||
153 | return -EIO; | ||
154 | } | ||
155 | |||
156 | static int ak4642_sync(struct snd_soc_codec *codec) | ||
157 | { | ||
158 | u16 *cache = codec->reg_cache; | ||
159 | int i, r = 0; | ||
160 | |||
161 | for (i = 0; i < AK4642_CACHEREGNUM; i++) | ||
162 | r |= ak4642_write(codec, i, cache[i]); | ||
163 | |||
164 | return r; | ||
165 | }; | ||
166 | |||
167 | static int ak4642_dai_startup(struct snd_pcm_substream *substream, | ||
168 | struct snd_soc_dai *dai) | ||
169 | { | ||
170 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
171 | struct snd_soc_codec *codec = dai->codec; | ||
172 | |||
173 | if (is_play) { | ||
174 | /* | ||
175 | * start headphone output | ||
176 | * | ||
177 | * PLL, Master Mode | ||
178 | * Audio I/F Format :MSB justified (ADC & DAC) | ||
179 | * Sampling Frequency: 44.1kHz | ||
180 | * Digital Volume: −8dB | ||
181 | * Bass Boost Level : Middle | ||
182 | * | ||
183 | * This operation came from example code of | ||
184 | * "ASAHI KASEI AK4642" (japanese) manual p97. | ||
185 | * | ||
186 | * Example code use 0x39, 0x79 value for 0x01 address, | ||
187 | * But we need MCKO (0x02) bit now | ||
188 | */ | ||
189 | ak4642_write(codec, 0x05, 0x27); | ||
190 | ak4642_write(codec, 0x0f, 0x09); | ||
191 | ak4642_write(codec, 0x0e, 0x19); | ||
192 | ak4642_write(codec, 0x09, 0x91); | ||
193 | ak4642_write(codec, 0x0c, 0x91); | ||
194 | ak4642_write(codec, 0x0a, 0x28); | ||
195 | ak4642_write(codec, 0x0d, 0x28); | ||
196 | ak4642_write(codec, 0x00, 0x64); | ||
197 | ak4642_write(codec, 0x01, 0x3b); /* + MCKO bit */ | ||
198 | ak4642_write(codec, 0x01, 0x7b); /* + MCKO bit */ | ||
199 | } else { | ||
200 | /* | ||
201 | * start stereo input | ||
202 | * | ||
203 | * PLL Master Mode | ||
204 | * Audio I/F Format:MSB justified (ADC & DAC) | ||
205 | * Sampling Frequency:44.1kHz | ||
206 | * Pre MIC AMP:+20dB | ||
207 | * MIC Power On | ||
208 | * ALC setting:Refer to Table 35 | ||
209 | * ALC bit=“1” | ||
210 | * | ||
211 | * This operation came from example code of | ||
212 | * "ASAHI KASEI AK4642" (japanese) manual p94. | ||
213 | */ | ||
214 | ak4642_write(codec, 0x05, 0x27); | ||
215 | ak4642_write(codec, 0x02, 0x05); | ||
216 | ak4642_write(codec, 0x06, 0x3c); | ||
217 | ak4642_write(codec, 0x08, 0xe1); | ||
218 | ak4642_write(codec, 0x0b, 0x00); | ||
219 | ak4642_write(codec, 0x07, 0x21); | ||
220 | ak4642_write(codec, 0x00, 0x41); | ||
221 | ak4642_write(codec, 0x10, 0x01); | ||
222 | } | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static void ak4642_dai_shutdown(struct snd_pcm_substream *substream, | ||
228 | struct snd_soc_dai *dai) | ||
229 | { | ||
230 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
231 | struct snd_soc_codec *codec = dai->codec; | ||
232 | |||
233 | if (is_play) { | ||
234 | /* stop headphone output */ | ||
235 | ak4642_write(codec, 0x01, 0x3b); | ||
236 | ak4642_write(codec, 0x01, 0x0b); | ||
237 | ak4642_write(codec, 0x00, 0x40); | ||
238 | ak4642_write(codec, 0x0e, 0x11); | ||
239 | ak4642_write(codec, 0x0f, 0x08); | ||
240 | } else { | ||
241 | /* stop stereo input */ | ||
242 | ak4642_write(codec, 0x00, 0x40); | ||
243 | ak4642_write(codec, 0x10, 0x00); | ||
244 | ak4642_write(codec, 0x07, 0x01); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai, | ||
249 | int clk_id, unsigned int freq, int dir) | ||
250 | { | ||
251 | struct snd_soc_codec *codec = codec_dai->codec; | ||
252 | struct ak4642_priv *ak4642 = codec->private_data; | ||
253 | |||
254 | ak4642->sysclk = freq; | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static struct snd_soc_dai_ops ak4642_dai_ops = { | ||
259 | .startup = ak4642_dai_startup, | ||
260 | .shutdown = ak4642_dai_shutdown, | ||
261 | .set_sysclk = ak4642_dai_set_sysclk, | ||
262 | }; | ||
263 | |||
264 | struct snd_soc_dai ak4642_dai = { | ||
265 | .name = "AK4642", | ||
266 | .playback = { | ||
267 | .stream_name = "Playback", | ||
268 | .channels_min = 1, | ||
269 | .channels_max = 2, | ||
270 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
271 | .formats = SNDRV_PCM_FMTBIT_S16_LE }, | ||
272 | .capture = { | ||
273 | .stream_name = "Capture", | ||
274 | .channels_min = 1, | ||
275 | .channels_max = 2, | ||
276 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
277 | .formats = SNDRV_PCM_FMTBIT_S16_LE }, | ||
278 | .ops = &ak4642_dai_ops, | ||
279 | }; | ||
280 | EXPORT_SYMBOL_GPL(ak4642_dai); | ||
281 | |||
282 | static int ak4642_resume(struct platform_device *pdev) | ||
283 | { | ||
284 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
285 | struct snd_soc_codec *codec = socdev->card->codec; | ||
286 | |||
287 | ak4642_sync(codec); | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | /* | ||
292 | * initialise the AK4642 driver | ||
293 | * register the mixer and dsp interfaces with the kernel | ||
294 | */ | ||
295 | static int ak4642_init(struct ak4642_priv *ak4642) | ||
296 | { | ||
297 | struct snd_soc_codec *codec = &ak4642->codec; | ||
298 | int ret = 0; | ||
299 | |||
300 | if (ak4642_codec) { | ||
301 | dev_err(codec->dev, "Another ak4642 is registered\n"); | ||
302 | return -EINVAL; | ||
303 | } | ||
304 | |||
305 | mutex_init(&codec->mutex); | ||
306 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
307 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
308 | |||
309 | codec->private_data = ak4642; | ||
310 | codec->name = "AK4642"; | ||
311 | codec->owner = THIS_MODULE; | ||
312 | codec->read = ak4642_read_reg_cache; | ||
313 | codec->write = ak4642_write; | ||
314 | codec->dai = &ak4642_dai; | ||
315 | codec->num_dai = 1; | ||
316 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
317 | codec->reg_cache_size = ARRAY_SIZE(ak4642_reg); | ||
318 | codec->reg_cache = kmemdup(ak4642_reg, | ||
319 | sizeof(ak4642_reg), GFP_KERNEL); | ||
320 | |||
321 | if (!codec->reg_cache) | ||
322 | return -ENOMEM; | ||
323 | |||
324 | ak4642_dai.dev = codec->dev; | ||
325 | ak4642_codec = codec; | ||
326 | |||
327 | ret = snd_soc_register_codec(codec); | ||
328 | if (ret) { | ||
329 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
330 | goto reg_cache_err; | ||
331 | } | ||
332 | |||
333 | ret = snd_soc_register_dai(&ak4642_dai); | ||
334 | if (ret) { | ||
335 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
336 | snd_soc_unregister_codec(codec); | ||
337 | goto reg_cache_err; | ||
338 | } | ||
339 | |||
340 | /* | ||
341 | * clock setting | ||
342 | * | ||
343 | * Audio I/F Format: MSB justified (ADC & DAC) | ||
344 | * BICK frequency at Master Mode: 64fs | ||
345 | * Input Master Clock Select at PLL Mode: 11.2896MHz | ||
346 | * MCKO: Enable | ||
347 | * Sampling Frequency: 44.1kHz | ||
348 | * | ||
349 | * This operation came from example code of | ||
350 | * "ASAHI KASEI AK4642" (japanese) manual p89. | ||
351 | * | ||
352 | * please fix-me | ||
353 | */ | ||
354 | ak4642_write(codec, 0x01, 0x08); | ||
355 | ak4642_write(codec, 0x04, 0x4a); | ||
356 | ak4642_write(codec, 0x05, 0x27); | ||
357 | ak4642_write(codec, 0x00, 0x40); | ||
358 | ak4642_write(codec, 0x01, 0x0b); | ||
359 | |||
360 | return ret; | ||
361 | |||
362 | reg_cache_err: | ||
363 | kfree(codec->reg_cache); | ||
364 | codec->reg_cache = NULL; | ||
365 | |||
366 | return ret; | ||
367 | } | ||
368 | |||
369 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
370 | static int ak4642_i2c_probe(struct i2c_client *i2c, | ||
371 | const struct i2c_device_id *id) | ||
372 | { | ||
373 | struct ak4642_priv *ak4642; | ||
374 | struct snd_soc_codec *codec; | ||
375 | int ret; | ||
376 | |||
377 | ak4642 = kzalloc(sizeof(struct ak4642_priv), GFP_KERNEL); | ||
378 | if (!ak4642) | ||
379 | return -ENOMEM; | ||
380 | |||
381 | codec = &ak4642->codec; | ||
382 | codec->dev = &i2c->dev; | ||
383 | |||
384 | i2c_set_clientdata(i2c, ak4642); | ||
385 | codec->control_data = i2c; | ||
386 | |||
387 | ret = ak4642_init(ak4642); | ||
388 | if (ret < 0) | ||
389 | printk(KERN_ERR "failed to initialise AK4642\n"); | ||
390 | |||
391 | return ret; | ||
392 | } | ||
393 | |||
394 | static int ak4642_i2c_remove(struct i2c_client *client) | ||
395 | { | ||
396 | struct ak4642_priv *ak4642 = i2c_get_clientdata(client); | ||
397 | |||
398 | snd_soc_unregister_dai(&ak4642_dai); | ||
399 | snd_soc_unregister_codec(&ak4642->codec); | ||
400 | kfree(ak4642->codec.reg_cache); | ||
401 | kfree(ak4642); | ||
402 | ak4642_codec = NULL; | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static const struct i2c_device_id ak4642_i2c_id[] = { | ||
408 | { "ak4642", 0 }, | ||
409 | { "ak4643", 0 }, | ||
410 | { } | ||
411 | }; | ||
412 | MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id); | ||
413 | |||
414 | static struct i2c_driver ak4642_i2c_driver = { | ||
415 | .driver = { | ||
416 | .name = "AK4642 I2C Codec", | ||
417 | .owner = THIS_MODULE, | ||
418 | }, | ||
419 | .probe = ak4642_i2c_probe, | ||
420 | .remove = ak4642_i2c_remove, | ||
421 | .id_table = ak4642_i2c_id, | ||
422 | }; | ||
423 | |||
424 | #endif | ||
425 | |||
426 | static int ak4642_probe(struct platform_device *pdev) | ||
427 | { | ||
428 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
429 | int ret; | ||
430 | |||
431 | if (!ak4642_codec) { | ||
432 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
433 | return -ENODEV; | ||
434 | } | ||
435 | |||
436 | socdev->card->codec = ak4642_codec; | ||
437 | |||
438 | /* register pcms */ | ||
439 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
440 | if (ret < 0) { | ||
441 | printk(KERN_ERR "ak4642: failed to create pcms\n"); | ||
442 | goto pcm_err; | ||
443 | } | ||
444 | |||
445 | ret = snd_soc_init_card(socdev); | ||
446 | if (ret < 0) { | ||
447 | printk(KERN_ERR "ak4642: failed to register card\n"); | ||
448 | goto card_err; | ||
449 | } | ||
450 | |||
451 | dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION); | ||
452 | return ret; | ||
453 | |||
454 | card_err: | ||
455 | snd_soc_free_pcms(socdev); | ||
456 | snd_soc_dapm_free(socdev); | ||
457 | pcm_err: | ||
458 | return ret; | ||
459 | |||
460 | } | ||
461 | |||
462 | /* power down chip */ | ||
463 | static int ak4642_remove(struct platform_device *pdev) | ||
464 | { | ||
465 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
466 | |||
467 | snd_soc_free_pcms(socdev); | ||
468 | snd_soc_dapm_free(socdev); | ||
469 | |||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | struct snd_soc_codec_device soc_codec_dev_ak4642 = { | ||
474 | .probe = ak4642_probe, | ||
475 | .remove = ak4642_remove, | ||
476 | .resume = ak4642_resume, | ||
477 | }; | ||
478 | EXPORT_SYMBOL_GPL(soc_codec_dev_ak4642); | ||
479 | |||
480 | static int __init ak4642_modinit(void) | ||
481 | { | ||
482 | int ret; | ||
483 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
484 | ret = i2c_add_driver(&ak4642_i2c_driver); | ||
485 | #endif | ||
486 | return ret; | ||
487 | |||
488 | } | ||
489 | module_init(ak4642_modinit); | ||
490 | |||
491 | static void __exit ak4642_exit(void) | ||
492 | { | ||
493 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
494 | i2c_del_driver(&ak4642_i2c_driver); | ||
495 | #endif | ||
496 | |||
497 | } | ||
498 | module_exit(ak4642_exit); | ||
499 | |||
500 | MODULE_DESCRIPTION("Soc AK4642 driver"); | ||
501 | MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>"); | ||
502 | MODULE_LICENSE("GPL"); | ||