2 * ak4642.c -- AK4642/AK4643 ALSA Soc Audio driver
4 * Copyright (C) 2009 Renesas Solutions Corp.
5 * Kuninori Morimoto <morimoto.kuninori@renesas.com>
7 * Based on wm8731.c by Richard Purdie
8 * Based on ak4535.c by Richard Purdie
9 * Based on wm8753.c by Liam Girdwood
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.
18 * This is very simple driver.
19 * It can use headphone output / stereo input only
21 * AK4642 is not tested.
25 #include <linux/delay.h>
26 #include <linux/i2c.h>
27 #include <linux/platform_device.h>
28 #include <linux/slab.h>
29 #include <sound/soc-dapm.h>
30 #include <sound/initval.h>
31 #include <sound/tlv.h>
35 #define AK4642_VERSION "0.0.1"
75 #define AK4642_CACHEREGNUM 0x25
78 #define HPMTN (1 << 6)
79 #define PMHPL (1 << 5)
80 #define PMHPR (1 << 4)
81 #define MS (1 << 3) /* master/slave select */
83 #define PMPLL (1 << 0)
85 #define PMHP_MASK (PMHPL | PMHPR)
86 #define PMHP PMHP_MASK
93 #define PLL_MASK (PLL3 | PLL2 | PLL1 | PLL0)
95 #define BCKO_MASK (1 << 3)
96 #define BCKO_64 BCKO_MASK
103 #define FS_MASK (FS0 | FS1 | FS2 | FS3)
105 struct snd_soc_codec_device soc_codec_dev_ak4642;
108 * Playback Volume (table 39)
110 * max : 0x00 : +12.0 dB
112 * min : 0xFE : -115.0 dB
115 static const DECLARE_TLV_DB_SCALE(out_tlv, -11500, 50, 1);
117 static const struct snd_kcontrol_new ak4642_snd_controls[] = {
119 SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC,
120 0, 0xFF, 1, out_tlv),
124 /* codec private data */
126 struct snd_soc_codec codec;
129 static struct snd_soc_codec *ak4642_codec;
132 * ak4642 register cache
134 static const u16 ak4642_reg[AK4642_CACHEREGNUM] = {
135 0x0000, 0x0000, 0x0001, 0x0000,
136 0x0002, 0x0000, 0x0000, 0x0000,
137 0x00e1, 0x00e1, 0x0018, 0x0000,
138 0x00e1, 0x0018, 0x0011, 0x0008,
139 0x0000, 0x0000, 0x0000, 0x0000,
140 0x0000, 0x0000, 0x0000, 0x0000,
141 0x0000, 0x0000, 0x0000, 0x0000,
142 0x0000, 0x0000, 0x0000, 0x0000,
143 0x0000, 0x0000, 0x0000, 0x0000,
148 * read ak4642 register cache
150 static inline unsigned int ak4642_read_reg_cache(struct snd_soc_codec *codec,
153 u16 *cache = codec->reg_cache;
154 if (reg >= AK4642_CACHEREGNUM)
160 * write ak4642 register cache
162 static inline void ak4642_write_reg_cache(struct snd_soc_codec *codec,
163 u16 reg, unsigned int value)
165 u16 *cache = codec->reg_cache;
166 if (reg >= AK4642_CACHEREGNUM)
173 * write to the AK4642 register space
175 static int ak4642_write(struct snd_soc_codec *codec, unsigned int reg,
181 * D15..D8 AK4642 register offset
182 * D7...D0 register data
184 data[0] = reg & 0xff;
185 data[1] = value & 0xff;
187 if (codec->hw_write(codec->control_data, data, 2) == 2) {
188 ak4642_write_reg_cache(codec, reg, value);
194 static int ak4642_sync(struct snd_soc_codec *codec)
196 u16 *cache = codec->reg_cache;
199 for (i = 0; i < AK4642_CACHEREGNUM; i++)
200 r |= ak4642_write(codec, i, cache[i]);
205 static int ak4642_dai_startup(struct snd_pcm_substream *substream,
206 struct snd_soc_dai *dai)
208 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
209 struct snd_soc_codec *codec = dai->codec;
213 * start headphone output
216 * Audio I/F Format :MSB justified (ADC & DAC)
217 * Bass Boost Level : Middle
219 * This operation came from example code of
220 * "ASAHI KASEI AK4642" (japanese) manual p97.
222 ak4642_write(codec, 0x0f, 0x09);
223 ak4642_write(codec, 0x0e, 0x19);
224 ak4642_write(codec, 0x09, 0x91);
225 ak4642_write(codec, 0x0c, 0x91);
226 ak4642_write(codec, 0x00, 0x64);
227 snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP);
228 snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN);
234 * Audio I/F Format:MSB justified (ADC & DAC)
237 * ALC setting:Refer to Table 35
240 * This operation came from example code of
241 * "ASAHI KASEI AK4642" (japanese) manual p94.
243 ak4642_write(codec, 0x02, 0x05);
244 ak4642_write(codec, 0x06, 0x3c);
245 ak4642_write(codec, 0x08, 0xe1);
246 ak4642_write(codec, 0x0b, 0x00);
247 ak4642_write(codec, 0x07, 0x21);
248 ak4642_write(codec, 0x00, 0x41);
249 ak4642_write(codec, 0x10, 0x01);
255 static void ak4642_dai_shutdown(struct snd_pcm_substream *substream,
256 struct snd_soc_dai *dai)
258 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
259 struct snd_soc_codec *codec = dai->codec;
262 /* stop headphone output */
263 snd_soc_update_bits(codec, PW_MGMT2, HPMTN, 0);
264 snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, 0);
265 ak4642_write(codec, 0x00, 0x40);
266 ak4642_write(codec, 0x0e, 0x11);
267 ak4642_write(codec, 0x0f, 0x08);
269 /* stop stereo input */
270 ak4642_write(codec, 0x00, 0x40);
271 ak4642_write(codec, 0x10, 0x00);
272 ak4642_write(codec, 0x07, 0x01);
276 static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai,
277 int clk_id, unsigned int freq, int dir)
279 struct snd_soc_codec *codec = codec_dai->codec;
293 pll = PLL2 | PLL1 | PLL0;
299 pll = PLL3 | PLL2 | PLL0;
304 snd_soc_update_bits(codec, MD_CTL1, PLL_MASK, pll);
309 static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
311 struct snd_soc_codec *codec = dai->codec;
315 data = MCKO | PMPLL; /* use MCKO */
318 /* set master/slave audio interface */
319 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
320 case SND_SOC_DAIFMT_CBM_CFM:
324 case SND_SOC_DAIFMT_CBS_CFS:
329 snd_soc_update_bits(codec, PW_MGMT2, MS, data);
330 snd_soc_update_bits(codec, MD_CTL1, BCKO_MASK, bcko);
335 static int ak4642_dai_hw_params(struct snd_pcm_substream *substream,
336 struct snd_pcm_hw_params *params,
337 struct snd_soc_dai *dai)
339 struct snd_soc_codec *codec = dai->codec;
342 switch (params_rate(params)) {
362 rate = FS2 | FS1 | FS0;
368 rate = FS3 | FS2 | FS1;
374 rate = FS3 | FS2 | FS1 | FS0;
377 rate = FS3 | FS1 | FS0;
383 snd_soc_update_bits(codec, MD_CTL2, FS_MASK, rate);
388 static struct snd_soc_dai_ops ak4642_dai_ops = {
389 .startup = ak4642_dai_startup,
390 .shutdown = ak4642_dai_shutdown,
391 .set_sysclk = ak4642_dai_set_sysclk,
392 .set_fmt = ak4642_dai_set_fmt,
393 .hw_params = ak4642_dai_hw_params,
396 struct snd_soc_dai ak4642_dai = {
399 .stream_name = "Playback",
402 .rates = SNDRV_PCM_RATE_8000_48000,
403 .formats = SNDRV_PCM_FMTBIT_S16_LE },
405 .stream_name = "Capture",
408 .rates = SNDRV_PCM_RATE_8000_48000,
409 .formats = SNDRV_PCM_FMTBIT_S16_LE },
410 .ops = &ak4642_dai_ops,
411 .symmetric_rates = 1,
413 EXPORT_SYMBOL_GPL(ak4642_dai);
415 static int ak4642_resume(struct platform_device *pdev)
417 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
418 struct snd_soc_codec *codec = socdev->card->codec;
425 * initialise the AK4642 driver
426 * register the mixer and dsp interfaces with the kernel
428 static int ak4642_init(struct ak4642_priv *ak4642)
430 struct snd_soc_codec *codec = &ak4642->codec;
434 dev_err(codec->dev, "Another ak4642 is registered\n");
438 mutex_init(&codec->mutex);
439 INIT_LIST_HEAD(&codec->dapm_widgets);
440 INIT_LIST_HEAD(&codec->dapm_paths);
442 snd_soc_codec_set_drvdata(codec, ak4642);
443 codec->name = "AK4642";
444 codec->owner = THIS_MODULE;
445 codec->read = ak4642_read_reg_cache;
446 codec->write = ak4642_write;
447 codec->dai = &ak4642_dai;
449 codec->hw_write = (hw_write_t)i2c_master_send;
450 codec->reg_cache_size = ARRAY_SIZE(ak4642_reg);
451 codec->reg_cache = kmemdup(ak4642_reg,
452 sizeof(ak4642_reg), GFP_KERNEL);
454 if (!codec->reg_cache)
457 ak4642_dai.dev = codec->dev;
458 ak4642_codec = codec;
460 ret = snd_soc_register_codec(codec);
462 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
466 ret = snd_soc_register_dai(&ak4642_dai);
468 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
469 snd_soc_unregister_codec(codec);
476 kfree(codec->reg_cache);
477 codec->reg_cache = NULL;
482 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
483 static int ak4642_i2c_probe(struct i2c_client *i2c,
484 const struct i2c_device_id *id)
486 struct ak4642_priv *ak4642;
487 struct snd_soc_codec *codec;
490 ak4642 = kzalloc(sizeof(struct ak4642_priv), GFP_KERNEL);
494 codec = &ak4642->codec;
495 codec->dev = &i2c->dev;
497 i2c_set_clientdata(i2c, ak4642);
498 codec->control_data = i2c;
500 ret = ak4642_init(ak4642);
502 printk(KERN_ERR "failed to initialise AK4642\n");
509 static int ak4642_i2c_remove(struct i2c_client *client)
511 struct ak4642_priv *ak4642 = i2c_get_clientdata(client);
513 snd_soc_unregister_dai(&ak4642_dai);
514 snd_soc_unregister_codec(&ak4642->codec);
515 kfree(ak4642->codec.reg_cache);
522 static const struct i2c_device_id ak4642_i2c_id[] = {
527 MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
529 static struct i2c_driver ak4642_i2c_driver = {
531 .name = "AK4642 I2C Codec",
532 .owner = THIS_MODULE,
534 .probe = ak4642_i2c_probe,
535 .remove = ak4642_i2c_remove,
536 .id_table = ak4642_i2c_id,
541 static int ak4642_probe(struct platform_device *pdev)
543 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
547 dev_err(&pdev->dev, "Codec device not registered\n");
551 socdev->card->codec = ak4642_codec;
554 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
556 printk(KERN_ERR "ak4642: failed to create pcms\n");
560 snd_soc_add_controls(ak4642_codec, ak4642_snd_controls,
561 ARRAY_SIZE(ak4642_snd_controls));
563 dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
571 /* power down chip */
572 static int ak4642_remove(struct platform_device *pdev)
574 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
576 snd_soc_free_pcms(socdev);
577 snd_soc_dapm_free(socdev);
582 struct snd_soc_codec_device soc_codec_dev_ak4642 = {
583 .probe = ak4642_probe,
584 .remove = ak4642_remove,
585 .resume = ak4642_resume,
587 EXPORT_SYMBOL_GPL(soc_codec_dev_ak4642);
589 static int __init ak4642_modinit(void)
592 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
593 ret = i2c_add_driver(&ak4642_i2c_driver);
598 module_init(ak4642_modinit);
600 static void __exit ak4642_exit(void)
602 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
603 i2c_del_driver(&ak4642_i2c_driver);
607 module_exit(ak4642_exit);
609 MODULE_DESCRIPTION("Soc AK4642 driver");
610 MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
611 MODULE_LICENSE("GPL");