aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs
diff options
context:
space:
mode:
authorKuninori Morimoto <morimoto.kuninori@renesas.com>2009-08-20 21:23:41 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-08-21 05:54:02 -0400
commita3a83d9a7cb0ce3b1d100060d5ad777e7480b4f2 (patch)
tree2a54acafb3ceb482c9a7c6030940b2db4cc7c3b7 /sound/soc/codecs
parentb2ec22e2633996727f4f2abcd806aaeb0506dd6a (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')
-rw-r--r--sound/soc/codecs/Kconfig4
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/ak4642.c502
-rw-r--r--sound/soc/codecs/ak4642.h20
4 files changed, 528 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 167a5ce06cdf..0edca93af3b0 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -18,6 +18,7 @@ config SND_SOC_ALL_CODECS
18 select SND_SOC_AD73311 if I2C 18 select SND_SOC_AD73311 if I2C
19 select SND_SOC_AK4104 if SPI_MASTER 19 select SND_SOC_AK4104 if SPI_MASTER
20 select SND_SOC_AK4535 if I2C 20 select SND_SOC_AK4535 if I2C
21 select SND_SOC_AK4642 if I2C
21 select SND_SOC_CS4270 if I2C 22 select SND_SOC_CS4270 if I2C
22 select SND_SOC_MAX9877 if I2C 23 select SND_SOC_MAX9877 if I2C
23 select SND_SOC_PCM3008 24 select SND_SOC_PCM3008
@@ -92,6 +93,9 @@ config SND_SOC_AK4104
92config SND_SOC_AK4535 93config SND_SOC_AK4535
93 tristate 94 tristate
94 95
96config SND_SOC_AK4642
97 tristate
98
95# Cirrus Logic CS4270 Codec 99# Cirrus Logic CS4270 Codec
96config SND_SOC_CS4270 100config SND_SOC_CS4270
97 tristate 101 tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index fbab43bbe3a7..fb4af28486ba 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -5,6 +5,7 @@ snd-soc-ad1980-objs := ad1980.o
5snd-soc-ad73311-objs := ad73311.o 5snd-soc-ad73311-objs := ad73311.o
6snd-soc-ak4104-objs := ak4104.o 6snd-soc-ak4104-objs := ak4104.o
7snd-soc-ak4535-objs := ak4535.o 7snd-soc-ak4535-objs := ak4535.o
8snd-soc-ak4642-objs := ak4642.o
8snd-soc-cs4270-objs := cs4270.o 9snd-soc-cs4270-objs := cs4270.o
9snd-soc-cx20442-objs := cx20442.o 10snd-soc-cx20442-objs := cx20442.o
10snd-soc-l3-objs := l3.o 11snd-soc-l3-objs := l3.o
@@ -54,6 +55,7 @@ obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
54obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o 55obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
55obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o 56obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
56obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o 57obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
58obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
57obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o 59obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
58obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o 60obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
59obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o 61obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
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
83struct snd_soc_codec_device soc_codec_dev_ak4642;
84
85/* codec private data */
86struct ak4642_priv {
87 struct snd_soc_codec codec;
88 unsigned int sysclk;
89};
90
91static struct snd_soc_codec *ak4642_codec;
92
93/*
94 * ak4642 register cache
95 */
96static 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 */
112static 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 */
124static 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 */
137static 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
156static 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
167static 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
227static 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
248static 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
258static 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
264struct 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};
280EXPORT_SYMBOL_GPL(ak4642_dai);
281
282static 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 */
295static 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
362reg_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)
370static 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
394static 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
407static const struct i2c_device_id ak4642_i2c_id[] = {
408 { "ak4642", 0 },
409 { "ak4643", 0 },
410 { }
411};
412MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
413
414static 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
426static 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
454card_err:
455 snd_soc_free_pcms(socdev);
456 snd_soc_dapm_free(socdev);
457pcm_err:
458 return ret;
459
460}
461
462/* power down chip */
463static 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
473struct snd_soc_codec_device soc_codec_dev_ak4642 = {
474 .probe = ak4642_probe,
475 .remove = ak4642_remove,
476 .resume = ak4642_resume,
477};
478EXPORT_SYMBOL_GPL(soc_codec_dev_ak4642);
479
480static 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}
489module_init(ak4642_modinit);
490
491static 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}
498module_exit(ak4642_exit);
499
500MODULE_DESCRIPTION("Soc AK4642 driver");
501MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
502MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ak4642.h b/sound/soc/codecs/ak4642.h
new file mode 100644
index 000000000000..e476833d314e
--- /dev/null
+++ b/sound/soc/codecs/ak4642.h
@@ -0,0 +1,20 @@
1/*
2 * ak4642.h -- AK4642 Soc Audio driver
3 *
4 * Copyright (C) 2009 Renesas Solutions Corp.
5 * Kuninori Morimoto <morimoto.kuninori@renesas.com>
6 *
7 * Based on ak4535.c
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#ifndef _AK4642_H
15#define _AK4642_H
16
17extern struct snd_soc_dai ak4642_dai;
18extern struct snd_soc_codec_device soc_codec_dev_ak4642;
19
20#endif