diff options
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r-- | sound/soc/codecs/Kconfig | 8 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 4 | ||||
-rw-r--r-- | sound/soc/codecs/ad1836.c | 1 | ||||
-rw-r--r-- | sound/soc/codecs/ad1938.c | 1 | ||||
-rw-r--r-- | sound/soc/codecs/ak4642.c | 502 | ||||
-rw-r--r-- | sound/soc/codecs/ak4642.h | 20 | ||||
-rw-r--r-- | sound/soc/codecs/ak4671.c | 825 | ||||
-rw-r--r-- | sound/soc/codecs/ak4671.h | 156 | ||||
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.c | 222 | ||||
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.h | 2 | ||||
-rw-r--r-- | sound/soc/codecs/wm8350.c | 13 | ||||
-rw-r--r-- | sound/soc/codecs/wm8400.c | 3 | ||||
-rw-r--r-- | sound/soc/codecs/wm8510.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/wm8580.c | 8 | ||||
-rw-r--r-- | sound/soc/codecs/wm8753.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/wm8900.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/wm8940.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/wm8960.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/wm8974.c | 5 | ||||
-rw-r--r-- | sound/soc/codecs/wm8990.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/wm8993.c | 90 | ||||
-rw-r--r-- | sound/soc/codecs/wm9705.c | 2 | ||||
-rw-r--r-- | sound/soc/codecs/wm9713.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/wm_hubs.c | 19 |
24 files changed, 1752 insertions, 157 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 20ebf7437f9..3c46f34928e 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -18,6 +18,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_AD73311 if I2C select SND_SOC_AK4104 if SPI_MASTER select SND_SOC_AK4535 if I2C + select SND_SOC_AK4642 if I2C + select SND_SOC_AK4671 if I2C select SND_SOC_CS4270 if I2C select SND_SOC_MAX9877 if I2C select SND_SOC_PCM3008 @@ -93,6 +95,12 @@ config SND_SOC_AK4104 config SND_SOC_AK4535 tristate +config SND_SOC_AK4642 + tristate + +config SND_SOC_AK4671 + tristate + # Cirrus Logic CS4270 Codec config SND_SOC_CS4270 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 711d8f5887d..fc1c458cbe2 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -5,6 +5,8 @@ snd-soc-ad1980-objs := ad1980.o snd-soc-ad73311-objs := ad73311.o snd-soc-ak4104-objs := ak4104.o snd-soc-ak4535-objs := ak4535.o +snd-soc-ak4642-objs := ak4642.o +snd-soc-ak4671-objs := ak4671.o snd-soc-cs4270-objs := cs4270.o snd-soc-cx20442-objs := cx20442.o snd-soc-l3-objs := l3.o @@ -55,6 +57,8 @@ obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o +obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o +obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 3612bb92df9..01343dc984f 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -18,7 +18,6 @@ #include <linux/init.h> #include <linux/module.h> -#include <linux/version.h> #include <linux/kernel.h> #include <linux/device.h> #include <sound/core.h> diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index e62b27701a4..9a049a1995a 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c @@ -28,7 +28,6 @@ #include <linux/init.h> #include <linux/module.h> -#include <linux/version.h> #include <linux/kernel.h> #include <linux/device.h> #include <sound/core.h> diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c new file mode 100644 index 00000000000..e057c7b578d --- /dev/null +++ b/sound/soc/codecs/ak4642.c @@ -0,0 +1,502 @@ +/* + * ak4642.c -- AK4642/AK4643 ALSA Soc Audio driver + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Kuninori Morimoto <morimoto.kuninori@renesas.com> + * + * Based on wm8731.c by Richard Purdie + * Based on ak4535.c by Richard Purdie + * Based on wm8753.c by Liam Girdwood + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* ** CAUTION ** + * + * This is very simple driver. + * It can use headphone output / stereo input only + * + * AK4642 is not tested. + * AK4643 is tested. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> + +#include "ak4642.h" + +#define AK4642_VERSION "0.0.1" + +#define PW_MGMT1 0x00 +#define PW_MGMT2 0x01 +#define SG_SL1 0x02 +#define SG_SL2 0x03 +#define MD_CTL1 0x04 +#define MD_CTL2 0x05 +#define TIMER 0x06 +#define ALC_CTL1 0x07 +#define ALC_CTL2 0x08 +#define L_IVC 0x09 +#define L_DVC 0x0a +#define ALC_CTL3 0x0b +#define R_IVC 0x0c +#define R_DVC 0x0d +#define MD_CTL3 0x0e +#define MD_CTL4 0x0f +#define PW_MGMT3 0x10 +#define DF_S 0x11 +#define FIL3_0 0x12 +#define FIL3_1 0x13 +#define FIL3_2 0x14 +#define FIL3_3 0x15 +#define EQ_0 0x16 +#define EQ_1 0x17 +#define EQ_2 0x18 +#define EQ_3 0x19 +#define EQ_4 0x1a +#define EQ_5 0x1b +#define FIL1_0 0x1c +#define FIL1_1 0x1d +#define FIL1_2 0x1e +#define FIL1_3 0x1f +#define PW_MGMT4 0x20 +#define MD_CTL5 0x21 +#define LO_MS 0x22 +#define HP_MS 0x23 +#define SPK_MS 0x24 + +#define AK4642_CACHEREGNUM 0x25 + +struct snd_soc_codec_device soc_codec_dev_ak4642; + +/* codec private data */ +struct ak4642_priv { + struct snd_soc_codec codec; + unsigned int sysclk; +}; + +static struct snd_soc_codec *ak4642_codec; + +/* + * ak4642 register cache + */ +static const u16 ak4642_reg[AK4642_CACHEREGNUM] = { + 0x0000, 0x0000, 0x0001, 0x0000, + 0x0002, 0x0000, 0x0000, 0x0000, + 0x00e1, 0x00e1, 0x0018, 0x0000, + 0x00e1, 0x0018, 0x0011, 0x0008, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, +}; + +/* + * read ak4642 register cache + */ +static inline unsigned int ak4642_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg >= AK4642_CACHEREGNUM) + return -1; + return cache[reg]; +} + +/* + * write ak4642 register cache + */ +static inline void ak4642_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg >= AK4642_CACHEREGNUM) + return; + + cache[reg] = value; +} + +/* + * write to the AK4642 register space + */ +static int ak4642_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D8 AK4642 register offset + * D7...D0 register data + */ + data[0] = reg & 0xff; + data[1] = value & 0xff; + + if (codec->hw_write(codec->control_data, data, 2) == 2) { + ak4642_write_reg_cache(codec, reg, value); + return 0; + } else + return -EIO; +} + +static int ak4642_sync(struct snd_soc_codec *codec) +{ + u16 *cache = codec->reg_cache; + int i, r = 0; + + for (i = 0; i < AK4642_CACHEREGNUM; i++) + r |= ak4642_write(codec, i, cache[i]); + + return r; +}; + +static int ak4642_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + struct snd_soc_codec *codec = dai->codec; + + if (is_play) { + /* + * start headphone output + * + * PLL, Master Mode + * Audio I/F Format :MSB justified (ADC & DAC) + * Sampling Frequency: 44.1kHz + * Digital Volume: −8dB + * Bass Boost Level : Middle + * + * This operation came from example code of + * "ASAHI KASEI AK4642" (japanese) manual p97. + * + * Example code use 0x39, 0x79 value for 0x01 address, + * But we need MCKO (0x02) bit now + */ + ak4642_write(codec, 0x05, 0x27); + ak4642_write(codec, 0x0f, 0x09); + ak4642_write(codec, 0x0e, 0x19); + ak4642_write(codec, 0x09, 0x91); + ak4642_write(codec, 0x0c, 0x91); + ak4642_write(codec, 0x0a, 0x28); + ak4642_write(codec, 0x0d, 0x28); + ak4642_write(codec, 0x00, 0x64); + ak4642_write(codec, 0x01, 0x3b); /* + MCKO bit */ + ak4642_write(codec, 0x01, 0x7b); /* + MCKO bit */ + } else { + /* + * start stereo input + * + * PLL Master Mode + * Audio I/F Format:MSB justified (ADC & DAC) + * Sampling Frequency:44.1kHz + * Pre MIC AMP:+20dB + * MIC Power On + * ALC setting:Refer to Table 35 + * ALC bit=“1” + * + * This operation came from example code of + * "ASAHI KASEI AK4642" (japanese) manual p94. + */ + ak4642_write(codec, 0x05, 0x27); + ak4642_write(codec, 0x02, 0x05); + ak4642_write(codec, 0x06, 0x3c); + ak4642_write(codec, 0x08, 0xe1); + ak4642_write(codec, 0x0b, 0x00); + ak4642_write(codec, 0x07, 0x21); + ak4642_write(codec, 0x00, 0x41); + ak4642_write(codec, 0x10, 0x01); + } + + return 0; +} + +static void ak4642_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + struct snd_soc_codec *codec = dai->codec; + + if (is_play) { + /* stop headphone output */ + ak4642_write(codec, 0x01, 0x3b); + ak4642_write(codec, 0x01, 0x0b); + ak4642_write(codec, 0x00, 0x40); + ak4642_write(codec, 0x0e, 0x11); + ak4642_write(codec, 0x0f, 0x08); + } else { + /* stop stereo input */ + ak4642_write(codec, 0x00, 0x40); + ak4642_write(codec, 0x10, 0x00); + ak4642_write(codec, 0x07, 0x01); + } +} + +static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct ak4642_priv *ak4642 = codec->private_data; + + ak4642->sysclk = freq; + return 0; +} + +static struct snd_soc_dai_ops ak4642_dai_ops = { + .startup = ak4642_dai_startup, + .shutdown = ak4642_dai_shutdown, + .set_sysclk = ak4642_dai_set_sysclk, +}; + +struct snd_soc_dai ak4642_dai = { + .name = "AK4642", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE }, + .ops = &ak4642_dai_ops, +}; +EXPORT_SYMBOL_GPL(ak4642_dai); + +static int ak4642_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + ak4642_sync(codec); + return 0; +} + +/* + * initialise the AK4642 driver + * register the mixer and dsp interfaces with the kernel + */ +static int ak4642_init(struct ak4642_priv *ak4642) +{ + struct snd_soc_codec *codec = &ak4642->codec; + int ret = 0; + + if (ak4642_codec) { + dev_err(codec->dev, "Another ak4642 is registered\n"); + return -EINVAL; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = ak4642; + codec->name = "AK4642"; + codec->owner = THIS_MODULE; + codec->read = ak4642_read_reg_cache; + codec->write = ak4642_write; + codec->dai = &ak4642_dai; + codec->num_dai = 1; + codec->hw_write = (hw_write_t)i2c_master_send; + codec->reg_cache_size = ARRAY_SIZE(ak4642_reg); + codec->reg_cache = kmemdup(ak4642_reg, + sizeof(ak4642_reg), GFP_KERNEL); + + if (!codec->reg_cache) + return -ENOMEM; + + ak4642_dai.dev = codec->dev; + ak4642_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + goto reg_cache_err; + } + + ret = snd_soc_register_dai(&ak4642_dai); + if (ret) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + snd_soc_unregister_codec(codec); + goto reg_cache_err; + } + + /* + * clock setting + * + * Audio I/F Format: MSB justified (ADC & DAC) + * BICK frequency at Master Mode: 64fs + * Input Master Clock Select at PLL Mode: 11.2896MHz + * MCKO: Enable + * Sampling Frequency: 44.1kHz + * + * This operation came from example code of + * "ASAHI KASEI AK4642" (japanese) manual p89. + * + * please fix-me + */ + ak4642_write(codec, 0x01, 0x08); + ak4642_write(codec, 0x04, 0x4a); + ak4642_write(codec, 0x05, 0x27); + ak4642_write(codec, 0x00, 0x40); + ak4642_write(codec, 0x01, 0x0b); + + return ret; + +reg_cache_err: + kfree(codec->reg_cache); + codec->reg_cache = NULL; + + return ret; +} + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +static int ak4642_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct ak4642_priv *ak4642; + struct snd_soc_codec *codec; + int ret; + + ak4642 = kzalloc(sizeof(struct ak4642_priv), GFP_KERNEL); + if (!ak4642) + return -ENOMEM; + + codec = &ak4642->codec; + codec->dev = &i2c->dev; + + i2c_set_clientdata(i2c, ak4642); + codec->control_data = i2c; + + ret = ak4642_init(ak4642); + if (ret < 0) + printk(KERN_ERR "failed to initialise AK4642\n"); + + return ret; +} + +static int ak4642_i2c_remove(struct i2c_client *client) +{ + struct ak4642_priv *ak4642 = i2c_get_clientdata(client); + + snd_soc_unregister_dai(&ak4642_dai); + snd_soc_unregister_codec(&ak4642->codec); + kfree(ak4642->codec.reg_cache); + kfree(ak4642); + ak4642_codec = NULL; + + return 0; +} + +static const struct i2c_device_id ak4642_i2c_id[] = { + { "ak4642", 0 }, + { "ak4643", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id); + +static struct i2c_driver ak4642_i2c_driver = { + .driver = { + .name = "AK4642 I2C Codec", + .owner = THIS_MODULE, + }, + .probe = ak4642_i2c_probe, + .remove = ak4642_i2c_remove, + .id_table = ak4642_i2c_id, +}; + +#endif + +static int ak4642_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + int ret; + + if (!ak4642_codec) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = ak4642_codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "ak4642: failed to create pcms\n"); + goto pcm_err; + } + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + printk(KERN_ERR "ak4642: failed to register card\n"); + goto card_err; + } + + dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION); + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + return ret; + +} + +/* power down chip */ +static int ak4642_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_ak4642 = { + .probe = ak4642_probe, + .remove = ak4642_remove, + .resume = ak4642_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_ak4642); + +static int __init ak4642_modinit(void) +{ + int ret; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + ret = i2c_add_driver(&ak4642_i2c_driver); +#endif + return ret; + +} +module_init(ak4642_modinit); + +static void __exit ak4642_exit(void) +{ +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&ak4642_i2c_driver); +#endif + +} +module_exit(ak4642_exit); + +MODULE_DESCRIPTION("Soc AK4642 driver"); +MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ak4642.h b/sound/soc/codecs/ak4642.h new file mode 100644 index 00000000000..e476833d314 --- /dev/null +++ b/sound/soc/codecs/ak4642.h @@ -0,0 +1,20 @@ +/* + * ak4642.h -- AK4642 Soc Audio driver + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Kuninori Morimoto <morimoto.kuninori@renesas.com> + * + * Based on ak4535.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _AK4642_H +#define _AK4642_H + +extern struct snd_soc_dai ak4642_dai; +extern struct snd_soc_codec_device soc_codec_dev_ak4642; + +#endif diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c new file mode 100644 index 00000000000..b61214d1c5d --- /dev/null +++ b/sound/soc/codecs/ak4671.c @@ -0,0 +1,825 @@ +/* + * ak4671.c -- audio driver for AK4671 + * + * Copyright (C) 2009 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim <jy0922.shim@samsung.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "ak4671.h" + +static struct snd_soc_codec *ak4671_codec; + +/* codec private data */ +struct ak4671_priv { + struct snd_soc_codec codec; + u8 reg_cache[AK4671_CACHEREGNUM]; +}; + +/* ak4671 register cache & default register settings */ +static const u8 ak4671_reg[AK4671_CACHEREGNUM] = { + 0x00, /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) */ + 0xf6, /* AK4671_PLL_MODE_SELECT0 (0x01) */ + 0x00, /* AK4671_PLL_MODE_SELECT1 (0x02) */ + 0x02, /* AK4671_FORMAT_SELECT (0x03) */ + 0x00, /* AK4671_MIC_SIGNAL_SELECT (0x04) */ + 0x55, /* AK4671_MIC_AMP_GAIN (0x05) */ + 0x00, /* AK4671_MIXING_POWER_MANAGEMENT0 (0x06) */ + 0x00, /* AK4671_MIXING_POWER_MANAGEMENT1 (0x07) */ + 0xb5, /* AK4671_OUTPUT_VOLUME_CONTROL (0x08) */ + 0x00, /* AK4671_LOUT1_SIGNAL_SELECT (0x09) */ + 0x00, /* AK4671_ROUT1_SIGNAL_SELECT (0x0a) */ + 0x00, /* AK4671_LOUT2_SIGNAL_SELECT (0x0b) */ + 0x00, /* AK4671_ROUT2_SIGNAL_SELECT (0x0c) */ + 0x00, /* AK4671_LOUT3_SIGNAL_SELECT (0x0d) */ + 0x00, /* AK4671_ROUT3_SIGNAL_SELECT (0x0e) */ + 0x00, /* AK4671_LOUT1_POWER_MANAGERMENT (0x0f) */ + 0x00, /* AK4671_LOUT2_POWER_MANAGERMENT (0x10) */ + 0x80, /* AK4671_LOUT3_POWER_MANAGERMENT (0x11) */ + 0x91, /* AK4671_LCH_INPUT_VOLUME_CONTROL (0x12) */ + 0x91, /* AK4671_RCH_INPUT_VOLUME_CONTROL (0x13) */ + 0xe1, /* AK4671_ALC_REFERENCE_SELECT (0x14) */ + 0x00, /* AK4671_DIGITAL_MIXING_CONTROL (0x15) */ + 0x00, /* AK4671_ALC_TIMER_SELECT (0x16) */ + 0x00, /* AK4671_ALC_MODE_CONTROL (0x17) */ + 0x02, /* AK4671_MODE_CONTROL1 (0x18) */ + 0x01, /* AK4671_MODE_CONTROL2 (0x19) */ + 0x18, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL (0x1a) */ + 0x18, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL (0x1b) */ + 0x00, /* AK4671_SIDETONE_A_CONTROL (0x1c) */ + 0x02, /* AK4671_DIGITAL_FILTER_SELECT (0x1d) */ + 0x00, /* AK4671_FIL3_COEFFICIENT0 (0x1e) */ + 0x00, /* AK4671_FIL3_COEFFICIENT1 (0x1f) */ + 0x00, /* AK4671_FIL3_COEFFICIENT2 (0x20) */ + 0x00, /* AK4671_FIL3_COEFFICIENT3 (0x21) */ + 0x00, /* AK4671_EQ_COEFFICIENT0 (0x22) */ + 0x00, /* AK4671_EQ_COEFFICIENT1 (0x23) */ + 0x00, /* AK4671_EQ_COEFFICIENT2 (0x24) */ + 0x00, /* AK4671_EQ_COEFFICIENT3 (0x25) */ + 0x00, /* AK4671_EQ_COEFFICIENT4 (0x26) */ + 0x00, /* AK4671_EQ_COEFFICIENT5 (0x27) */ + 0xa9, /* AK4671_FIL1_COEFFICIENT0 (0x28) */ + 0x1f, /* AK4671_FIL1_COEFFICIENT1 (0x29) */ + 0xad, /* AK4671_FIL1_COEFFICIENT2 (0x2a) */ + 0x20, /* AK4671_FIL1_COEFFICIENT3 (0x2b) */ + 0x00, /* AK4671_FIL2_COEFFICIENT0 (0x2c) */ + 0x00, /* AK4671_FIL2_COEFFICIENT1 (0x2d) */ + 0x00, /* AK4671_FIL2_COEFFICIENT2 (0x2e) */ + 0x00, /* AK4671_FIL2_COEFFICIENT3 (0x2f) */ + 0x00, /* AK4671_DIGITAL_FILTER_SELECT2 (0x30) */ + 0x00, /* this register not used */ + 0x00, /* AK4671_E1_COEFFICIENT0 (0x32) */ + 0x00, /* AK4671_E1_COEFFICIENT1 (0x33) */ + 0x00, /* AK4671_E1_COEFFICIENT2 (0x34) */ + 0x00, /* AK4671_E1_COEFFICIENT3 (0x35) */ + 0x00, /* AK4671_E1_COEFFICIENT4 (0x36) */ + 0x00, /* AK4671_E1_COEFFICIENT5 (0x37) */ + 0x00, /* AK4671_E2_COEFFICIENT0 (0x38) */ + 0x00, /* AK4671_E2_COEFFICIENT1 (0x39) */ + 0x00, /* AK4671_E2_COEFFICIENT2 (0x3a) */ + 0x00, /* AK4671_E2_COEFFICIENT3 (0x3b) */ + 0x00, /* AK4671_E2_COEFFICIENT4 (0x3c) */ + 0x00, /* AK4671_E2_COEFFICIENT5 (0x3d) */ + 0x00, /* AK4671_E3_COEFFICIENT0 (0x3e) */ + 0x00, /* AK4671_E3_COEFFICIENT1 (0x3f) */ + 0x00, /* AK4671_E3_COEFFICIENT2 (0x40) */ + 0x00, /* AK4671_E3_COEFFICIENT3 (0x41) */ + 0x00, /* AK4671_E3_COEFFICIENT4 (0x42) */ + 0x00, /* AK4671_E3_COEFFICIENT5 (0x43) */ + 0x00, /* AK4671_E4_COEFFICIENT0 (0x44) */ + 0x00, /* AK4671_E4_COEFFICIENT1 (0x45) */ + 0x00, /* AK4671_E4_COEFFICIENT2 (0x46) */ + 0x00, /* AK4671_E4_COEFFICIENT3 (0x47) */ + 0x00, /* AK4671_E4_COEFFICIENT4 (0x48) */ + 0x00, /* AK4671_E4_COEFFICIENT5 (0x49) */ + 0x00, /* AK4671_E5_COEFFICIENT0 (0x4a) */ + 0x00, /* AK4671_E5_COEFFICIENT1 (0x4b) */ + 0x00, /* AK4671_E5_COEFFICIENT2 (0x4c) */ + 0x00, /* AK4671_E5_COEFFICIENT3 (0x4d) */ + 0x00, /* AK4671_E5_COEFFICIENT4 (0x4e) */ + 0x00, /* AK4671_E5_COEFFICIENT5 (0x4f) */ + 0x88, /* AK4671_EQ_CONTROL_250HZ_100HZ (0x50) */ + 0x88, /* AK4671_EQ_CONTROL_3500HZ_1KHZ (0x51) */ + 0x08, /* AK4671_EQ_CONTRO_10KHZ (0x52) */ + 0x00, /* AK4671_PCM_IF_CONTROL0 (0x53) */ + 0x00, /* AK4671_PCM_IF_CONTROL1 (0x54) */ + 0x00, /* AK4671_PCM_IF_CONTROL2 (0x55) */ + 0x18, /* AK4671_DIGITAL_VOLUME_B_CONTROL (0x56) */ + 0x18, /* AK4671_DIGITAL_VOLUME_C_CONTROL (0x57) */ + 0x00, /* AK4671_SIDETONE_VOLUME_CONTROL (0x58) */ + 0x00, /* AK4671_DIGITAL_MIXING_CONTROL2 (0x59) */ + 0x00, /* AK4671_SAR_ADC_CONTROL (0x5a) */ +}; + +/* + * LOUT1/ROUT1 output volume control: + * from -24 to 6 dB in 6 dB steps (mute instead of -30 dB) + */ +static DECLARE_TLV_DB_SCALE(out1_tlv, -3000, 600, 1); + +/* + * LOUT2/ROUT2 output volume control: + * from -33 to 6 dB in 3 dB steps (mute instead of -33 dB) + */ +static DECLARE_TLV_DB_SCALE(out2_tlv, -3300, 300, 1); + +/* + * LOUT3/ROUT3 output volume control: + * from -6 to 3 dB in 3 dB steps + */ +static DECLARE_TLV_DB_SCALE(out3_tlv, -600, 300, 0); + +/* + * Mic amp gain control: + * from -15 to 30 dB in 3 dB steps + * REVISIT: The actual min value(0x01) is -12 dB and the reg value 0x00 is not + * available + */ +static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -1500, 300, 0); + +static const struct snd_kcontrol_new ak4671_snd_controls[] = { + /* Common playback gain controls */ + SOC_SINGLE_TLV("Line Output1 Playback Volume", + AK4671_OUTPUT_VOLUME_CONTROL, 0, 0x6, 0, out1_tlv), + SOC_SINGLE_TLV("Headphone Output2 Playback Volume", + AK4671_OUTPUT_VOLUME_CONTROL, 4, 0xd, 0, out2_tlv), + SOC_SINGLE_TLV("Line Output3 Playback Volume", + AK4671_LOUT3_POWER_MANAGERMENT, 6, 0x3, 0, out3_tlv), + + /* Common capture gain controls */ + SOC_DOUBLE_TLV("Mic Amp Capture Volume", + AK4671_MIC_AMP_GAIN, 0, 4, 0xf, 0, mic_amp_tlv), +}; + +/* event handlers */ +static int ak4671_out2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + u8 reg; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + reg = snd_soc_read(codec, AK4671_LOUT2_POWER_MANAGERMENT); + reg |= AK4671_MUTEN; + snd_soc_write(codec, AK4671_LOUT2_POWER_MANAGERMENT, reg); + break; + case SND_SOC_DAPM_PRE_PMD: + reg = snd_soc_read(codec, AK4671_LOUT2_POWER_MANAGERMENT); + reg &= ~AK4671_MUTEN; + snd_soc_write(codec, AK4671_LOUT2_POWER_MANAGERMENT, reg); + break; + } + + return 0; +} + +/* Output Mixers */ +static const struct snd_kcontrol_new ak4671_lout1_mixer_controls[] = { + SOC_DAPM_SINGLE("DACL", AK4671_LOUT1_SIGNAL_SELECT, 0, 1, 0), + SOC_DAPM_SINGLE("LINL1", AK4671_LOUT1_SIGNAL_SELECT, 1, 1, 0), + SOC_DAPM_SINGLE("LINL2", AK4671_LOUT1_SIGNAL_SELECT, 2, 1, 0), + SOC_DAPM_SINGLE("LINL3", AK4671_LOUT1_SIGNAL_SELECT, 3, 1, 0), + SOC_DAPM_SINGLE("LINL4", AK4671_LOUT1_SIGNAL_SELECT, 4, 1, 0), + SOC_DAPM_SINGLE("LOOPL", AK4671_LOUT1_SIGNAL_SELECT, 5, 1, 0), +}; + +static const struct snd_kcontrol_new ak4671_rout1_mixer_controls[] = { + SOC_DAPM_SINGLE("DACR", AK4671_ROUT1_SIGNAL_SELECT, 0, 1, 0), + SOC_DAPM_SINGLE("RINR1", AK4671_ROUT1_SIGNAL_SELECT, 1, 1, 0), + SOC_DAPM_SINGLE("RINR2", AK4671_ROUT1_SIGNAL_SELECT, 2, 1, 0), + SOC_DAPM_SINGLE("RINR3", AK4671_ROUT1_SIGNAL_SELECT, 3, 1, 0), + SOC_DAPM_SINGLE("RINR4", AK4671_ROUT1_SIGNAL_SELECT, 4, 1, 0), + SOC_DAPM_SINGLE("LOOPR", AK4671_ROUT1_SIGNAL_SELECT, 5, 1, 0), +}; + +static const struct snd_kcontrol_new ak4671_lout2_mixer_controls[] = { + SOC_DAPM_SINGLE("DACHL", AK4671_LOUT2_SIGNAL_SELECT, 0, 1, 0), + SOC_DAPM_SINGLE("LINH1", AK4671_LOUT2_SIGNAL_SELECT, 1, 1, 0), + SOC_DAPM_SINGLE("LINH2", AK4671_LOUT2_SIGNAL_SELECT, 2, 1, 0), + SOC_DAPM_SINGLE("LINH3", AK4671_LOUT2_SIGNAL_SELECT, 3, 1, 0), + SOC_DAPM_SINGLE("LINH4", AK4671_LOUT2_SIGNAL_SELECT, 4, 1, 0), + SOC_DAPM_SINGLE("LOOPHL", AK4671_LOUT2_SIGNAL_SELECT, 5, 1, 0), +}; + +static const struct snd_kcontrol_new ak4671_rout2_mixer_controls[] = { + SOC_DAPM_SINGLE("DACHR", AK4671_ROUT2_SIGNAL_SELECT, 0, 1, 0), + SOC_DAPM_SINGLE("RINH1", AK4671_ROUT2_SIGNAL_SELECT, 1, 1, 0), + SOC_DAPM_SINGLE("RINH2", AK4671_ROUT2_SIGNAL_SELECT, 2, 1, 0), + SOC_DAPM_SINGLE("RINH3", AK4671_ROUT2_SIGNAL_SELECT, 3, 1, 0), + SOC_DAPM_SINGLE("RINH4", AK4671_ROUT2_SIGNAL_SELECT, 4, 1, 0), + SOC_DAPM_SINGLE("LOOPHR", AK4671_ROUT2_SIGNAL_SELECT, 5, 1, 0), +}; + +static const struct snd_kcontrol_new ak4671_lout3_mixer_controls[] = { + SOC_DAPM_SINGLE("DACSL", AK4671_LOUT3_SIGNAL_SELECT, 0, 1, 0), + SOC_DAPM_SINGLE("LINS1", AK4671_LOUT3_SIGNAL_SELECT, 1, 1, 0), + SOC_DAPM_SINGLE("LINS2", AK4671_LOUT3_SIGNAL_SELECT, 2, 1, 0), + SOC_DAPM_SINGLE("LINS3", AK4671_LOUT3_SIGNAL_SELECT, 3, 1, 0), + SOC_DAPM_SINGLE("LINS4", AK4671_LOUT3_SIGNAL_SELECT, 4, 1, 0), + SOC_DAPM_SINGLE("LOOPSL", AK4671_LOUT3_SIGNAL_SELECT, 5, 1, 0), +}; + +static const struct snd_kcontrol_new ak4671_rout3_mixer_controls[] = { + SOC_DAPM_SINGLE("DACSR", AK4671_ROUT3_SIGNAL_SELECT, 0, 1, 0), + SOC_DAPM_SINGLE("RINS1", AK4671_ROUT3_SIGNAL_SELECT, 1, 1, 0), + SOC_DAPM_SINGLE("RINS2", AK4671_ROUT3_SIGNAL_SELECT, 2, 1, 0), + SOC_DAPM_SINGLE("RINS3", AK4671_ROUT3_SIGNAL_SELECT, 3, 1, 0), + SOC_DAPM_SINGLE("RINS4", AK4671_ROUT3_SIGNAL_SELECT, 4, 1, 0), + SOC_DAPM_SINGLE("LOOPSR", AK4671_ROUT3_SIGNAL_SELECT, 5, 1, 0), +}; + +/* Input MUXs */ +static const char *ak4671_lin_mux_texts[] = + {"LIN1", "LIN2", "LIN3", "LIN4"}; +static const struct soc_enum ak4671_lin_mux_enum = + SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 0, + ARRAY_SIZE(ak4671_lin_mux_texts), + ak4671_lin_mux_texts); +static const struct snd_kcontrol_new ak4671_lin_mux_control = + SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum); + +static const char *ak4671_rin_mux_texts[] = + {"RIN1", "RIN2", "RIN3", "RIN4"}; +static const struct soc_enum ak4671_rin_mux_enum = + SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 2, + ARRAY_SIZE(ak4671_rin_mux_texts), + ak4671_rin_mux_texts); +static const struct snd_kcontrol_new ak4671_rin_mux_control = + SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum); + +static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = { + /* Inputs */ + SND_SOC_DAPM_INPUT("LIN1"), + SND_SOC_DAPM_INPUT("RIN1"), + SND_SOC_DAPM_INPUT("LIN2"), + SND_SOC_DAPM_INPUT("RIN2"), + SND_SOC_DAPM_INPUT("LIN3"), + SND_SOC_DAPM_INPUT("RIN3"), + SND_SOC_DAPM_INPUT("LIN4"), + SND_SOC_DAPM_INPUT("RIN4"), + + /* Outputs */ + SND_SOC_DAPM_OUTPUT("LOUT1"), + SND_SOC_DAPM_OUTPUT("ROUT1"), + SND_SOC_DAPM_OUTPUT("LOUT2"), + SND_SOC_DAPM_OUTPUT("ROUT2"), + SND_SOC_DAPM_OUTPUT("LOUT3"), + SND_SOC_DAPM_OUTPUT("ROUT3"), + + /* DAC */ + SND_SOC_DAPM_DAC("DAC Left", "Left HiFi Playback", + AK4671_AD_DA_POWER_MANAGEMENT, 6, 0), + SND_SOC_DAPM_DAC("DAC Right", "Right HiFi Playback", + AK4671_AD_DA_POWER_MANAGEMENT, 7, 0), + + /* ADC */ + SND_SOC_DAPM_ADC("ADC Left", "Left HiFi Capture", + AK4671_AD_DA_POWER_MANAGEMENT, 4, 0), + SND_SOC_DAPM_ADC("ADC Right", "Right HiFi Capture", + AK4671_AD_DA_POWER_MANAGEMENT, 5, 0), + + /* PGA */ + SND_SOC_DAPM_PGA("LOUT2 Mix Amp", + AK4671_LOUT2_POWER_MANAGERMENT, 5, 0, NULL, 0), + SND_SOC_DAPM_PGA("ROUT2 Mix Amp", + AK4671_LOUT2_POWER_MANAGERMENT, 6, 0, NULL, 0), + + SND_SOC_DAPM_PGA("LIN1 Mixing Circuit", + AK4671_MIXING_POWER_MANAGEMENT1, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("RIN1 Mixing Circuit", + AK4671_MIXING_POWER_MANAGEMENT1, 1, 0, NULL, 0), + SND_SOC_DAPM_PGA("LIN2 Mixing Circuit", + AK4671_MIXING_POWER_MANAGEMENT1, 2, 0, NULL, 0), + SND_SOC_DAPM_PGA("RIN2 Mixing Circuit", + AK4671_MIXING_POWER_MANAGEMENT1, 3, 0, NULL, 0), + SND_SOC_DAPM_PGA("LIN3 Mixing Circuit", + AK4671_MIXING_POWER_MANAGEMENT1, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("RIN3 Mixing Circuit", + AK4671_MIXING_POWER_MANAGEMENT1, 5, 0, NULL, 0), + SND_SOC_DAPM_PGA("LIN4 Mixing Circuit", + AK4671_MIXING_POWER_MANAGEMENT1, 6, 0, NULL, 0), + SND_SOC_DAPM_PGA("RIN4 Mixing Circuit", + AK4671_MIXING_POWER_MANAGEMENT1, 7, 0, NULL, 0), + + /* Output Mixers */ + SND_SOC_DAPM_MIXER("LOUT1 Mixer", AK4671_LOUT1_POWER_MANAGERMENT, 0, 0, + &ak4671_lout1_mixer_controls[0], + ARRAY_SIZE(ak4671_lout1_mixer_controls)), + SND_SOC_DAPM_MIXER("ROUT1 Mixer", AK4671_LOUT1_POWER_MANAGERMENT, 1, 0, + &ak4671_rout1_mixer_controls[0], + ARRAY_SIZE(ak4671_rout1_mixer_controls)), + SND_SOC_DAPM_MIXER_E("LOUT2 Mixer", AK4671_LOUT2_POWER_MANAGERMENT, + 0, 0, &ak4671_lout2_mixer_controls[0], + ARRAY_SIZE(ak4671_lout2_mixer_controls), + ak4671_out2_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MIXER_E("ROUT2 Mixer", AK4671_LOUT2_POWER_MANAGERMENT, + 1, 0, &ak4671_rout2_mixer_controls[0], + ARRAY_SIZE(ak4671_rout2_mixer_controls), + ak4671_out2_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MIXER("LOUT3 Mixer", AK4671_LOUT3_POWER_MANAGERMENT, 0, 0, + &ak4671_lout3_mixer_controls[0], + ARRAY_SIZE(ak4671_lout3_mixer_controls)), + SND_SOC_DAPM_MIXER("ROUT3 Mixer", AK4671_LOUT3_POWER_MANAGERMENT, 1, 0, + &ak4671_rout3_mixer_controls[0], + ARRAY_SIZE(ak4671_rout3_mixer_controls)), + + /* Input MUXs */ + SND_SOC_DAPM_MUX("LIN MUX", AK4671_AD_DA_POWER_MANAGEMENT, 2, 0, + &ak4671_lin_mux_control), + SND_SOC_DAPM_MUX("RIN MUX", AK4671_AD_DA_POWER_MANAGEMENT, 3, 0, + &ak4671_rin_mux_control), + + /* Mic Power */ + SND_SOC_DAPM_MICBIAS("Mic Bias", AK4671_AD_DA_POWER_MANAGEMENT, 1, 0), + + /* Supply */ + SND_SOC_DAPM_SUPPLY("PMPLL", AK4671_PLL_MODE_SELECT1, 0, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_route intercon[] = { + {"DAC Left", "NULL", "PMPLL"}, + {"DAC Right", "NULL", "PMPLL"}, + {"ADC Left", "NULL", "PMPLL"}, + {"ADC Right", "NULL", "PMPLL"}, + + /* Outputs */ + {"LOUT1", "NULL", "LOUT1 Mixer"}, + {"ROUT1", "NULL", "ROUT1 Mixer"}, + {"LOUT2", "NULL", "LOUT2 Mix Amp"}, + {"ROUT2", "NULL", "ROUT2 Mix Amp"}, + {"LOUT3", "NULL", "LOUT3 Mixer"}, + {"ROUT3", "NULL", "ROUT3 Mixer"}, + + {"LOUT1 Mixer", "DACL", "DAC Left"}, + {"ROUT1 Mixer", "DACR", "DAC Right"}, + {"LOUT2 Mixer", "DACHL", "DAC Left"}, + {"ROUT2 Mixer", "DACHR", "DAC Right"}, + {"LOUT2 Mix Amp", "NULL", "LOUT2 Mixer"}, + {"ROUT2 Mix Amp", "NULL", "ROUT2 Mixer"}, + {"LOUT3 Mixer", "DACSL", "DAC Left"}, + {"ROUT3 Mixer", "DACSR", "DAC Right"}, + + /* Inputs */ + {"LIN MUX", "LIN1", "LIN1"}, + {"LIN MUX", "LIN2", "LIN2"}, + {"LIN MUX", "LIN3", "LIN3"}, + {"LIN MUX", "LIN4", "LIN4"}, + + {"RIN MUX", "RIN1", "RIN1"}, + {"RIN MUX", "RIN2", "RIN2"}, + {"RIN MUX", "RIN3", "RIN3"}, + {"RIN MUX", "RIN4", "RIN4"}, + + {"LIN1", NULL, "Mic Bias"}, + {"RIN1", NULL, "Mic Bias"}, + {"LIN2", NULL, "Mic Bias"}, + {"RIN2", NULL, "Mic Bias"}, + + {"ADC Left", "NULL", "LIN MUX"}, + {"ADC Right", "NULL", "RIN MUX"}, + + /* Analog Loops */ + {"LIN1 Mixing Circuit", "NULL", "LIN1"}, + {"RIN1 Mixing Circuit", "NULL", "RIN1"}, + {"LIN2 Mixing Circuit", "NULL", "LIN2"}, + {"RIN2 Mixing Circuit", "NULL", "RIN2"}, + {"LIN3 Mixing Circuit", "NULL", "LIN3"}, + {"RIN3 Mixing Circuit", "NULL", "RIN3"}, + {"LIN4 Mixing Circuit", "NULL", "LIN4"}, + {"RIN4 Mixing Circuit", "NULL", "RIN4"}, + + {"LOUT1 Mixer", "LINL1", "LIN1 Mixing Circuit"}, + {"ROUT1 Mixer", "RINR1", "RIN1 Mixing Circuit"}, + {"LOUT2 Mixer", "LINH1", "LIN1 Mixing Circuit"}, + {"ROUT2 Mixer", "RINH1", "RIN1 Mixing Circuit"}, + {"LOUT3 Mixer", "LINS1", "LIN1 Mixing Circuit"}, + {"ROUT3 Mixer", "RINS1", "RIN1 Mixing Circuit"}, + + {"LOUT1 Mixer", "LINL2", "LIN2 Mixing Circuit"}, + {"ROUT1 Mixer", "RINR2", "RIN2 Mixing Circuit"}, + {"LOUT2 Mixer", "LINH2", "LIN2 Mixing Circuit"}, + {"ROUT2 Mixer", "RINH2", "RIN2 Mixing Circuit"}, + {"LOUT3 Mixer", "LINS2", "LIN2 Mixing Circuit"}, + {"ROUT3 Mixer", "RINS2", "RIN2 Mixing Circuit"}, + + {"LOUT1 Mixer", "LINL3", "LIN3 Mixing Circuit"}, + {"ROUT1 Mixer", "RINR3", "RIN3 Mixing Circuit"}, + {"LOUT2 Mixer", "LINH3", "LIN3 Mixing Circuit"}, + {"ROUT2 Mixer", "RINH3", "RIN3 Mixing Circuit"}, + {"LOUT3 Mixer", "LINS3", "LIN3 Mixing Circuit"}, + {"ROUT3 Mixer", "RINS3", "RIN3 Mixing Circuit"}, + + {"LOUT1 Mixer", "LINL4", "LIN4 Mixing Circuit"}, + {"ROUT1 Mixer", "RINR4", "RIN4 Mixing Circuit"}, + {"LOUT2 Mixer", "LINH4", "LIN4 Mixing Circuit"}, + {"ROUT2 Mixer", "RINH4", "RIN4 Mixing Circuit"}, + {"LOUT3 Mixer", "LINS4", "LIN4 Mixing Circuit"}, + {"ROUT3 Mixer", "RINS4", "RIN4 Mixing Circuit"}, +}; + +static int ak4671_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, ak4671_dapm_widgets, + ARRAY_SIZE(ak4671_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +static int ak4671_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + u8 fs; + + fs = snd_soc_read(codec, AK4671_PLL_MODE_SELECT0); + fs &= ~AK4671_FS; + + switch (params_rate(params)) { + case 8000: + fs |= AK4671_FS_8KHZ; + break; + case 12000: + fs |= AK4671_FS_12KHZ; + break; + case 16000: + fs |= AK4671_FS_16KHZ; + break; + case 24000: + fs |= AK4671_FS_24KHZ; + break; + case 11025: + fs |= AK4671_FS_11_025KHZ; + break; + case 22050: + fs |= AK4671_FS_22_05KHZ; + break; + case 32000: + fs |= AK4671_FS_32KHZ; + break; + case 44100: + fs |= AK4671_FS_44_1KHZ; + break; + case 48000: + fs |= AK4671_FS_48KHZ; + break; + default: + return -EINVAL; + } + + snd_soc_write(codec, AK4671_PLL_MODE_SELECT0, fs); + + return 0; +} + +static int ak4671_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + u8 pll; + + pll = snd_soc_read(codec, AK4671_PLL_MODE_SELECT0); + pll &= ~AK4671_PLL; + + switch (freq) { + case 11289600: + pll |= AK4671_PLL_11_2896MHZ; + break; + case 12000000: + pll |= AK4671_PLL_12MHZ; + break; + case 12288000: + pll |= AK4671_PLL_12_288MHZ; + break; + case 13000000: + pll |= AK4671_PLL_13MHZ; + break; + case 13500000: + pll |= AK4671_PLL_13_5MHZ; + break; + case 19200000: + pll |= AK4671_PLL_19_2MHZ; + break; + case 24000000: + pll |= AK4671_PLL_24MHZ; + break; + case 26000000: + pll |= AK4671_PLL_26MHZ; + break; + case 27000000: + pll |= AK4671_PLL_27MHZ; + break; + default: + return -EINVAL; + } + + snd_soc_write(codec, AK4671_PLL_MODE_SELECT0, pll); + + return 0; +} + +static int ak4671_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + u8 mode; + u8 format; + + /* set master/slave audio interface */ + mode = snd_soc_read(codec, AK4671_PLL_MODE_SELECT1); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + mode |= AK4671_M_S; + break; + case SND_SOC_DAIFMT_CBM_CFS: + mode &= ~(AK4671_M_S); + break; + default: + return -EINVAL; + } + + /* interface format */ + format = snd_soc_read(codec, AK4671_FORMAT_SELECT); + format &= ~AK4671_DIF; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + format |= AK4671_DIF_I2S_MODE; + break; + case SND_SOC_DAIFMT_LEFT_J: + format |= AK4671_DIF_MSB_MODE; + break; + case SND_SOC_DAIFMT_DSP_A: + format |= AK4671_DIF_DSP_MODE; + format |= AK4671_BCKP; + format |= AK4671_MSBS; + break; + default: + return -EINVAL; + } + + /* set mode and format */ + snd_soc_write(codec, AK4671_PLL_MODE_SELECT1, mode); + snd_soc_write(codec, AK4671_FORMAT_SELECT, format); + + return 0; +} + +static int ak4671_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + u8 reg; + + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + case SND_SOC_BIAS_STANDBY: + reg = snd_soc_read(codec, AK4671_AD_DA_POWER_MANAGEMENT); + snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, + reg | AK4671_PMVCM); + break; + case SND_SOC_BIAS_OFF: + snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00); + break; + } + codec->bias_level = level; + return 0; +} + +#define AK4671_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ + SNDRV_PCM_RATE_48000) + +#define AK4671_FORMATS SNDRV_PCM_FMTBIT_S16_LE + +static struct snd_soc_dai_ops ak4671_dai_ops = { + .hw_params = ak4671_hw_params, + .set_sysclk = ak4671_set_dai_sysclk, + .set_fmt = ak4671_set_dai_fmt, +}; + +struct snd_soc_dai ak4671_dai = { + .name = "AK4671", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AK4671_RATES, + .formats = AK4671_FORMATS,}, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AK4671_RATES, + .formats = AK4671_FORMATS,}, + .ops = &ak4671_dai_ops, +}; +EXPORT_SYMBOL_GPL(ak4671_dai); + +static int ak4671_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + if (ak4671_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = ak4671_codec; + codec = ak4671_codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms: %d\n", ret); + goto pcm_err; + } + + snd_soc_add_controls(codec, ak4671_snd_controls, + ARRAY_SIZE(ak4671_snd_controls)); + ak4671_add_widgets(codec); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(codec->dev, "failed to register card: %d\n", ret); + goto card_err; + } + + ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + return ret; +} + +static int ak4671_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_ak4671 = { + .probe = ak4671_probe, + .remove = ak4671_remove, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_ak4671); + +static int ak4671_register(struct ak4671_priv *ak4671, + enum snd_soc_control_type control) +{ + int ret; + struct snd_soc_codec *codec = &ak4671->codec; + + if (ak4671_codec) { + dev_err(codec->dev, "Another AK4671 is registered\n"); + ret = -EINVAL; + goto err; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = ak4671; + codec->name = "AK4671"; + codec->owner = THIS_MODULE; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = ak4671_set_bias_level; + codec->dai = &ak4671_dai; + codec->num_dai = 1; + codec->reg_cache_size = AK4671_CACHEREGNUM; + codec->reg_cache = &ak4671->reg_cache; + + memcpy(codec->reg_cache, ak4671_reg, sizeof(ak4671_reg)); + + ret = snd_soc_codec_set_cache_io(codec, 8, 8, control); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + + ak4671_dai.dev = codec->dev; + ak4671_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + goto err; + } + + ret = snd_soc_register_dai(&ak4671_dai); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + goto err_codec; + } + + return 0; + +err_codec: + snd_soc_unregister_codec(codec); +err: + kfree(ak4671); + return ret; +} + +static void ak4671_unregister(struct ak4671_priv *ak4671) +{ + ak4671_set_bias_level(&ak4671->codec, SND_SOC_BIAS_OFF); + snd_soc_unregister_dai(&ak4671_dai); + snd_soc_unregister_codec(&ak4671->codec); + kfree(ak4671); + ak4671_codec = NULL; +} + +static int __devinit ak4671_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ak4671_priv *ak4671; + struct snd_soc_codec *codec; + + ak4671 = kzalloc(sizeof(struct ak4671_priv), GFP_KERNEL); + if (ak4671 == NULL) + return -ENOMEM; + + codec = &ak4671->codec; + codec->hw_write = (hw_write_t)i2c_master_send; + + i2c_set_clientdata(client, ak4671); + codec->control_data = client; + + codec->dev = &client->dev; + + return ak4671_register(ak4671, SND_SOC_I2C); +} + +static __devexit int ak4671_i2c_remove(struct i2c_client *client) +{ + struct ak4671_priv *ak4671 = i2c_get_clientdata(client); + + ak4671_unregister(ak4671); + + return 0; +} + +static const struct i2c_device_id ak4671_i2c_id[] = { + { "ak4671", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id); + +static struct i2c_driver ak4671_i2c_driver = { + .driver = { + .name = "ak4671", + .owner = THIS_MODULE, + }, + .probe = ak4671_i2c_probe, + .remove = __devexit_p(ak4671_i2c_remove), + .id_table = ak4671_i2c_id, +}; + +static int __init ak4671_modinit(void) +{ + return i2c_add_driver(&ak4671_i2c_driver); +} +module_init(ak4671_modinit); + +static void __exit ak4671_exit(void) +{ + i2c_del_driver(&ak4671_i2c_driver); +} +module_exit(ak4671_exit); + +MODULE_DESCRIPTION("ASoC AK4671 codec driver"); +MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ak4671.h b/sound/soc/codecs/ak4671.h new file mode 100644 index 00000000000..e2fad964e88 --- /dev/null +++ b/sound/soc/codecs/ak4671.h @@ -0,0 +1,156 @@ +/* + * ak4671.h -- audio driver for AK4671 + * + * Copyright (C) 2009 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim <jy0922.shim@samsung.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef _AK4671_H +#define _AK4671_H + +#define AK4671_AD_DA_POWER_MANAGEMENT 0x00 +#define AK4671_PLL_MODE_SELECT0 0x01 +#define AK4671_PLL_MODE_SELECT1 0x02 +#define AK4671_FORMAT_SELECT 0x03 +#define AK4671_MIC_SIGNAL_SELECT 0x04 +#define AK4671_MIC_AMP_GAIN 0x05 +#define AK4671_MIXING_POWER_MANAGEMENT0 0x06 +#define AK4671_MIXING_POWER_MANAGEMENT1 0x07 +#define AK4671_OUTPUT_VOLUME_CONTROL 0x08 +#define AK4671_LOUT1_SIGNAL_SELECT 0x09 +#define AK4671_ROUT1_SIGNAL_SELECT 0x0a +#define AK4671_LOUT2_SIGNAL_SELECT 0x0b +#define AK4671_ROUT2_SIGNAL_SELECT 0x0c +#define AK4671_LOUT3_SIGNAL_SELECT 0x0d +#define AK4671_ROUT3_SIGNAL_SELECT 0x0e +#define AK4671_LOUT1_POWER_MANAGERMENT 0x0f +#define AK4671_LOUT2_POWER_MANAGERMENT 0x10 +#define AK4671_LOUT3_POWER_MANAGERMENT 0x11 +#define AK4671_LCH_INPUT_VOLUME_CONTROL 0x12 +#define AK4671_RCH_INPUT_VOLUME_CONTROL 0x13 +#define AK4671_ALC_REFERENCE_SELECT 0x14 +#define AK4671_DIGITAL_MIXING_CONTROL 0x15 +#define AK4671_ALC_TIMER_SELECT 0x16 +#define AK4671_ALC_MODE_CONTROL 0x17 +#define AK4671_MODE_CONTROL1 0x18 +#define AK4671_MODE_CONTROL2 0x19 +#define AK4671_LCH_OUTPUT_VOLUME_CONTROL 0x1a +#define AK4671_RCH_OUTPUT_VOLUME_CONTROL 0x1b +#define AK4671_SIDETONE_A_CONTROL 0x1c +#define AK4671_DIGITAL_FILTER_SELECT 0x1d +#define AK4671_FIL3_COEFFICIENT0 0x1e +#define AK4671_FIL3_COEFFICIENT1 0x1f +#define AK4671_FIL3_COEFFICIENT2 0x20 +#define AK4671_FIL3_COEFFICIENT3 0x21 +#define AK4671_EQ_COEFFICIENT0 0x22 +#define AK4671_EQ_COEFFICIENT1 0x23 +#define AK4671_EQ_COEFFICIENT2 0x24 +#define AK4671_EQ_COEFFICIENT3 0x25 +#define AK4671_EQ_COEFFICIENT4 0x26 +#define AK4671_EQ_COEFFICIENT5 0x27 +#define AK4671_FIL1_COEFFICIENT0 0x28 +#define AK4671_FIL1_COEFFICIENT1 0x29 +#define AK4671_FIL1_COEFFICIENT2 0x2a +#define AK4671_FIL1_COEFFICIENT3 0x2b +#define AK4671_FIL2_COEFFICIENT0 0x2c +#define AK4671_FIL2_COEFFICIENT1 0x2d +#define AK4671_FIL2_COEFFICIENT2 0x2e +#define AK4671_FIL2_COEFFICIENT3 0x2f +#define AK4671_DIGITAL_FILTER_SELECT2 0x30 +#define AK4671_E1_COEFFICIENT0 0x32 +#define AK4671_E1_COEFFICIENT1 0x33 +#define AK4671_E1_COEFFICIENT2 0x34 +#define AK4671_E1_COEFFICIENT3 0x35 +#define AK4671_E1_COEFFICIENT4 0x36 +#define AK4671_E1_COEFFICIENT5 0x37 +#define AK4671_E2_COEFFICIENT0 0x38 +#define AK4671_E2_COEFFICIENT1 0x39 +#define AK4671_E2_COEFFICIENT2 0x3a +#define AK4671_E2_COEFFICIENT3 0x3b +#define AK4671_E2_COEFFICIENT4 0x3c +#define AK4671_E2_COEFFICIENT5 0x3d +#define AK4671_E3_COEFFICIENT0 0x3e +#define AK4671_E3_COEFFICIENT1 0x3f +#define AK4671_E3_COEFFICIENT2 0x40 +#define AK4671_E3_COEFFICIENT3 0x41 +#define AK4671_E3_COEFFICIENT4 0x42 +#define AK4671_E3_COEFFICIENT5 0x43 +#define AK4671_E4_COEFFICIENT0 0x44 +#define AK4671_E4_COEFFICIENT1 0x45 +#define AK4671_E4_COEFFICIENT2 0x46 +#define AK4671_E4_COEFFICIENT3 0x47 +#define AK4671_E4_COEFFICIENT4 0x48 +#define AK4671_E4_COEFFICIENT5 0x49 +#define AK4671_E5_COEFFICIENT0 0x4a +#define AK4671_E5_COEFFICIENT1 0x4b +#define AK4671_E5_COEFFICIENT2 0x4c +#define AK4671_E5_COEFFICIENT3 0x4d +#define AK4671_E5_COEFFICIENT4 0x4e +#define AK4671_E5_COEFFICIENT5 0x4f +#define AK4671_EQ_CONTROL_250HZ_100HZ 0x50 +#define AK4671_EQ_CONTROL_3500HZ_1KHZ 0x51 +#define AK4671_EQ_CONTRO_10KHZ 0x52 +#define AK4671_PCM_IF_CONTROL0 0x53 +#define AK4671_PCM_IF_CONTROL1 0x54 +#define AK4671_PCM_IF_CONTROL2 0x55 +#define AK4671_DIGITAL_VOLUME_B_CONTROL 0x56 +#define AK4671_DIGITAL_VOLUME_C_CONTROL 0x57 +#define AK4671_SIDETONE_VOLUME_CONTROL 0x58 +#define AK4671_DIGITAL_MIXING_CONTROL2 0x59 +#define AK4671_SAR_ADC_CONTROL 0x5a + +#define AK4671_CACHEREGNUM (AK4671_SAR_ADC_CONTROL + 1) + +/* Bitfield Definitions */ + +/* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */ +#define AK4671_PMVCM 0x01 + +/* AK4671_PLL_MODE_SELECT0 (0x01) Fields */ +#define AK4671_PLL 0x0f +#define AK4671_PLL_11_2896MHZ (4 << 0) +#define AK4671_PLL_12_288MHZ (5 << 0) +#define AK4671_PLL_12MHZ (6 << 0) +#define AK4671_PLL_24MHZ (7 << 0) +#define AK4671_PLL_19_2MHZ (8 << 0) +#define AK4671_PLL_13_5MHZ (12 << 0) +#define AK4671_PLL_27MHZ (13 << 0) +#define AK4671_PLL_13MHZ (14 << 0) +#define AK4671_PLL_26MHZ (15 << 0) +#define AK4671_FS 0xf0 +#define AK4671_FS_8KHZ (0 << 4) +#define AK4671_FS_12KHZ (1 << 4) +#define AK4671_FS_16KHZ (2 << 4) +#define AK4671_FS_24KHZ (3 << 4) +#define AK4671_FS_11_025KHZ (5 << 4) +#define AK4671_FS_22_05KHZ (7 << 4) +#define AK4671_FS_32KHZ (10 << 4) +#define AK4671_FS_48KHZ (11 << 4) +#define AK4671_FS_44_1KHZ (15 << 4) + +/* AK4671_PLL_MODE_SELECT1 (0x02) Fields */ +#define AK4671_PMPLL 0x01 +#define AK4671_M_S 0x02 + +/* AK4671_FORMAT_SELECT (0x03) Fields */ +#define AK4671_DIF 0x03 +#define AK4671_DIF_DSP_MODE (0 << 0) +#define AK4671_DIF_MSB_MODE (2 << 0) +#define AK4671_DIF_I2S_MODE (3 << 0) +#define AK4671_BCKP 0x04 +#define AK4671_MSBS 0x08 +#define AK4671_SDOD 0x10 + +/* AK4671_LOUT2_POWER_MANAGEMENT (0x10) Fields */ +#define AK4671_MUTEN 0x04 + +extern struct snd_soc_dai ak4671_dai; +extern struct snd_soc_codec_device soc_codec_dev_ak4671; + +#endif diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 126b15b18ae..3395cf945d5 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -53,6 +53,7 @@ /* codec private data */ struct aic3x_priv { + struct snd_soc_codec codec; unsigned int sysclk; int master; }; @@ -1156,11 +1157,13 @@ static int aic3x_resume(struct platform_device *pdev) * initialise the AIC3X driver * register the mixer and dsp interfaces with the kernel */ -static int aic3x_init(struct snd_soc_device *socdev) +static int aic3x_init(struct snd_soc_codec *codec) { - struct snd_soc_codec *codec = socdev->card->codec; - struct aic3x_setup_data *setup = socdev->codec_data; - int reg, ret = 0; + int reg; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); codec->name = "tlv320aic3x"; codec->owner = THIS_MODULE; @@ -1177,13 +1180,6 @@ static int aic3x_init(struct snd_soc_device *socdev) aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); aic3x_write(codec, AIC3X_RESET, SOFT_RESET); - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - printk(KERN_ERR "aic3x: failed to create pcms\n"); - goto pcm_err; - } - /* DAC default volume and mute */ aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON); aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON); @@ -1250,30 +1246,51 @@ static int aic3x_init(struct snd_soc_device *socdev) /* off, with power on */ aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* setup GPIO functions */ - aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4); - aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4); + return 0; +} - snd_soc_add_controls(codec, aic3x_snd_controls, - ARRAY_SIZE(aic3x_snd_controls)); - aic3x_add_widgets(codec); - ret = snd_soc_init_card(socdev); +static struct snd_soc_codec *aic3x_codec; + +static int aic3x_register(struct snd_soc_codec *codec) +{ + int ret; + + ret = aic3x_init(codec); if (ret < 0) { - printk(KERN_ERR "aic3x: failed to register card\n"); - goto card_err; + dev_err(codec->dev, "Failed to initialise device\n"); + return ret; } - return ret; + aic3x_codec = codec; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); - return ret; + ret = snd_soc_register_codec(codec); + if (ret) { + dev_err(codec->dev, "Failed to register codec\n"); + return ret; + } + + ret = snd_soc_register_dai(&aic3x_dai); + if (ret) { + dev_err(codec->dev, "Failed to register dai\n"); + snd_soc_unregister_codec(codec); + return ret; + } + + return 0; } -static struct snd_soc_device *aic3x_socdev; +static int aic3x_unregister(struct aic3x_priv *aic3x) +{ + aic3x_set_bias_level(&aic3x->codec, SND_SOC_BIAS_OFF); + + snd_soc_unregister_dai(&aic3x_dai); + snd_soc_unregister_codec(&aic3x->codec); + + kfree(aic3x); + aic3x_codec = NULL; + + return 0; +} #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) /* @@ -1288,28 +1305,36 @@ static struct snd_soc_device *aic3x_socdev; static int aic3x_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct snd_soc_device *socdev = aic3x_socdev; - struct snd_soc_codec *codec = socdev->card->codec; - int ret; + struct snd_soc_codec *codec; + struct aic3x_priv *aic3x; + + aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); + if (aic3x == NULL) { + dev_err(&i2c->dev, "failed to create private data\n"); + return -ENOMEM; + } - i2c_set_clientdata(i2c, codec); + codec = &aic3x->codec; + codec->dev = &i2c->dev; + codec->private_data = aic3x; codec->control_data = i2c; + codec->hw_write = (hw_write_t) i2c_master_send; - ret = aic3x_init(socdev); - if (ret < 0) - printk(KERN_ERR "aic3x: failed to initialise AIC3X\n"); - return ret; + i2c_set_clientdata(i2c, aic3x); + + return aic3x_register(codec); } static int aic3x_i2c_remove(struct i2c_client *client) { - struct snd_soc_codec *codec = i2c_get_clientdata(client); - kfree(codec->reg_cache); - return 0; + struct aic3x_priv *aic3x = i2c_get_clientdata(client); + + return aic3x_unregister(aic3x); } static const struct i2c_device_id aic3x_i2c_id[] = { { "tlv320aic3x", 0 }, + { "tlv320aic33", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); @@ -1320,50 +1345,28 @@ static struct i2c_driver aic3x_i2c_driver = { .name = "aic3x I2C Codec", .owner = THIS_MODULE, }, - .probe = aic3x_i2c_probe, + .probe = aic3x_i2c_probe, .remove = aic3x_i2c_remove, .id_table = aic3x_i2c_id, }; -static int aic3x_add_i2c_device(struct platform_device *pdev, - const struct aic3x_setup_data *setup) +static inline void aic3x_i2c_init(void) { - struct i2c_board_info info; - struct i2c_adapter *adapter; - struct i2c_client *client; int ret; ret = i2c_add_driver(&aic3x_i2c_driver); - if (ret != 0) { - dev_err(&pdev->dev, "can't add i2c driver\n"); - return ret; - } - - memset(&info, 0, sizeof(struct i2c_board_info)); - info.addr = setup->i2c_address; - strlcpy(info.type, "tlv320aic3x", I2C_NAME_SIZE); - - adapter = i2c_get_adapter(setup->i2c_bus); - if (!adapter) { - dev_err(&pdev->dev, "can't get i2c adapter %d\n", - setup->i2c_bus); - goto err_driver; - } - - client = i2c_new_device(adapter, &info); - i2c_put_adapter(adapter); - if (!client) { - dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", - (unsigned int)info.addr); - goto err_driver; - } - - return 0; + if (ret) + printk(KERN_ERR "%s: error regsitering i2c driver, %d\n", + __func__, ret); +} -err_driver: +static inline void aic3x_i2c_exit(void) +{ i2c_del_driver(&aic3x_i2c_driver); - return -ENODEV; } +#else +static inline void aic3x_i2c_init(void) { } +static inline void aic3x_i2c_exit(void) { } #endif static int aic3x_probe(struct platform_device *pdev) @@ -1371,42 +1374,51 @@ static int aic3x_probe(struct platform_device *pdev) struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct aic3x_setup_data *setup; struct snd_soc_codec *codec; - struct aic3x_priv *aic3x; int ret = 0; - printk(KERN_INFO "AIC3X Audio Codec %s\n", AIC3X_VERSION); + codec = aic3x_codec; + if (!codec) { + dev_err(&pdev->dev, "Codec not registered\n"); + return -ENODEV; + } + socdev->card->codec = codec; setup = socdev->codec_data; - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); - if (aic3x == NULL) { - kfree(codec); - return -ENOMEM; + if (setup) { + /* setup GPIO functions */ + aic3x_write(codec, AIC3X_GPIO1_REG, + (setup->gpio_func[0] & 0xf) << 4); + aic3x_write(codec, AIC3X_GPIO2_REG, + (setup->gpio_func[1] & 0xf) << 4); } - codec->private_data = aic3x; - socdev->card->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - aic3x_socdev = socdev; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - if (setup->i2c_address) { - codec->hw_write = (hw_write_t) i2c_master_send; - ret = aic3x_add_i2c_device(pdev, setup); + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "aic3x: failed to create pcms\n"); + goto pcm_err; } -#else - /* Add other interfaces here */ -#endif - if (ret != 0) { - kfree(codec->private_data); - kfree(codec); + snd_soc_add_controls(codec, aic3x_snd_controls, + ARRAY_SIZE(aic3x_snd_controls)); + + aic3x_add_widgets(codec); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + printk(KERN_ERR "aic3x: failed to register card\n"); + goto card_err; } + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + +pcm_err: + kfree(codec->reg_cache); return ret; } @@ -1421,12 +1433,8 @@ static int aic3x_remove(struct platform_device *pdev) snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_unregister_device(codec->control_data); - i2c_del_driver(&aic3x_i2c_driver); -#endif - kfree(codec->private_data); - kfree(codec); + + kfree(codec->reg_cache); return 0; } @@ -1441,13 +1449,15 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x); static int __init aic3x_modinit(void) { - return snd_soc_register_dai(&aic3x_dai); + aic3x_i2c_init(); + + return 0; } module_init(aic3x_modinit); static void __exit aic3x_exit(void) { - snd_soc_unregister_dai(&aic3x_dai); + aic3x_i2c_exit(); } module_exit(aic3x_exit); diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index ac827e578c4..9af1c886213 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -282,8 +282,6 @@ int aic3x_headset_detected(struct snd_soc_codec *codec); int aic3x_button_pressed(struct snd_soc_codec *codec); struct aic3x_setup_data { - int i2c_bus; - unsigned short i2c_address; unsigned int gpio_func[2]; }; diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 4ded0e3a35e..3f7e8a8b387 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -63,6 +63,8 @@ struct wm8350_data { struct wm8350_jack_data hpl; struct wm8350_jack_data hpr; struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; + int fll_freq_out; + int fll_freq_in; }; static unsigned int wm8350_codec_cache_read(struct snd_soc_codec *codec, @@ -610,7 +612,7 @@ SOC_DAPM_SINGLE("Switch", WM8350_BEEP_VOLUME, 15, 1, 1); /* Out4 Capture Mux */ static const struct snd_kcontrol_new wm8350_out4_capture_controls = -SOC_DAPM_ENUM("Route", wm8350_enum[8]); +SOC_DAPM_ENUM("Route", wm8350_enum[7]); static const struct snd_soc_dapm_widget wm8350_dapm_widgets[] = { @@ -1099,15 +1101,19 @@ static inline int fll_factors(struct _fll_div *fll_div, unsigned int input, } static int wm8350_set_fll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, + int pll_id, int source, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; struct wm8350 *wm8350 = codec->control_data; + struct wm8350_data *priv = codec->private_data; struct _fll_div fll_div; int ret = 0; u16 fll_1, fll_4; + if (freq_in == priv->fll_freq_in && freq_out == priv->fll_freq_out) + return 0; + /* power down FLL - we need to do this for reconfiguration */ wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA | WM8350_FLL_OSC_ENA); @@ -1142,6 +1148,9 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai, wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_OSC_ENA); wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA); + priv->fll_freq_out = freq_out; + priv->fll_freq_in = freq_in; + return 0; } diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index b9ef4d91522..9cb8e50f0fb 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -1011,7 +1011,8 @@ static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors, } static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, - unsigned int freq_in, unsigned int freq_out) + int source, unsigned int freq_in, + unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; struct wm8400_priv *wm8400 = codec->private_data; diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 060d5d06ba9..5702435af81 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -271,8 +271,8 @@ static void pll_factors(unsigned int target, unsigned int source) pll_div.k = K; } -static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; u16 reg; diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index d5473473a1e..3be5c0b2552 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -407,8 +407,8 @@ static int pll_factors(struct _pll_div *pll_div, unsigned int target, return 0; } -static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { int offset; struct snd_soc_codec *codec = codec_dai->codec; @@ -458,12 +458,12 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, return 0; snd_soc_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff); - snd_soc_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0xff); + snd_soc_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0x1ff); snd_soc_write(codec, WM8580_PLLA3 + offset, (pll_div.k >> 18 & 0xf) | (pll_div.n << 4)); reg = snd_soc_read(codec, WM8580_PLLA4 + offset); - reg &= ~0x3f; + reg &= ~0x1b; reg |= pll_div.prescale | pll_div.postscale << 1 | pll_div.freqmode << 3; diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index d80d414cfbb..f60f3a02d1f 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -723,8 +723,8 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, pll_div->k = K; } -static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { u16 reg, enable; int offset; diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 5e9c855c003..882604ef768 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -814,8 +814,8 @@ reenable: return 0; } -static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { return wm8900_set_fll(codec_dai->codec, pll_id, freq_in, freq_out); } diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index da97aae475a..914d788a2b7 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -536,8 +536,8 @@ static void pll_factors(unsigned int target, unsigned int source) } /* Untested at the moment */ -static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; u16 reg; diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index f59703be61c..416fb3c1701 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -540,8 +540,8 @@ static int pll_factors(unsigned int source, unsigned int target, return 0; } -static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; u16 reg; diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index d8a013ab317..93d66e30f10 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/version.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> @@ -329,8 +328,8 @@ static void pll_factors(unsigned int target, unsigned int source) pll_div.k = K; } -static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; u16 reg; diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 2d702db4131..f657e9a5fe2 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -972,8 +972,8 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, pll_div->k = K; } -static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { u16 reg; struct snd_soc_codec *codec = codec_dai->codec; diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 13befa33824..6b32a285260 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -422,7 +422,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, return 0; } -static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, +static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source, unsigned int Fref, unsigned int Fout) { struct snd_soc_codec *codec = dai->codec; @@ -846,18 +846,76 @@ SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 2, 1, 0), SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 0, 1, 0), }; +static const char *aif_text[] = { + "Left", "Right" +}; + +static const struct soc_enum aifoutl_enum = + SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_1, 15, 2, aif_text); + +static const struct snd_kcontrol_new aifoutl_mux = + SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum); + +static const struct soc_enum aifoutr_enum = + SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_1, 14, 2, aif_text); + +static const struct snd_kcontrol_new aifoutr_mux = + SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum); + +static const struct soc_enum aifinl_enum = + SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_2, 15, 2, aif_text); + +static const struct snd_kcontrol_new aifinl_mux = + SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum); + +static const struct soc_enum aifinr_enum = + SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_2, 14, 2, aif_text); + +static const struct snd_kcontrol_new aifinr_mux = + SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum); + +static const char *sidetone_text[] = { + "None", "Left", "Right" +}; + +static const struct soc_enum sidetonel_enum = + SOC_ENUM_SINGLE(WM8993_DIGITAL_SIDE_TONE, 2, 3, sidetone_text); + +static const struct snd_kcontrol_new sidetonel_mux = + SOC_DAPM_ENUM("Left Sidetone", sidetonel_enum); + +static const struct soc_enum sidetoner_enum = + SOC_ENUM_SINGLE(WM8993_DIGITAL_SIDE_TONE, 0, 3, sidetone_text); + +static const struct snd_kcontrol_new sidetoner_mux = + SOC_DAPM_ENUM("Right Sidetone", sidetoner_enum); + static const struct snd_soc_dapm_widget wm8993_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8993_BUS_CONTROL_1, 1, 0, clk_sys_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("TOCLK", WM8993_CLOCKING_1, 14, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8993_CLOCKING_3, 0, 0, NULL, 0), +SND_SOC_DAPM_ADC("ADCL", NULL, WM8993_POWER_MANAGEMENT_2, 1, 0), +SND_SOC_DAPM_ADC("ADCR", NULL, WM8993_POWER_MANAGEMENT_2, 0, 0), + +SND_SOC_DAPM_MUX("AIFOUTL Mux", SND_SOC_NOPM, 0, 0, &aifoutl_mux), +SND_SOC_DAPM_MUX("AIFOUTR Mux", SND_SOC_NOPM, 0, 0, &aifoutr_mux), + +SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_ADC("ADCL", "Capture", WM8993_POWER_MANAGEMENT_2, 1, 0), -SND_SOC_DAPM_ADC("ADCR", "Capture", WM8993_POWER_MANAGEMENT_2, 0, 0), +SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_DAC("DACL", "Playback", WM8993_POWER_MANAGEMENT_3, 1, 0), -SND_SOC_DAPM_DAC("DACR", "Playback", WM8993_POWER_MANAGEMENT_3, 0, 0), +SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &aifinl_mux), +SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &aifinr_mux), + +SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &sidetonel_mux), +SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &sidetoner_mux), + +SND_SOC_DAPM_DAC("DACL", NULL, WM8993_POWER_MANAGEMENT_3, 1, 0), +SND_SOC_DAPM_DAC("DACR", NULL, WM8993_POWER_MANAGEMENT_3, 0, 0), SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), @@ -875,10 +933,32 @@ static const struct snd_soc_dapm_route routes[] = { { "ADCR", NULL, "CLK_SYS" }, { "ADCR", NULL, "CLK_DSP" }, + { "AIFOUTL Mux", "Left", "ADCL" }, + { "AIFOUTL Mux", "Right", "ADCR" }, + { "AIFOUTR Mux", "Left", "ADCL" }, + { "AIFOUTR Mux", "Right", "ADCR" }, + + { "AIFOUTL", NULL, "AIFOUTL Mux" }, + { "AIFOUTR", NULL, "AIFOUTR Mux" }, + + { "DACL Mux", "Left", "AIFINL" }, + { "DACL Mux", "Right", "AIFINR" }, + { "DACR Mux", "Left", "AIFINL" }, + { "DACR Mux", "Right", "AIFINR" }, + + { "DACL Sidetone", "Left", "ADCL" }, + { "DACL Sidetone", "Right", "ADCR" }, + { "DACR Sidetone", "Left", "ADCL" }, + { "DACR Sidetone", "Right", "ADCR" }, + { "DACL", NULL, "CLK_SYS" }, { "DACL", NULL, "CLK_DSP" }, + { "DACL", NULL, "DACL Mux" }, + { "DACL", NULL, "DACL Sidetone" }, { "DACR", NULL, "CLK_SYS" }, { "DACR", NULL, "CLK_DSP" }, + { "DACR", NULL, "DACR Mux" }, + { "DACR", NULL, "DACR Sidetone" }, { "Left Output Mixer", "DAC Switch", "DACL" }, diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index fa88b463e71..e7d2840d9e5 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -406,7 +406,7 @@ static int wm9705_soc_probe(struct platform_device *pdev) ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm9705: failed to register card\n"); - goto pcm_err; + goto reset_err; } return 0; diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index abed37acf78..ca3d449ed89 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -800,8 +800,8 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, return 0; } -static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; return wm9713_set_pll(codec, pll_id, freq_in, freq_out); diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index e8fc474ba5c..e542027eea8 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -18,7 +18,6 @@ #include <linux/pm.h> #include <linux/i2c.h> #include <linux/platform_device.h> -#include <linux/regulator/consumer.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -274,17 +273,12 @@ static int hp_event(struct snd_soc_dapm_widget *w, /* Start the DC servo */ snd_soc_update_bits(codec, WM8993_DC_SERVO_0, - WM8993_DCS_ENA_CHAN_0 | - WM8993_DCS_ENA_CHAN_1 | - WM8993_DCS_TRIG_STARTUP_1 | - WM8993_DCS_TRIG_STARTUP_0, + 0xFFFF, WM8993_DCS_ENA_CHAN_0 | WM8993_DCS_ENA_CHAN_1 | WM8993_DCS_TRIG_STARTUP_1 | WM8993_DCS_TRIG_STARTUP_0); wait_for_dc_servo(codec); - snd_soc_update_bits(codec, WM8993_DC_SERVO_1, - WM8993_DCS_TIMER_PERIOD_01_MASK, 0xa); reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT | WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT; @@ -299,11 +293,8 @@ static int hp_event(struct snd_soc_dapm_widget *w, WM8993_HPOUT1R_DLY | WM8993_HPOUT1R_OUTP); - snd_soc_update_bits(codec, WM8993_DC_SERVO_1, - WM8993_DCS_TIMER_PERIOD_01_MASK, 0); snd_soc_update_bits(codec, WM8993_DC_SERVO_0, - WM8993_DCS_ENA_CHAN_0 | - WM8993_DCS_ENA_CHAN_1, 0); + 0xffff, 0); snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg); snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, @@ -474,12 +465,6 @@ SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0, SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0, mixinr, ARRAY_SIZE(mixinr)), -SND_SOC_DAPM_ADC("ADCL", "Capture", WM8993_POWER_MANAGEMENT_2, 1, 0), -SND_SOC_DAPM_ADC("ADCR", "Capture", WM8993_POWER_MANAGEMENT_2, 0, 0), - -SND_SOC_DAPM_DAC("DACL", "Playback", WM8993_POWER_MANAGEMENT_3, 1, 0), -SND_SOC_DAPM_DAC("DACR", "Playback", WM8993_POWER_MANAGEMENT_3, 0, 0), - SND_SOC_DAPM_MIXER("Left Output Mixer", WM8993_POWER_MANAGEMENT_3, 5, 0, left_output_mixer, ARRAY_SIZE(left_output_mixer)), SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0, |