aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/atmel/playpaq_wm8510.c24
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c2
-rw-r--r--sound/soc/codecs/Kconfig8
-rw-r--r--sound/soc/codecs/Makefile4
-rw-r--r--sound/soc/codecs/ad73311.h2
-rw-r--r--sound/soc/codecs/ak4104.c365
-rw-r--r--sound/soc/codecs/ak4104.h7
-rw-r--r--sound/soc/codecs/cs4270.c15
-rw-r--r--sound/soc/codecs/twl4030.c18
-rw-r--r--sound/soc/codecs/uda1380.c113
-rw-r--r--sound/soc/codecs/wm8400.c1481
-rw-r--r--sound/soc/codecs/wm8400.h62
-rw-r--r--sound/soc/codecs/wm8510.c4
-rw-r--r--sound/soc/codecs/wm8580.c4
-rw-r--r--sound/soc/codecs/wm8753.c5
-rw-r--r--sound/soc/davinci/Kconfig2
-rw-r--r--sound/soc/davinci/davinci-sffsdr.c20
-rw-r--r--sound/soc/fsl/fsl_dma.c3
-rw-r--r--sound/soc/fsl/fsl_ssi.c65
-rw-r--r--sound/soc/fsl/fsl_ssi.h2
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c5
-rw-r--r--sound/soc/omap/osk5912.c12
-rw-r--r--sound/soc/omap/sdp3430.c105
-rw-r--r--sound/soc/pxa/pxa-ssp.c20
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c38
-rw-r--r--sound/soc/pxa/zylonite.c7
-rw-r--r--sound/soc/s3c24xx/Kconfig28
-rw-r--r--sound/soc/s3c24xx/Makefile6
-rw-r--r--sound/soc/s3c24xx/jive_wm8750.c201
-rw-r--r--sound/soc/s3c24xx/neo1973_wm8753.c48
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.c638
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.h90
-rw-r--r--sound/soc/s3c24xx/s3c2412-i2s.c614
-rw-r--r--sound/soc/s3c24xx/s3c2412-i2s.h17
-rw-r--r--sound/soc/s3c24xx/s3c2443-ac97.c9
-rw-r--r--sound/soc/s3c24xx/s3c24xx-i2s.c53
-rw-r--r--sound/soc/s3c24xx/s3c24xx-pcm.c47
-rw-r--r--sound/soc/s3c24xx/s3c24xx_uda134x.c2
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.c220
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.h31
-rw-r--r--sound/soc/soc-dapm.c265
-rw-r--r--sound/soc/soc-jack.c129
42 files changed, 3823 insertions, 968 deletions
diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c
index 43dd8cee83c6..70657534e6b1 100644
--- a/sound/soc/atmel/playpaq_wm8510.c
+++ b/sound/soc/atmel/playpaq_wm8510.c
@@ -164,38 +164,38 @@ static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream,
164 */ 164 */
165 switch (params_rate(params)) { 165 switch (params_rate(params)) {
166 case 48000: 166 case 48000:
167 pll_out = 12288000; 167 pll_out = 24576000;
168 mclk_div = WM8510_MCLKDIV_1; 168 mclk_div = WM8510_MCLKDIV_2;
169 bclk = WM8510_BCLKDIV_8; 169 bclk = WM8510_BCLKDIV_8;
170 break; 170 break;
171 171
172 case 44100: 172 case 44100:
173 pll_out = 11289600; 173 pll_out = 22579200;
174 mclk_div = WM8510_MCLKDIV_1; 174 mclk_div = WM8510_MCLKDIV_2;
175 bclk = WM8510_BCLKDIV_8; 175 bclk = WM8510_BCLKDIV_8;
176 break; 176 break;
177 177
178 case 22050: 178 case 22050:
179 pll_out = 11289600; 179 pll_out = 22579200;
180 mclk_div = WM8510_MCLKDIV_2; 180 mclk_div = WM8510_MCLKDIV_4;
181 bclk = WM8510_BCLKDIV_8; 181 bclk = WM8510_BCLKDIV_8;
182 break; 182 break;
183 183
184 case 16000: 184 case 16000:
185 pll_out = 12288000; 185 pll_out = 24576000;
186 mclk_div = WM8510_MCLKDIV_3; 186 mclk_div = WM8510_MCLKDIV_6;
187 bclk = WM8510_BCLKDIV_8; 187 bclk = WM8510_BCLKDIV_8;
188 break; 188 break;
189 189
190 case 11025: 190 case 11025:
191 pll_out = 11289600; 191 pll_out = 22579200;
192 mclk_div = WM8510_MCLKDIV_4; 192 mclk_div = WM8510_MCLKDIV_8;
193 bclk = WM8510_BCLKDIV_8; 193 bclk = WM8510_BCLKDIV_8;
194 break; 194 break;
195 195
196 case 8000: 196 case 8000:
197 pll_out = 12288000; 197 pll_out = 24576000;
198 mclk_div = WM8510_MCLKDIV_6; 198 mclk_div = WM8510_MCLKDIV_12;
199 bclk = WM8510_BCLKDIV_8; 199 bclk = WM8510_BCLKDIV_8;
200 break; 200 break;
201 201
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index 5885702c78ff..8a935f2d1767 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -357,8 +357,8 @@ sport_config_err:
357sport_err: 357sport_err:
358#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET 358#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
359 gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); 359 gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
360#endif
361gpio_err: 360gpio_err:
361#endif
362 peripheral_free_list(sport_req[sport_num]); 362 peripheral_free_list(sport_req[sport_num]);
363peripheral_err: 363peripheral_err:
364 free_page((unsigned long)cmd_count); 364 free_page((unsigned long)cmd_count);
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 628a591c728f..b6c7f7a01cb0 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -14,6 +14,7 @@ config SND_SOC_ALL_CODECS
14 select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS 14 select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
15 select SND_SOC_AD1980 if SND_SOC_AC97_BUS 15 select SND_SOC_AD1980 if SND_SOC_AC97_BUS
16 select SND_SOC_AD73311 if I2C 16 select SND_SOC_AD73311 if I2C
17 select SND_SOC_AK4104 if SPI_MASTER
17 select SND_SOC_AK4535 if I2C 18 select SND_SOC_AK4535 if I2C
18 select SND_SOC_CS4270 if I2C 19 select SND_SOC_CS4270 if I2C
19 select SND_SOC_PCM3008 20 select SND_SOC_PCM3008
@@ -25,6 +26,7 @@ config SND_SOC_ALL_CODECS
25 select SND_SOC_UDA134X 26 select SND_SOC_UDA134X
26 select SND_SOC_UDA1380 if I2C 27 select SND_SOC_UDA1380 if I2C
27 select SND_SOC_WM8350 if MFD_WM8350 28 select SND_SOC_WM8350 if MFD_WM8350
29 select SND_SOC_WM8400 if MFD_WM8400
28 select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI 30 select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI
29 select SND_SOC_WM8580 if I2C 31 select SND_SOC_WM8580 if I2C
30 select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI 32 select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
@@ -60,6 +62,9 @@ config SND_SOC_AD1980
60config SND_SOC_AD73311 62config SND_SOC_AD73311
61 tristate 63 tristate
62 64
65config SND_SOC_AK4104
66 tristate
67
63config SND_SOC_AK4535 68config SND_SOC_AK4535
64 tristate 69 tristate
65 70
@@ -106,6 +111,9 @@ config SND_SOC_UDA1380
106config SND_SOC_WM8350 111config SND_SOC_WM8350
107 tristate 112 tristate
108 113
114config SND_SOC_WM8400
115 tristate
116
109config SND_SOC_WM8510 117config SND_SOC_WM8510
110 tristate 118 tristate
111 119
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 3664cdc300b2..030d2454725f 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,6 +1,7 @@
1snd-soc-ac97-objs := ac97.o 1snd-soc-ac97-objs := ac97.o
2snd-soc-ad1980-objs := ad1980.o 2snd-soc-ad1980-objs := ad1980.o
3snd-soc-ad73311-objs := ad73311.o 3snd-soc-ad73311-objs := ad73311.o
4snd-soc-ak4104-objs := ak4104.o
4snd-soc-ak4535-objs := ak4535.o 5snd-soc-ak4535-objs := ak4535.o
5snd-soc-cs4270-objs := cs4270.o 6snd-soc-cs4270-objs := cs4270.o
6snd-soc-l3-objs := l3.o 7snd-soc-l3-objs := l3.o
@@ -13,6 +14,7 @@ snd-soc-twl4030-objs := twl4030.o
13snd-soc-uda134x-objs := uda134x.o 14snd-soc-uda134x-objs := uda134x.o
14snd-soc-uda1380-objs := uda1380.o 15snd-soc-uda1380-objs := uda1380.o
15snd-soc-wm8350-objs := wm8350.o 16snd-soc-wm8350-objs := wm8350.o
17snd-soc-wm8400-objs := wm8400.o
16snd-soc-wm8510-objs := wm8510.o 18snd-soc-wm8510-objs := wm8510.o
17snd-soc-wm8580-objs := wm8580.o 19snd-soc-wm8580-objs := wm8580.o
18snd-soc-wm8728-objs := wm8728.o 20snd-soc-wm8728-objs := wm8728.o
@@ -30,6 +32,7 @@ snd-soc-wm9713-objs := wm9713.o
30obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o 32obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
31obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o 33obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
32obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o 34obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
35obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
33obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o 36obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
34obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o 37obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
35obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o 38obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
@@ -42,6 +45,7 @@ obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
42obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o 45obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
43obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o 46obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
44obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o 47obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o
48obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o
45obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o 49obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o
46obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o 50obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o
47obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o 51obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o
diff --git a/sound/soc/codecs/ad73311.h b/sound/soc/codecs/ad73311.h
index 507ce0c30edf..569573d2d4d7 100644
--- a/sound/soc/codecs/ad73311.h
+++ b/sound/soc/codecs/ad73311.h
@@ -70,7 +70,7 @@
70#define REGD_IGS(x) (x & 0x7) 70#define REGD_IGS(x) (x & 0x7)
71#define REGD_RMOD (1 << 3) 71#define REGD_RMOD (1 << 3)
72#define REGD_OGS(x) ((x & 0x7) << 4) 72#define REGD_OGS(x) ((x & 0x7) << 4)
73#define REGD_MUTE (x << 7) 73#define REGD_MUTE (1 << 7)
74 74
75/* Control register E */ 75/* Control register E */
76#define CTRL_REG_E (4 << 8) 76#define CTRL_REG_E (4 << 8)
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
new file mode 100644
index 000000000000..4d47bc4f7428
--- /dev/null
+++ b/sound/soc/codecs/ak4104.c
@@ -0,0 +1,365 @@
1/*
2 * AK4104 ALSA SoC (ASoC) driver
3 *
4 * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11
12#include <linux/module.h>
13#include <sound/core.h>
14#include <sound/soc.h>
15#include <sound/initval.h>
16#include <linux/spi/spi.h>
17#include <sound/asoundef.h>
18
19#include "ak4104.h"
20
21/* AK4104 registers addresses */
22#define AK4104_REG_CONTROL1 0x00
23#define AK4104_REG_RESERVED 0x01
24#define AK4104_REG_CONTROL2 0x02
25#define AK4104_REG_TX 0x03
26#define AK4104_REG_CHN_STATUS(x) ((x) + 0x04)
27#define AK4104_NUM_REGS 10
28
29#define AK4104_REG_MASK 0x1f
30#define AK4104_READ 0xc0
31#define AK4104_WRITE 0xe0
32#define AK4104_RESERVED_VAL 0x5b
33
34/* Bit masks for AK4104 registers */
35#define AK4104_CONTROL1_RSTN (1 << 0)
36#define AK4104_CONTROL1_PW (1 << 1)
37#define AK4104_CONTROL1_DIF0 (1 << 2)
38#define AK4104_CONTROL1_DIF1 (1 << 3)
39
40#define AK4104_CONTROL2_SEL0 (1 << 0)
41#define AK4104_CONTROL2_SEL1 (1 << 1)
42#define AK4104_CONTROL2_MODE (1 << 2)
43
44#define AK4104_TX_TXE (1 << 0)
45#define AK4104_TX_V (1 << 1)
46
47#define DRV_NAME "ak4104"
48
49struct ak4104_private {
50 struct snd_soc_codec codec;
51 u8 reg_cache[AK4104_NUM_REGS];
52};
53
54static int ak4104_fill_cache(struct snd_soc_codec *codec)
55{
56 int i;
57 u8 *reg_cache = codec->reg_cache;
58 struct spi_device *spi = codec->control_data;
59
60 for (i = 0; i < codec->reg_cache_size; i++) {
61 int ret = spi_w8r8(spi, i | AK4104_READ);
62 if (ret < 0) {
63 dev_err(&spi->dev, "SPI write failure\n");
64 return ret;
65 }
66
67 reg_cache[i] = ret;
68 }
69
70 return 0;
71}
72
73static unsigned int ak4104_read_reg_cache(struct snd_soc_codec *codec,
74 unsigned int reg)
75{
76 u8 *reg_cache = codec->reg_cache;
77
78 if (reg >= codec->reg_cache_size)
79 return -EINVAL;
80
81 return reg_cache[reg];
82}
83
84static int ak4104_spi_write(struct snd_soc_codec *codec, unsigned int reg,
85 unsigned int value)
86{
87 u8 *cache = codec->reg_cache;
88 struct spi_device *spi = codec->control_data;
89
90 if (reg >= codec->reg_cache_size)
91 return -EINVAL;
92
93 reg &= AK4104_REG_MASK;
94 reg |= AK4104_WRITE;
95
96 /* only write to the hardware if value has changed */
97 if (cache[reg] != value) {
98 u8 tmp[2] = { reg, value };
99 if (spi_write(spi, tmp, sizeof(tmp))) {
100 dev_err(&spi->dev, "SPI write failed\n");
101 return -EIO;
102 }
103
104 cache[reg] = value;
105 }
106
107 return 0;
108}
109
110static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
111 unsigned int format)
112{
113 struct snd_soc_codec *codec = codec_dai->codec;
114 int val = 0;
115
116 val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
117 if (val < 0)
118 return val;
119
120 val &= ~(AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1);
121
122 /* set DAI format */
123 switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
124 case SND_SOC_DAIFMT_RIGHT_J:
125 break;
126 case SND_SOC_DAIFMT_LEFT_J:
127 val |= AK4104_CONTROL1_DIF0;
128 break;
129 case SND_SOC_DAIFMT_I2S:
130 val |= AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1;
131 break;
132 default:
133 dev_err(codec->dev, "invalid dai format\n");
134 return -EINVAL;
135 }
136
137 /* This device can only be slave */
138 if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
139 return -EINVAL;
140
141 return ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
142}
143
144static int ak4104_hw_params(struct snd_pcm_substream *substream,
145 struct snd_pcm_hw_params *params,
146 struct snd_soc_dai *dai)
147{
148 struct snd_soc_pcm_runtime *rtd = substream->private_data;
149 struct snd_soc_device *socdev = rtd->socdev;
150 struct snd_soc_codec *codec = socdev->card->codec;
151 int val = 0;
152
153 /* set the IEC958 bits: consumer mode, no copyright bit */
154 val |= IEC958_AES0_CON_NOT_COPYRIGHT;
155 ak4104_spi_write(codec, AK4104_REG_CHN_STATUS(0), val);
156
157 val = 0;
158
159 switch (params_rate(params)) {
160 case 44100:
161 val |= IEC958_AES3_CON_FS_44100;
162 break;
163 case 48000:
164 val |= IEC958_AES3_CON_FS_48000;
165 break;
166 case 32000:
167 val |= IEC958_AES3_CON_FS_32000;
168 break;
169 default:
170 dev_err(codec->dev, "unsupported sampling rate\n");
171 return -EINVAL;
172 }
173
174 return ak4104_spi_write(codec, AK4104_REG_CHN_STATUS(3), val);
175}
176
177static struct snd_soc_dai_ops ak4101_dai_ops = {
178 .hw_params = ak4104_hw_params,
179 .set_fmt = ak4104_set_dai_fmt,
180};
181
182struct snd_soc_dai ak4104_dai = {
183 .name = DRV_NAME,
184 .playback = {
185 .stream_name = "Playback",
186 .channels_min = 2,
187 .channels_max = 2,
188 .rates = SNDRV_PCM_RATE_44100 |
189 SNDRV_PCM_RATE_48000 |
190 SNDRV_PCM_RATE_32000,
191 .formats = SNDRV_PCM_FMTBIT_S16_LE |
192 SNDRV_PCM_FMTBIT_S24_3LE |
193 SNDRV_PCM_FMTBIT_S24_LE
194 },
195 .ops = &ak4101_dai_ops,
196};
197
198static struct snd_soc_codec *ak4104_codec;
199
200static int ak4104_spi_probe(struct spi_device *spi)
201{
202 struct snd_soc_codec *codec;
203 struct ak4104_private *ak4104;
204 int ret, val;
205
206 spi->bits_per_word = 8;
207 spi->mode = SPI_MODE_0;
208 ret = spi_setup(spi);
209 if (ret < 0)
210 return ret;
211
212 ak4104 = kzalloc(sizeof(struct ak4104_private), GFP_KERNEL);
213 if (!ak4104) {
214 dev_err(&spi->dev, "could not allocate codec\n");
215 return -ENOMEM;
216 }
217
218 codec = &ak4104->codec;
219 mutex_init(&codec->mutex);
220 INIT_LIST_HEAD(&codec->dapm_widgets);
221 INIT_LIST_HEAD(&codec->dapm_paths);
222
223 codec->dev = &spi->dev;
224 codec->name = DRV_NAME;
225 codec->owner = THIS_MODULE;
226 codec->dai = &ak4104_dai;
227 codec->num_dai = 1;
228 codec->private_data = ak4104;
229 codec->control_data = spi;
230 codec->reg_cache = ak4104->reg_cache;
231 codec->reg_cache_size = AK4104_NUM_REGS;
232
233 /* read all regs and fill the cache */
234 ret = ak4104_fill_cache(codec);
235 if (ret < 0) {
236 dev_err(&spi->dev, "failed to fill register cache\n");
237 return ret;
238 }
239
240 /* read the 'reserved' register - according to the datasheet, it
241 * should contain 0x5b. Not a good way to verify the presence of
242 * the device, but there is no hardware ID register. */
243 if (ak4104_read_reg_cache(codec, AK4104_REG_RESERVED) !=
244 AK4104_RESERVED_VAL) {
245 ret = -ENODEV;
246 goto error_free_codec;
247 }
248
249 /* set power-up and non-reset bits */
250 val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
251 val |= AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN;
252 ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
253 if (ret < 0)
254 goto error_free_codec;
255
256 /* enable transmitter */
257 val = ak4104_read_reg_cache(codec, AK4104_REG_TX);
258 val |= AK4104_TX_TXE;
259 ret = ak4104_spi_write(codec, AK4104_REG_TX, val);
260 if (ret < 0)
261 goto error_free_codec;
262
263 ak4104_codec = codec;
264 ret = snd_soc_register_dai(&ak4104_dai);
265 if (ret < 0) {
266 dev_err(&spi->dev, "failed to register DAI\n");
267 goto error_free_codec;
268 }
269
270 spi_set_drvdata(spi, ak4104);
271 dev_info(&spi->dev, "SPI device initialized\n");
272 return 0;
273
274error_free_codec:
275 kfree(ak4104);
276 ak4104_dai.dev = NULL;
277 return ret;
278}
279
280static int __devexit ak4104_spi_remove(struct spi_device *spi)
281{
282 int ret, val;
283 struct ak4104_private *ak4104 = spi_get_drvdata(spi);
284
285 val = ak4104_read_reg_cache(&ak4104->codec, AK4104_REG_CONTROL1);
286 if (val < 0)
287 return val;
288
289 /* clear power-up and non-reset bits */
290 val &= ~(AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
291 ret = ak4104_spi_write(&ak4104->codec, AK4104_REG_CONTROL1, val);
292 if (ret < 0)
293 return ret;
294
295 ak4104_codec = NULL;
296 kfree(ak4104);
297 return 0;
298}
299
300static int ak4104_probe(struct platform_device *pdev)
301{
302 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
303 struct snd_soc_codec *codec = ak4104_codec;
304 int ret;
305
306 /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */
307 socdev->card->codec = codec;
308
309 /* Register PCMs */
310 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
311 if (ret < 0) {
312 dev_err(codec->dev, "failed to create pcms\n");
313 return ret;
314 }
315
316 /* Register the socdev */
317 ret = snd_soc_init_card(socdev);
318 if (ret < 0) {
319 dev_err(codec->dev, "failed to register card\n");
320 snd_soc_free_pcms(socdev);
321 return ret;
322 }
323
324 return 0;
325}
326
327static int ak4104_remove(struct platform_device *pdev)
328{
329 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
330 snd_soc_free_pcms(socdev);
331 return 0;
332};
333
334struct snd_soc_codec_device soc_codec_device_ak4104 = {
335 .probe = ak4104_probe,
336 .remove = ak4104_remove
337};
338EXPORT_SYMBOL_GPL(soc_codec_device_ak4104);
339
340static struct spi_driver ak4104_spi_driver = {
341 .driver = {
342 .name = DRV_NAME,
343 .owner = THIS_MODULE,
344 },
345 .probe = ak4104_spi_probe,
346 .remove = __devexit_p(ak4104_spi_remove),
347};
348
349static int __init ak4104_init(void)
350{
351 pr_info("Asahi Kasei AK4104 ALSA SoC Codec Driver\n");
352 return spi_register_driver(&ak4104_spi_driver);
353}
354module_init(ak4104_init);
355
356static void __exit ak4104_exit(void)
357{
358 spi_unregister_driver(&ak4104_spi_driver);
359}
360module_exit(ak4104_exit);
361
362MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
363MODULE_DESCRIPTION("Asahi Kasei AK4104 ALSA SoC driver");
364MODULE_LICENSE("GPL");
365
diff --git a/sound/soc/codecs/ak4104.h b/sound/soc/codecs/ak4104.h
new file mode 100644
index 000000000000..eb88fe7e4def
--- /dev/null
+++ b/sound/soc/codecs/ak4104.h
@@ -0,0 +1,7 @@
1#ifndef _AK4104_H
2#define _AK4104_H
3
4extern struct snd_soc_dai ak4104_dai;
5extern struct snd_soc_codec_device soc_codec_device_ak4104;
6
7#endif
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 7ae3d6520e3f..2137670c9b78 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -12,14 +12,13 @@
12 * 12 *
13 * Current features/limitations: 13 * Current features/limitations:
14 * 14 *
15 * 1) Software mode is supported. Stand-alone mode is not supported. 15 * - Software mode is supported. Stand-alone mode is not supported.
16 * 2) Only I2C is supported, not SPI 16 * - Only I2C is supported, not SPI
17 * 3) Only Master mode is supported, not Slave. 17 * - Support for master and slave mode
18 * 4) The machine driver's 'startup' function must call 18 * - The machine driver's 'startup' function must call
19 * cs4270_set_dai_sysclk() with the value of MCLK. 19 * cs4270_set_dai_sysclk() with the value of MCLK.
20 * 5) Only I2S and left-justified modes are supported 20 * - Only I2S and left-justified modes are supported
21 * 6) Power management is not supported 21 * - Power management is not supported
22 * 7) The only supported control is volume and hardware mute (if enabled)
23 */ 22 */
24 23
25#include <linux/module.h> 24#include <linux/module.h>
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 535d8ce2c328..86bb15cc82ce 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -584,12 +584,11 @@ static int headsetl_event(struct snd_soc_dapm_widget *w,
584 584
585 /* Save the current volume */ 585 /* Save the current volume */
586 hs_gain = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_GAIN_SET); 586 hs_gain = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_GAIN_SET);
587 hs_pop = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_POPN_SET);
587 588
588 switch (event) { 589 switch (event) {
589 case SND_SOC_DAPM_POST_PMU: 590 case SND_SOC_DAPM_POST_PMU:
590 /* Do the anti-pop/bias ramp enable according to the TRM */ 591 /* Do the anti-pop/bias ramp enable according to the TRM */
591 hs_pop = TWL4030_RAMP_DELAY_645MS;
592 twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
593 hs_pop |= TWL4030_VMID_EN; 592 hs_pop |= TWL4030_VMID_EN;
594 twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop); 593 twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
595 /* Is this needed? Can we just use whatever gain here? */ 594 /* Is this needed? Can we just use whatever gain here? */
@@ -603,8 +602,6 @@ static int headsetl_event(struct snd_soc_dapm_widget *w,
603 break; 602 break;
604 case SND_SOC_DAPM_POST_PMD: 603 case SND_SOC_DAPM_POST_PMD:
605 /* Do the anti-pop/bias ramp disable according to the TRM */ 604 /* Do the anti-pop/bias ramp disable according to the TRM */
606 hs_pop = twl4030_read_reg_cache(w->codec,
607 TWL4030_REG_HS_POPN_SET);
608 hs_pop &= ~TWL4030_RAMP_EN; 605 hs_pop &= ~TWL4030_RAMP_EN;
609 twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop); 606 twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
610 /* Bypass the reg_cache to mute the headset */ 607 /* Bypass the reg_cache to mute the headset */
@@ -847,6 +844,17 @@ static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0);
847 */ 844 */
848static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0); 845static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0);
849 846
847static const char *twl4030_rampdelay_texts[] = {
848 "27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms",
849 "437/323/218 ms", "874/645/437 ms", "1748/1291/874 ms",
850 "3495/2581/1748 ms"
851};
852
853static const struct soc_enum twl4030_rampdelay_enum =
854 SOC_ENUM_SINGLE(TWL4030_REG_HS_POPN_SET, 2,
855 ARRAY_SIZE(twl4030_rampdelay_texts),
856 twl4030_rampdelay_texts);
857
850static const struct snd_kcontrol_new twl4030_snd_controls[] = { 858static const struct snd_kcontrol_new twl4030_snd_controls[] = {
851 /* Common playback gain controls */ 859 /* Common playback gain controls */
852 SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume", 860 SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume",
@@ -901,6 +909,8 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = {
901 909
902 SOC_DOUBLE_TLV("Analog Capture Volume", TWL4030_REG_ANAMIC_GAIN, 910 SOC_DOUBLE_TLV("Analog Capture Volume", TWL4030_REG_ANAMIC_GAIN,
903 0, 3, 5, 0, input_gain_tlv), 911 0, 3, 5, 0, input_gain_tlv),
912
913 SOC_ENUM("HS ramp delay", twl4030_rampdelay_enum),
904}; 914};
905 915
906static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { 916static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index cafa7684c0e7..5b21594e0e58 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -25,6 +25,7 @@
25#include <linux/ioctl.h> 25#include <linux/ioctl.h>
26#include <linux/delay.h> 26#include <linux/delay.h>
27#include <linux/i2c.h> 27#include <linux/i2c.h>
28#include <linux/workqueue.h>
28#include <sound/core.h> 29#include <sound/core.h>
29#include <sound/control.h> 30#include <sound/control.h>
30#include <sound/initval.h> 31#include <sound/initval.h>
@@ -35,7 +36,8 @@
35 36
36#include "uda1380.h" 37#include "uda1380.h"
37 38
38#define UDA1380_VERSION "0.6" 39static struct work_struct uda1380_work;
40static struct snd_soc_codec *uda1380_codec;
39 41
40/* 42/*
41 * uda1380 register cache 43 * uda1380 register cache
@@ -52,6 +54,8 @@ static const u16 uda1380_reg[UDA1380_CACHEREGNUM] = {
52 0x0000, 0x8000, 0x0002, 0x0000, 54 0x0000, 0x8000, 0x0002, 0x0000,
53}; 55};
54 56
57static unsigned long uda1380_cache_dirty;
58
55/* 59/*
56 * read uda1380 register cache 60 * read uda1380 register cache
57 */ 61 */
@@ -73,8 +77,11 @@ static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec,
73 u16 reg, unsigned int value) 77 u16 reg, unsigned int value)
74{ 78{
75 u16 *cache = codec->reg_cache; 79 u16 *cache = codec->reg_cache;
80
76 if (reg >= UDA1380_CACHEREGNUM) 81 if (reg >= UDA1380_CACHEREGNUM)
77 return; 82 return;
83 if ((reg >= 0x10) && (cache[reg] != value))
84 set_bit(reg - 0x10, &uda1380_cache_dirty);
78 cache[reg] = value; 85 cache[reg] = value;
79} 86}
80 87
@@ -113,6 +120,8 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
113 (data[0]<<8) | data[1]); 120 (data[0]<<8) | data[1]);
114 return -EIO; 121 return -EIO;
115 } 122 }
123 if (reg >= 0x10)
124 clear_bit(reg - 0x10, &uda1380_cache_dirty);
116 return 0; 125 return 0;
117 } else 126 } else
118 return -EIO; 127 return -EIO;
@@ -120,6 +129,20 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
120 129
121#define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0) 130#define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0)
122 131
132static void uda1380_flush_work(struct work_struct *work)
133{
134 int bit, reg;
135
136 for_each_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) {
137 reg = 0x10 + bit;
138 pr_debug("uda1380: flush reg %x val %x:\n", reg,
139 uda1380_read_reg_cache(uda1380_codec, reg));
140 uda1380_write(uda1380_codec, reg,
141 uda1380_read_reg_cache(uda1380_codec, reg));
142 clear_bit(bit, &uda1380_cache_dirty);
143 }
144}
145
123/* declarations of ALSA reg_elem_REAL controls */ 146/* declarations of ALSA reg_elem_REAL controls */
124static const char *uda1380_deemp[] = { 147static const char *uda1380_deemp[] = {
125 "None", 148 "None",
@@ -254,7 +277,6 @@ static const struct snd_kcontrol_new uda1380_snd_controls[] = {
254 SOC_SINGLE("DAC Polarity inverting Switch", UDA1380_MIXER, 15, 1, 0), /* DA_POL_INV */ 277 SOC_SINGLE("DAC Polarity inverting Switch", UDA1380_MIXER, 15, 1, 0), /* DA_POL_INV */
255 SOC_ENUM("Noise Shaper", uda1380_sel_ns_enum), /* SEL_NS */ 278 SOC_ENUM("Noise Shaper", uda1380_sel_ns_enum), /* SEL_NS */
256 SOC_ENUM("Digital Mixer Signal Control", uda1380_mix_enum), /* MIX_POS, MIX */ 279 SOC_ENUM("Digital Mixer Signal Control", uda1380_mix_enum), /* MIX_POS, MIX */
257 SOC_SINGLE("Silence Switch", UDA1380_MIXER, 7, 1, 0), /* SILENCE, force DAC output to silence */
258 SOC_SINGLE("Silence Detector Switch", UDA1380_MIXER, 6, 1, 0), /* SDET_ON */ 280 SOC_SINGLE("Silence Detector Switch", UDA1380_MIXER, 6, 1, 0), /* SDET_ON */
259 SOC_ENUM("Silence Detector Setting", uda1380_sdet_enum), /* SD_VALUE */ 281 SOC_ENUM("Silence Detector Setting", uda1380_sdet_enum), /* SD_VALUE */
260 SOC_ENUM("Oversampling Input", uda1380_os_enum), /* OS */ 282 SOC_ENUM("Oversampling Input", uda1380_os_enum), /* OS */
@@ -377,8 +399,9 @@ static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai,
377 iface |= R01_SFORI_MSB | R01_SFORO_MSB; 399 iface |= R01_SFORI_MSB | R01_SFORO_MSB;
378 } 400 }
379 401
380 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) 402 /* DATAI is slave only, so in single-link mode, this has to be slave */
381 iface |= R01_SIM; 403 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
404 return -EINVAL;
382 405
383 uda1380_write(codec, UDA1380_IFACE, iface); 406 uda1380_write(codec, UDA1380_IFACE, iface);
384 407
@@ -406,6 +429,10 @@ static int uda1380_set_dai_fmt_playback(struct snd_soc_dai *codec_dai,
406 iface |= R01_SFORI_MSB; 429 iface |= R01_SFORI_MSB;
407 } 430 }
408 431
432 /* DATAI is slave only, so this has to be slave */
433 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
434 return -EINVAL;
435
409 uda1380_write(codec, UDA1380_IFACE, iface); 436 uda1380_write(codec, UDA1380_IFACE, iface);
410 437
411 return 0; 438 return 0;
@@ -440,41 +467,28 @@ static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai,
440 return 0; 467 return 0;
441} 468}
442 469
443/* 470static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
444 * Flush reg cache 471 struct snd_soc_dai *dai)
445 * We can only write the interpolator and decimator registers
446 * when the DAI is being clocked by the CPU DAI. It's up to the
447 * machine and cpu DAI driver to do this before we are called.
448 */
449static int uda1380_pcm_prepare(struct snd_pcm_substream *substream,
450 struct snd_soc_dai *dai)
451{ 472{
452 struct snd_soc_pcm_runtime *rtd = substream->private_data; 473 struct snd_soc_pcm_runtime *rtd = substream->private_data;
453 struct snd_soc_device *socdev = rtd->socdev; 474 struct snd_soc_device *socdev = rtd->socdev;
454 struct snd_soc_codec *codec = socdev->card->codec; 475 struct snd_soc_codec *codec = socdev->card->codec;
455 int reg, reg_start, reg_end, clk; 476 int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
456 477
457 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 478 switch (cmd) {
458 reg_start = UDA1380_MVOL; 479 case SNDRV_PCM_TRIGGER_START:
459 reg_end = UDA1380_MIXER; 480 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
460 } else { 481 uda1380_write_reg_cache(codec, UDA1380_MIXER,
461 reg_start = UDA1380_DEC; 482 mixer & ~R14_SILENCE);
462 reg_end = UDA1380_AGC; 483 schedule_work(&uda1380_work);
463 } 484 break;
464 485 case SNDRV_PCM_TRIGGER_STOP:
465 /* FIXME disable DAC_CLK */ 486 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
466 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); 487 uda1380_write_reg_cache(codec, UDA1380_MIXER,
467 uda1380_write(codec, UDA1380_CLK, clk & ~R00_DAC_CLK); 488 mixer | R14_SILENCE);
468 489 schedule_work(&uda1380_work);
469 for (reg = reg_start; reg <= reg_end; reg++) { 490 break;
470 pr_debug("uda1380: flush reg %x val %x:", reg,
471 uda1380_read_reg_cache(codec, reg));
472 uda1380_write(codec, reg, uda1380_read_reg_cache(codec, reg));
473 } 491 }
474
475 /* FIXME restore DAC_CLK */
476 uda1380_write(codec, UDA1380_CLK, clk);
477
478 return 0; 492 return 0;
479} 493}
480 494
@@ -540,24 +554,6 @@ static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
540 uda1380_write(codec, UDA1380_CLK, clk); 554 uda1380_write(codec, UDA1380_CLK, clk);
541} 555}
542 556
543static int uda1380_mute(struct snd_soc_dai *codec_dai, int mute)
544{
545 struct snd_soc_codec *codec = codec_dai->codec;
546 u16 mute_reg = uda1380_read_reg_cache(codec, UDA1380_DEEMP) & ~R13_MTM;
547
548 /* FIXME: mute(codec,0) is called when the magician clock is already
549 * set to WSPLL, but for some unknown reason writing to interpolator
550 * registers works only when clocked by SYSCLK */
551 u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
552 uda1380_write(codec, UDA1380_CLK, ~R00_DAC_CLK & clk);
553 if (mute)
554 uda1380_write(codec, UDA1380_DEEMP, mute_reg | R13_MTM);
555 else
556 uda1380_write(codec, UDA1380_DEEMP, mute_reg);
557 uda1380_write(codec, UDA1380_CLK, clk);
558 return 0;
559}
560
561static int uda1380_set_bias_level(struct snd_soc_codec *codec, 557static int uda1380_set_bias_level(struct snd_soc_codec *codec,
562 enum snd_soc_bias_level level) 558 enum snd_soc_bias_level level)
563{ 559{
@@ -586,23 +582,21 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
586static struct snd_soc_dai_ops uda1380_dai_ops = { 582static struct snd_soc_dai_ops uda1380_dai_ops = {
587 .hw_params = uda1380_pcm_hw_params, 583 .hw_params = uda1380_pcm_hw_params,
588 .shutdown = uda1380_pcm_shutdown, 584 .shutdown = uda1380_pcm_shutdown,
589 .prepare = uda1380_pcm_prepare, 585 .trigger = uda1380_trigger,
590 .digital_mute = uda1380_mute,
591 .set_fmt = uda1380_set_dai_fmt_both, 586 .set_fmt = uda1380_set_dai_fmt_both,
592}; 587};
593 588
594static struct snd_soc_dai_ops uda1380_dai_ops_playback = { 589static struct snd_soc_dai_ops uda1380_dai_ops_playback = {
595 .hw_params = uda1380_pcm_hw_params, 590 .hw_params = uda1380_pcm_hw_params,
596 .shutdown = uda1380_pcm_shutdown, 591 .shutdown = uda1380_pcm_shutdown,
597 .prepare = uda1380_pcm_prepare, 592 .trigger = uda1380_trigger,
598 .digital_mute = uda1380_mute,
599 .set_fmt = uda1380_set_dai_fmt_playback, 593 .set_fmt = uda1380_set_dai_fmt_playback,
600}; 594};
601 595
602static struct snd_soc_dai_ops uda1380_dai_ops_capture = { 596static struct snd_soc_dai_ops uda1380_dai_ops_capture = {
603 .hw_params = uda1380_pcm_hw_params, 597 .hw_params = uda1380_pcm_hw_params,
604 .shutdown = uda1380_pcm_shutdown, 598 .shutdown = uda1380_pcm_shutdown,
605 .prepare = uda1380_pcm_prepare, 599 .trigger = uda1380_trigger,
606 .set_fmt = uda1380_set_dai_fmt_capture, 600 .set_fmt = uda1380_set_dai_fmt_capture,
607}; 601};
608 602
@@ -700,6 +694,9 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk)
700 codec->reg_cache_step = 1; 694 codec->reg_cache_step = 1;
701 uda1380_reset(codec); 695 uda1380_reset(codec);
702 696
697 uda1380_codec = codec;
698 INIT_WORK(&uda1380_work, uda1380_flush_work);
699
703 /* register pcms */ 700 /* register pcms */
704 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); 701 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
705 if (ret < 0) { 702 if (ret < 0) {
@@ -832,8 +829,6 @@ static int uda1380_probe(struct platform_device *pdev)
832 struct snd_soc_codec *codec; 829 struct snd_soc_codec *codec;
833 int ret; 830 int ret;
834 831
835 pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION);
836
837 setup = socdev->codec_data; 832 setup = socdev->codec_data;
838 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); 833 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
839 if (codec == NULL) 834 if (codec == NULL)
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
new file mode 100644
index 000000000000..4e1cefff8483
--- /dev/null
+++ b/sound/soc/codecs/wm8400.c
@@ -0,0 +1,1481 @@
1/*
2 * wm8400.c -- WM8400 ALSA Soc Audio driver
3 *
4 * Copyright 2008, 2009 Wolfson Microelectronics PLC.
5 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/kernel.h>
17#include <linux/init.h>
18#include <linux/delay.h>
19#include <linux/pm.h>
20#include <linux/platform_device.h>
21#include <linux/regulator/consumer.h>
22#include <linux/mfd/wm8400-audio.h>
23#include <linux/mfd/wm8400-private.h>
24#include <sound/core.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/soc.h>
28#include <sound/soc-dapm.h>
29#include <sound/initval.h>
30#include <sound/tlv.h>
31
32#include "wm8400.h"
33
34/* Fake register for internal state */
35#define WM8400_INTDRIVBITS (WM8400_REGISTER_COUNT + 1)
36#define WM8400_INMIXL_PWR 0
37#define WM8400_AINLMUX_PWR 1
38#define WM8400_INMIXR_PWR 2
39#define WM8400_AINRMUX_PWR 3
40
41static struct regulator_bulk_data power[] = {
42 {
43 .supply = "I2S1VDD",
44 },
45 {
46 .supply = "I2S2VDD",
47 },
48 {
49 .supply = "DCVDD",
50 },
51 {
52 .supply = "FLLVDD",
53 },
54 {
55 .supply = "HPVDD",
56 },
57 {
58 .supply = "SPKVDD",
59 },
60};
61
62/* codec private data */
63struct wm8400_priv {
64 struct snd_soc_codec codec;
65 struct wm8400 *wm8400;
66 u16 fake_register;
67 unsigned int sysclk;
68 unsigned int pcmclk;
69 struct work_struct work;
70};
71
72static inline unsigned int wm8400_read(struct snd_soc_codec *codec,
73 unsigned int reg)
74{
75 struct wm8400_priv *wm8400 = codec->private_data;
76
77 if (reg == WM8400_INTDRIVBITS)
78 return wm8400->fake_register;
79 else
80 return wm8400_reg_read(wm8400->wm8400, reg);
81}
82
83/*
84 * write to the wm8400 register space
85 */
86static int wm8400_write(struct snd_soc_codec *codec, unsigned int reg,
87 unsigned int value)
88{
89 struct wm8400_priv *wm8400 = codec->private_data;
90
91 if (reg == WM8400_INTDRIVBITS) {
92 wm8400->fake_register = value;
93 return 0;
94 } else
95 return wm8400_set_bits(wm8400->wm8400, reg, 0xffff, value);
96}
97
98static void wm8400_codec_reset(struct snd_soc_codec *codec)
99{
100 struct wm8400_priv *wm8400 = codec->private_data;
101
102 wm8400_reset_codec_reg_cache(wm8400->wm8400);
103}
104
105static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600);
106
107static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000);
108
109static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, -2100, 0);
110
111static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600);
112
113static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0);
114
115static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0);
116
117static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763);
118
119static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0);
120
121static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
122 struct snd_ctl_elem_value *ucontrol)
123{
124 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
125 struct soc_mixer_control *mc =
126 (struct soc_mixer_control *)kcontrol->private_value;
127 int reg = mc->reg;
128 int ret;
129 u16 val;
130
131 ret = snd_soc_put_volsw(kcontrol, ucontrol);
132 if (ret < 0)
133 return ret;
134
135 /* now hit the volume update bits (always bit 8) */
136 val = wm8400_read(codec, reg);
137 return wm8400_write(codec, reg, val | 0x0100);
138}
139
140#define WM8400_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert, tlv_array) \
141{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
142 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
143 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
144 .tlv.p = (tlv_array), \
145 .info = snd_soc_info_volsw, \
146 .get = snd_soc_get_volsw, .put = wm8400_outpga_put_volsw_vu, \
147 .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
148
149
150static const char *wm8400_digital_sidetone[] =
151 {"None", "Left ADC", "Right ADC", "Reserved"};
152
153static const struct soc_enum wm8400_left_digital_sidetone_enum =
154SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE,
155 WM8400_ADC_TO_DACL_SHIFT, 2, wm8400_digital_sidetone);
156
157static const struct soc_enum wm8400_right_digital_sidetone_enum =
158SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE,
159 WM8400_ADC_TO_DACR_SHIFT, 2, wm8400_digital_sidetone);
160
161static const char *wm8400_adcmode[] =
162 {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};
163
164static const struct soc_enum wm8400_right_adcmode_enum =
165SOC_ENUM_SINGLE(WM8400_ADC_CTRL, WM8400_ADC_HPF_CUT_SHIFT, 3, wm8400_adcmode);
166
167static const struct snd_kcontrol_new wm8400_snd_controls[] = {
168/* INMIXL */
169SOC_SINGLE("LIN12 PGA Boost", WM8400_INPUT_MIXER3, WM8400_L12MNBST_SHIFT,
170 1, 0),
171SOC_SINGLE("LIN34 PGA Boost", WM8400_INPUT_MIXER3, WM8400_L34MNBST_SHIFT,
172 1, 0),
173/* INMIXR */
174SOC_SINGLE("RIN12 PGA Boost", WM8400_INPUT_MIXER3, WM8400_R12MNBST_SHIFT,
175 1, 0),
176SOC_SINGLE("RIN34 PGA Boost", WM8400_INPUT_MIXER3, WM8400_R34MNBST_SHIFT,
177 1, 0),
178
179/* LOMIX */
180SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8400_OUTPUT_MIXER3,
181 WM8400_LLI3LOVOL_SHIFT, 7, 0, out_mix_tlv),
182SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER3,
183 WM8400_LR12LOVOL_SHIFT, 7, 0, out_mix_tlv),
184SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER3,
185 WM8400_LL12LOVOL_SHIFT, 7, 0, out_mix_tlv),
186SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8400_OUTPUT_MIXER5,
187 WM8400_LRI3LOVOL_SHIFT, 7, 0, out_mix_tlv),
188SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8400_OUTPUT_MIXER5,
189 WM8400_LRBLOVOL_SHIFT, 7, 0, out_mix_tlv),
190SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8400_OUTPUT_MIXER5,
191 WM8400_LRBLOVOL_SHIFT, 7, 0, out_mix_tlv),
192
193/* ROMIX */
194SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8400_OUTPUT_MIXER4,
195 WM8400_RRI3ROVOL_SHIFT, 7, 0, out_mix_tlv),
196SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER4,
197 WM8400_RL12ROVOL_SHIFT, 7, 0, out_mix_tlv),
198SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER4,
199 WM8400_RR12ROVOL_SHIFT, 7, 0, out_mix_tlv),
200SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8400_OUTPUT_MIXER6,
201 WM8400_RLI3ROVOL_SHIFT, 7, 0, out_mix_tlv),
202SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8400_OUTPUT_MIXER6,
203 WM8400_RLBROVOL_SHIFT, 7, 0, out_mix_tlv),
204SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8400_OUTPUT_MIXER6,
205 WM8400_RRBROVOL_SHIFT, 7, 0, out_mix_tlv),
206
207/* LOUT */
208WM8400_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8400_LEFT_OUTPUT_VOLUME,
209 WM8400_LOUTVOL_SHIFT, WM8400_LOUTVOL_MASK, 0, out_pga_tlv),
210SOC_SINGLE("LOUT ZC", WM8400_LEFT_OUTPUT_VOLUME, WM8400_LOZC_SHIFT, 1, 0),
211
212/* ROUT */
213WM8400_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8400_RIGHT_OUTPUT_VOLUME,
214 WM8400_ROUTVOL_SHIFT, WM8400_ROUTVOL_MASK, 0, out_pga_tlv),
215SOC_SINGLE("ROUT ZC", WM8400_RIGHT_OUTPUT_VOLUME, WM8400_ROZC_SHIFT, 1, 0),
216
217/* LOPGA */
218WM8400_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8400_LEFT_OPGA_VOLUME,
219 WM8400_LOPGAVOL_SHIFT, WM8400_LOPGAVOL_MASK, 0, out_pga_tlv),
220SOC_SINGLE("LOPGA ZC Switch", WM8400_LEFT_OPGA_VOLUME,
221 WM8400_LOPGAZC_SHIFT, 1, 0),
222
223/* ROPGA */
224WM8400_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8400_RIGHT_OPGA_VOLUME,
225 WM8400_ROPGAVOL_SHIFT, WM8400_ROPGAVOL_MASK, 0, out_pga_tlv),
226SOC_SINGLE("ROPGA ZC Switch", WM8400_RIGHT_OPGA_VOLUME,
227 WM8400_ROPGAZC_SHIFT, 1, 0),
228
229SOC_SINGLE("LON Mute Switch", WM8400_LINE_OUTPUTS_VOLUME,
230 WM8400_LONMUTE_SHIFT, 1, 0),
231SOC_SINGLE("LOP Mute Switch", WM8400_LINE_OUTPUTS_VOLUME,
232 WM8400_LOPMUTE_SHIFT, 1, 0),
233SOC_SINGLE("LOP Attenuation Switch", WM8400_LINE_OUTPUTS_VOLUME,
234 WM8400_LOATTN_SHIFT, 1, 0),
235SOC_SINGLE("RON Mute Switch", WM8400_LINE_OUTPUTS_VOLUME,
236 WM8400_RONMUTE_SHIFT, 1, 0),
237SOC_SINGLE("ROP Mute Switch", WM8400_LINE_OUTPUTS_VOLUME,
238 WM8400_ROPMUTE_SHIFT, 1, 0),
239SOC_SINGLE("ROP Attenuation Switch", WM8400_LINE_OUTPUTS_VOLUME,
240 WM8400_ROATTN_SHIFT, 1, 0),
241
242SOC_SINGLE("OUT3 Mute Switch", WM8400_OUT3_4_VOLUME,
243 WM8400_OUT3MUTE_SHIFT, 1, 0),
244SOC_SINGLE("OUT3 Attenuation Switch", WM8400_OUT3_4_VOLUME,
245 WM8400_OUT3ATTN_SHIFT, 1, 0),
246
247SOC_SINGLE("OUT4 Mute Switch", WM8400_OUT3_4_VOLUME,
248 WM8400_OUT4MUTE_SHIFT, 1, 0),
249SOC_SINGLE("OUT4 Attenuation Switch", WM8400_OUT3_4_VOLUME,
250 WM8400_OUT4ATTN_SHIFT, 1, 0),
251
252SOC_SINGLE("Speaker Mode Switch", WM8400_CLASSD1,
253 WM8400_CDMODE_SHIFT, 1, 0),
254
255SOC_SINGLE("Speaker Output Attenuation Volume", WM8400_SPEAKER_VOLUME,
256 WM8400_SPKATTN_SHIFT, WM8400_SPKATTN_MASK, 0),
257SOC_SINGLE("Speaker DC Boost Volume", WM8400_CLASSD3,
258 WM8400_DCGAIN_SHIFT, 6, 0),
259SOC_SINGLE("Speaker AC Boost Volume", WM8400_CLASSD3,
260 WM8400_ACGAIN_SHIFT, 6, 0),
261
262WM8400_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume",
263 WM8400_LEFT_DAC_DIGITAL_VOLUME, WM8400_DACL_VOL_SHIFT,
264 127, 0, out_dac_tlv),
265
266WM8400_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume",
267 WM8400_RIGHT_DAC_DIGITAL_VOLUME, WM8400_DACR_VOL_SHIFT,
268 127, 0, out_dac_tlv),
269
270SOC_ENUM("Left Digital Sidetone", wm8400_left_digital_sidetone_enum),
271SOC_ENUM("Right Digital Sidetone", wm8400_right_digital_sidetone_enum),
272
273SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8400_DIGITAL_SIDE_TONE,
274 WM8400_ADCL_DAC_SVOL_SHIFT, 15, 0, out_sidetone_tlv),
275SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8400_DIGITAL_SIDE_TONE,
276 WM8400_ADCR_DAC_SVOL_SHIFT, 15, 0, out_sidetone_tlv),
277
278SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8400_ADC_CTRL,
279 WM8400_ADC_HPF_ENA_SHIFT, 1, 0),
280
281SOC_ENUM("ADC HPF Mode", wm8400_right_adcmode_enum),
282
283WM8400_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume",
284 WM8400_LEFT_ADC_DIGITAL_VOLUME,
285 WM8400_ADCL_VOL_SHIFT,
286 WM8400_ADCL_VOL_MASK,
287 0,
288 in_adc_tlv),
289
290WM8400_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume",
291 WM8400_RIGHT_ADC_DIGITAL_VOLUME,
292 WM8400_ADCR_VOL_SHIFT,
293 WM8400_ADCR_VOL_MASK,
294 0,
295 in_adc_tlv),
296
297WM8400_OUTPGA_SINGLE_R_TLV("LIN12 Volume",
298 WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
299 WM8400_LIN12VOL_SHIFT,
300 WM8400_LIN12VOL_MASK,
301 0,
302 in_pga_tlv),
303
304SOC_SINGLE("LIN12 ZC Switch", WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
305 WM8400_LI12ZC_SHIFT, 1, 0),
306
307SOC_SINGLE("LIN12 Mute Switch", WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
308 WM8400_LI12MUTE_SHIFT, 1, 0),
309
310WM8400_OUTPGA_SINGLE_R_TLV("LIN34 Volume",
311 WM8400_LEFT_LINE_INPUT_3_4_VOLUME,
312 WM8400_LIN34VOL_SHIFT,
313 WM8400_LIN34VOL_MASK,
314 0,
315 in_pga_tlv),
316
317SOC_SINGLE("LIN34 ZC Switch", WM8400_LEFT_LINE_INPUT_3_4_VOLUME,
318 WM8400_LI34ZC_SHIFT, 1, 0),
319
320SOC_SINGLE("LIN34 Mute Switch", WM8400_LEFT_LINE_INPUT_3_4_VOLUME,
321 WM8400_LI34MUTE_SHIFT, 1, 0),
322
323WM8400_OUTPGA_SINGLE_R_TLV("RIN12 Volume",
324 WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
325 WM8400_RIN12VOL_SHIFT,
326 WM8400_RIN12VOL_MASK,
327 0,
328 in_pga_tlv),
329
330SOC_SINGLE("RIN12 ZC Switch", WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
331 WM8400_RI12ZC_SHIFT, 1, 0),
332
333SOC_SINGLE("RIN12 Mute Switch", WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
334 WM8400_RI12MUTE_SHIFT, 1, 0),
335
336WM8400_OUTPGA_SINGLE_R_TLV("RIN34 Volume",
337 WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
338 WM8400_RIN34VOL_SHIFT,
339 WM8400_RIN34VOL_MASK,
340 0,
341 in_pga_tlv),
342
343SOC_SINGLE("RIN34 ZC Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
344 WM8400_RI34ZC_SHIFT, 1, 0),
345
346SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
347 WM8400_RI34MUTE_SHIFT, 1, 0),
348
349};
350
351/* add non dapm controls */
352static int wm8400_add_controls(struct snd_soc_codec *codec)
353{
354 int err, i;
355
356 for (i = 0; i < ARRAY_SIZE(wm8400_snd_controls); i++) {
357 err = snd_ctl_add(codec->card,
358 snd_soc_cnew(&wm8400_snd_controls[i],codec,
359 NULL));
360 if (err < 0)
361 return err;
362 }
363 return 0;
364}
365
366/*
367 * _DAPM_ Controls
368 */
369
370static int inmixer_event (struct snd_soc_dapm_widget *w,
371 struct snd_kcontrol *kcontrol, int event)
372{
373 u16 reg, fakepower;
374
375 reg = wm8400_read(w->codec, WM8400_POWER_MANAGEMENT_2);
376 fakepower = wm8400_read(w->codec, WM8400_INTDRIVBITS);
377
378 if (fakepower & ((1 << WM8400_INMIXL_PWR) |
379 (1 << WM8400_AINLMUX_PWR))) {
380 reg |= WM8400_AINL_ENA;
381 } else {
382 reg &= ~WM8400_AINL_ENA;
383 }
384
385 if (fakepower & ((1 << WM8400_INMIXR_PWR) |
386 (1 << WM8400_AINRMUX_PWR))) {
387 reg |= WM8400_AINR_ENA;
388 } else {
389 reg &= ~WM8400_AINL_ENA;
390 }
391 wm8400_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg);
392
393 return 0;
394}
395
396static int outmixer_event (struct snd_soc_dapm_widget *w,
397 struct snd_kcontrol * kcontrol, int event)
398{
399 struct soc_mixer_control *mc =
400 (struct soc_mixer_control *)kcontrol->private_value;
401 u32 reg_shift = mc->shift;
402 int ret = 0;
403 u16 reg;
404
405 switch (reg_shift) {
406 case WM8400_SPEAKER_MIXER | (WM8400_LDSPK << 8) :
407 reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER1);
408 if (reg & WM8400_LDLO) {
409 printk(KERN_WARNING
410 "Cannot set as Output Mixer 1 LDLO Set\n");
411 ret = -1;
412 }
413 break;
414 case WM8400_SPEAKER_MIXER | (WM8400_RDSPK << 8):
415 reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER2);
416 if (reg & WM8400_RDRO) {
417 printk(KERN_WARNING
418 "Cannot set as Output Mixer 2 RDRO Set\n");
419 ret = -1;
420 }
421 break;
422 case WM8400_OUTPUT_MIXER1 | (WM8400_LDLO << 8):
423 reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER);
424 if (reg & WM8400_LDSPK) {
425 printk(KERN_WARNING
426 "Cannot set as Speaker Mixer LDSPK Set\n");
427 ret = -1;
428 }
429 break;
430 case WM8400_OUTPUT_MIXER2 | (WM8400_RDRO << 8):
431 reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER);
432 if (reg & WM8400_RDSPK) {
433 printk(KERN_WARNING
434 "Cannot set as Speaker Mixer RDSPK Set\n");
435 ret = -1;
436 }
437 break;
438 }
439
440 return ret;
441}
442
443/* INMIX dB values */
444static const unsigned int in_mix_tlv[] = {
445 TLV_DB_RANGE_HEAD(1),
446 0,7, TLV_DB_LINEAR_ITEM(-1200, 600),
447};
448
449/* Left In PGA Connections */
450static const struct snd_kcontrol_new wm8400_dapm_lin12_pga_controls[] = {
451SOC_DAPM_SINGLE("LIN1 Switch", WM8400_INPUT_MIXER2, WM8400_LMN1_SHIFT, 1, 0),
452SOC_DAPM_SINGLE("LIN2 Switch", WM8400_INPUT_MIXER2, WM8400_LMP2_SHIFT, 1, 0),
453};
454
455static const struct snd_kcontrol_new wm8400_dapm_lin34_pga_controls[] = {
456SOC_DAPM_SINGLE("LIN3 Switch", WM8400_INPUT_MIXER2, WM8400_LMN3_SHIFT, 1, 0),
457SOC_DAPM_SINGLE("LIN4 Switch", WM8400_INPUT_MIXER2, WM8400_LMP4_SHIFT, 1, 0),
458};
459
460/* Right In PGA Connections */
461static const struct snd_kcontrol_new wm8400_dapm_rin12_pga_controls[] = {
462SOC_DAPM_SINGLE("RIN1 Switch", WM8400_INPUT_MIXER2, WM8400_RMN1_SHIFT, 1, 0),
463SOC_DAPM_SINGLE("RIN2 Switch", WM8400_INPUT_MIXER2, WM8400_RMP2_SHIFT, 1, 0),
464};
465
466static const struct snd_kcontrol_new wm8400_dapm_rin34_pga_controls[] = {
467SOC_DAPM_SINGLE("RIN3 Switch", WM8400_INPUT_MIXER2, WM8400_RMN3_SHIFT, 1, 0),
468SOC_DAPM_SINGLE("RIN4 Switch", WM8400_INPUT_MIXER2, WM8400_RMP4_SHIFT, 1, 0),
469};
470
471/* INMIXL */
472static const struct snd_kcontrol_new wm8400_dapm_inmixl_controls[] = {
473SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8400_INPUT_MIXER3,
474 WM8400_LDBVOL_SHIFT, WM8400_LDBVOL_MASK, 0, in_mix_tlv),
475SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8400_INPUT_MIXER5, WM8400_LI2BVOL_SHIFT,
476 7, 0, in_mix_tlv),
477SOC_DAPM_SINGLE("LINPGA12 Switch", WM8400_INPUT_MIXER3, WM8400_L12MNB_SHIFT,
478 1, 0),
479SOC_DAPM_SINGLE("LINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT,
480 1, 0),
481};
482
483/* INMIXR */
484static const struct snd_kcontrol_new wm8400_dapm_inmixr_controls[] = {
485SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8400_INPUT_MIXER4,
486 WM8400_RDBVOL_SHIFT, WM8400_RDBVOL_MASK, 0, in_mix_tlv),
487SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8400_INPUT_MIXER6, WM8400_RI2BVOL_SHIFT,
488 7, 0, in_mix_tlv),
489SOC_DAPM_SINGLE("RINPGA12 Switch", WM8400_INPUT_MIXER3, WM8400_L12MNB_SHIFT,
490 1, 0),
491SOC_DAPM_SINGLE("RINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT,
492 1, 0),
493};
494
495/* AINLMUX */
496static const char *wm8400_ainlmux[] =
497 {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};
498
499static const struct soc_enum wm8400_ainlmux_enum =
500SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINLMODE_SHIFT,
501 ARRAY_SIZE(wm8400_ainlmux), wm8400_ainlmux);
502
503static const struct snd_kcontrol_new wm8400_dapm_ainlmux_controls =
504SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum);
505
506/* DIFFINL */
507
508/* AINRMUX */
509static const char *wm8400_ainrmux[] =
510 {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};
511
512static const struct soc_enum wm8400_ainrmux_enum =
513SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINRMODE_SHIFT,
514 ARRAY_SIZE(wm8400_ainrmux), wm8400_ainrmux);
515
516static const struct snd_kcontrol_new wm8400_dapm_ainrmux_controls =
517SOC_DAPM_ENUM("Route", wm8400_ainrmux_enum);
518
519/* RXVOICE */
520static const struct snd_kcontrol_new wm8400_dapm_rxvoice_controls[] = {
521SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8400_INPUT_MIXER5, WM8400_LR4BVOL_SHIFT,
522 WM8400_LR4BVOL_MASK, 0, in_mix_tlv),
523SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8400_INPUT_MIXER6, WM8400_RL4BVOL_SHIFT,
524 WM8400_RL4BVOL_MASK, 0, in_mix_tlv),
525};
526
527/* LOMIX */
528static const struct snd_kcontrol_new wm8400_dapm_lomix_controls[] = {
529SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8400_OUTPUT_MIXER1,
530 WM8400_LRBLO_SHIFT, 1, 0),
531SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8400_OUTPUT_MIXER1,
532 WM8400_LLBLO_SHIFT, 1, 0),
533SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8400_OUTPUT_MIXER1,
534 WM8400_LRI3LO_SHIFT, 1, 0),
535SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8400_OUTPUT_MIXER1,
536 WM8400_LLI3LO_SHIFT, 1, 0),
537SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER1,
538 WM8400_LR12LO_SHIFT, 1, 0),
539SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER1,
540 WM8400_LL12LO_SHIFT, 1, 0),
541SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8400_OUTPUT_MIXER1,
542 WM8400_LDLO_SHIFT, 1, 0),
543};
544
545/* ROMIX */
546static const struct snd_kcontrol_new wm8400_dapm_romix_controls[] = {
547SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8400_OUTPUT_MIXER2,
548 WM8400_RLBRO_SHIFT, 1, 0),
549SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8400_OUTPUT_MIXER2,
550 WM8400_RRBRO_SHIFT, 1, 0),
551SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8400_OUTPUT_MIXER2,
552 WM8400_RLI3RO_SHIFT, 1, 0),
553SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8400_OUTPUT_MIXER2,
554 WM8400_RRI3RO_SHIFT, 1, 0),
555SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER2,
556 WM8400_RL12RO_SHIFT, 1, 0),
557SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER2,
558 WM8400_RR12RO_SHIFT, 1, 0),
559SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8400_OUTPUT_MIXER2,
560 WM8400_RDRO_SHIFT, 1, 0),
561};
562
563/* LONMIX */
564static const struct snd_kcontrol_new wm8400_dapm_lonmix_controls[] = {
565SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8400_LINE_MIXER1,
566 WM8400_LLOPGALON_SHIFT, 1, 0),
567SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8400_LINE_MIXER1,
568 WM8400_LROPGALON_SHIFT, 1, 0),
569SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8400_LINE_MIXER1,
570 WM8400_LOPLON_SHIFT, 1, 0),
571};
572
573/* LOPMIX */
574static const struct snd_kcontrol_new wm8400_dapm_lopmix_controls[] = {
575SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8400_LINE_MIXER1,
576 WM8400_LR12LOP_SHIFT, 1, 0),
577SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8400_LINE_MIXER1,
578 WM8400_LL12LOP_SHIFT, 1, 0),
579SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8400_LINE_MIXER1,
580 WM8400_LLOPGALOP_SHIFT, 1, 0),
581};
582
583/* RONMIX */
584static const struct snd_kcontrol_new wm8400_dapm_ronmix_controls[] = {
585SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8400_LINE_MIXER2,
586 WM8400_RROPGARON_SHIFT, 1, 0),
587SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8400_LINE_MIXER2,
588 WM8400_RLOPGARON_SHIFT, 1, 0),
589SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8400_LINE_MIXER2,
590 WM8400_ROPRON_SHIFT, 1, 0),
591};
592
593/* ROPMIX */
594static const struct snd_kcontrol_new wm8400_dapm_ropmix_controls[] = {
595SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8400_LINE_MIXER2,
596 WM8400_RL12ROP_SHIFT, 1, 0),
597SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8400_LINE_MIXER2,
598 WM8400_RR12ROP_SHIFT, 1, 0),
599SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8400_LINE_MIXER2,
600 WM8400_RROPGAROP_SHIFT, 1, 0),
601};
602
603/* OUT3MIX */
604static const struct snd_kcontrol_new wm8400_dapm_out3mix_controls[] = {
605SOC_DAPM_SINGLE("OUT3MIX LIN4/RXP Bypass Switch", WM8400_OUT3_4_MIXER,
606 WM8400_LI4O3_SHIFT, 1, 0),
607SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8400_OUT3_4_MIXER,
608 WM8400_LPGAO3_SHIFT, 1, 0),
609};
610
611/* OUT4MIX */
612static const struct snd_kcontrol_new wm8400_dapm_out4mix_controls[] = {
613SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8400_OUT3_4_MIXER,
614 WM8400_RPGAO4_SHIFT, 1, 0),
615SOC_DAPM_SINGLE("OUT4MIX RIN4/RXP Bypass Switch", WM8400_OUT3_4_MIXER,
616 WM8400_RI4O4_SHIFT, 1, 0),
617};
618
619/* SPKMIX */
620static const struct snd_kcontrol_new wm8400_dapm_spkmix_controls[] = {
621SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8400_SPEAKER_MIXER,
622 WM8400_LI2SPK_SHIFT, 1, 0),
623SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8400_SPEAKER_MIXER,
624 WM8400_LB2SPK_SHIFT, 1, 0),
625SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8400_SPEAKER_MIXER,
626 WM8400_LOPGASPK_SHIFT, 1, 0),
627SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8400_SPEAKER_MIXER,
628 WM8400_LDSPK_SHIFT, 1, 0),
629SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8400_SPEAKER_MIXER,
630 WM8400_RDSPK_SHIFT, 1, 0),
631SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8400_SPEAKER_MIXER,
632 WM8400_ROPGASPK_SHIFT, 1, 0),
633SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8400_SPEAKER_MIXER,
634 WM8400_RL12ROP_SHIFT, 1, 0),
635SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8400_SPEAKER_MIXER,
636 WM8400_RI2SPK_SHIFT, 1, 0),
637};
638
639static const struct snd_soc_dapm_widget wm8400_dapm_widgets[] = {
640/* Input Side */
641/* Input Lines */
642SND_SOC_DAPM_INPUT("LIN1"),
643SND_SOC_DAPM_INPUT("LIN2"),
644SND_SOC_DAPM_INPUT("LIN3"),
645SND_SOC_DAPM_INPUT("LIN4/RXN"),
646SND_SOC_DAPM_INPUT("RIN3"),
647SND_SOC_DAPM_INPUT("RIN4/RXP"),
648SND_SOC_DAPM_INPUT("RIN1"),
649SND_SOC_DAPM_INPUT("RIN2"),
650SND_SOC_DAPM_INPUT("Internal ADC Source"),
651
652/* DACs */
653SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8400_POWER_MANAGEMENT_2,
654 WM8400_ADCL_ENA_SHIFT, 0),
655SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8400_POWER_MANAGEMENT_2,
656 WM8400_ADCR_ENA_SHIFT, 0),
657
658/* Input PGAs */
659SND_SOC_DAPM_MIXER("LIN12 PGA", WM8400_POWER_MANAGEMENT_2,
660 WM8400_LIN12_ENA_SHIFT,
661 0, &wm8400_dapm_lin12_pga_controls[0],
662 ARRAY_SIZE(wm8400_dapm_lin12_pga_controls)),
663SND_SOC_DAPM_MIXER("LIN34 PGA", WM8400_POWER_MANAGEMENT_2,
664 WM8400_LIN34_ENA_SHIFT,
665 0, &wm8400_dapm_lin34_pga_controls[0],
666 ARRAY_SIZE(wm8400_dapm_lin34_pga_controls)),
667SND_SOC_DAPM_MIXER("RIN12 PGA", WM8400_POWER_MANAGEMENT_2,
668 WM8400_RIN12_ENA_SHIFT,
669 0, &wm8400_dapm_rin12_pga_controls[0],
670 ARRAY_SIZE(wm8400_dapm_rin12_pga_controls)),
671SND_SOC_DAPM_MIXER("RIN34 PGA", WM8400_POWER_MANAGEMENT_2,
672 WM8400_RIN34_ENA_SHIFT,
673 0, &wm8400_dapm_rin34_pga_controls[0],
674 ARRAY_SIZE(wm8400_dapm_rin34_pga_controls)),
675
676/* INMIXL */
677SND_SOC_DAPM_MIXER_E("INMIXL", WM8400_INTDRIVBITS, WM8400_INMIXL_PWR, 0,
678 &wm8400_dapm_inmixl_controls[0],
679 ARRAY_SIZE(wm8400_dapm_inmixl_controls),
680 inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
681
682/* AINLMUX */
683SND_SOC_DAPM_MUX_E("AILNMUX", WM8400_INTDRIVBITS, WM8400_AINLMUX_PWR, 0,
684 &wm8400_dapm_ainlmux_controls, inmixer_event,
685 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
686
687/* INMIXR */
688SND_SOC_DAPM_MIXER_E("INMIXR", WM8400_INTDRIVBITS, WM8400_INMIXR_PWR, 0,
689 &wm8400_dapm_inmixr_controls[0],
690 ARRAY_SIZE(wm8400_dapm_inmixr_controls),
691 inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
692
693/* AINRMUX */
694SND_SOC_DAPM_MUX_E("AIRNMUX", WM8400_INTDRIVBITS, WM8400_AINRMUX_PWR, 0,
695 &wm8400_dapm_ainrmux_controls, inmixer_event,
696 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
697
698/* Output Side */
699/* DACs */
700SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8400_POWER_MANAGEMENT_3,
701 WM8400_DACL_ENA_SHIFT, 0),
702SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8400_POWER_MANAGEMENT_3,
703 WM8400_DACR_ENA_SHIFT, 0),
704
705/* LOMIX */
706SND_SOC_DAPM_MIXER_E("LOMIX", WM8400_POWER_MANAGEMENT_3,
707 WM8400_LOMIX_ENA_SHIFT,
708 0, &wm8400_dapm_lomix_controls[0],
709 ARRAY_SIZE(wm8400_dapm_lomix_controls),
710 outmixer_event, SND_SOC_DAPM_PRE_REG),
711
712/* LONMIX */
713SND_SOC_DAPM_MIXER("LONMIX", WM8400_POWER_MANAGEMENT_3, WM8400_LON_ENA_SHIFT,
714 0, &wm8400_dapm_lonmix_controls[0],
715 ARRAY_SIZE(wm8400_dapm_lonmix_controls)),
716
717/* LOPMIX */
718SND_SOC_DAPM_MIXER("LOPMIX", WM8400_POWER_MANAGEMENT_3, WM8400_LOP_ENA_SHIFT,
719 0, &wm8400_dapm_lopmix_controls[0],
720 ARRAY_SIZE(wm8400_dapm_lopmix_controls)),
721
722/* OUT3MIX */
723SND_SOC_DAPM_MIXER("OUT3MIX", WM8400_POWER_MANAGEMENT_1, WM8400_OUT3_ENA_SHIFT,
724 0, &wm8400_dapm_out3mix_controls[0],
725 ARRAY_SIZE(wm8400_dapm_out3mix_controls)),
726
727/* SPKMIX */
728SND_SOC_DAPM_MIXER_E("SPKMIX", WM8400_POWER_MANAGEMENT_1, WM8400_SPK_ENA_SHIFT,
729 0, &wm8400_dapm_spkmix_controls[0],
730 ARRAY_SIZE(wm8400_dapm_spkmix_controls), outmixer_event,
731 SND_SOC_DAPM_PRE_REG),
732
733/* OUT4MIX */
734SND_SOC_DAPM_MIXER("OUT4MIX", WM8400_POWER_MANAGEMENT_1, WM8400_OUT4_ENA_SHIFT,
735 0, &wm8400_dapm_out4mix_controls[0],
736 ARRAY_SIZE(wm8400_dapm_out4mix_controls)),
737
738/* ROPMIX */
739SND_SOC_DAPM_MIXER("ROPMIX", WM8400_POWER_MANAGEMENT_3, WM8400_ROP_ENA_SHIFT,
740 0, &wm8400_dapm_ropmix_controls[0],
741 ARRAY_SIZE(wm8400_dapm_ropmix_controls)),
742
743/* RONMIX */
744SND_SOC_DAPM_MIXER("RONMIX", WM8400_POWER_MANAGEMENT_3, WM8400_RON_ENA_SHIFT,
745 0, &wm8400_dapm_ronmix_controls[0],
746 ARRAY_SIZE(wm8400_dapm_ronmix_controls)),
747
748/* ROMIX */
749SND_SOC_DAPM_MIXER_E("ROMIX", WM8400_POWER_MANAGEMENT_3,
750 WM8400_ROMIX_ENA_SHIFT,
751 0, &wm8400_dapm_romix_controls[0],
752 ARRAY_SIZE(wm8400_dapm_romix_controls),
753 outmixer_event, SND_SOC_DAPM_PRE_REG),
754
755/* LOUT PGA */
756SND_SOC_DAPM_PGA("LOUT PGA", WM8400_POWER_MANAGEMENT_1, WM8400_LOUT_ENA_SHIFT,
757 0, NULL, 0),
758
759/* ROUT PGA */
760SND_SOC_DAPM_PGA("ROUT PGA", WM8400_POWER_MANAGEMENT_1, WM8400_ROUT_ENA_SHIFT,
761 0, NULL, 0),
762
763/* LOPGA */
764SND_SOC_DAPM_PGA("LOPGA", WM8400_POWER_MANAGEMENT_3, WM8400_LOPGA_ENA_SHIFT, 0,
765 NULL, 0),
766
767/* ROPGA */
768SND_SOC_DAPM_PGA("ROPGA", WM8400_POWER_MANAGEMENT_3, WM8400_ROPGA_ENA_SHIFT, 0,
769 NULL, 0),
770
771/* MICBIAS */
772SND_SOC_DAPM_MICBIAS("MICBIAS", WM8400_POWER_MANAGEMENT_1,
773 WM8400_MIC1BIAS_ENA_SHIFT, 0),
774
775SND_SOC_DAPM_OUTPUT("LON"),
776SND_SOC_DAPM_OUTPUT("LOP"),
777SND_SOC_DAPM_OUTPUT("OUT3"),
778SND_SOC_DAPM_OUTPUT("LOUT"),
779SND_SOC_DAPM_OUTPUT("SPKN"),
780SND_SOC_DAPM_OUTPUT("SPKP"),
781SND_SOC_DAPM_OUTPUT("ROUT"),
782SND_SOC_DAPM_OUTPUT("OUT4"),
783SND_SOC_DAPM_OUTPUT("ROP"),
784SND_SOC_DAPM_OUTPUT("RON"),
785
786SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
787};
788
789static const struct snd_soc_dapm_route audio_map[] = {
790 /* Make DACs turn on when playing even if not mixed into any outputs */
791 {"Internal DAC Sink", NULL, "Left DAC"},
792 {"Internal DAC Sink", NULL, "Right DAC"},
793
794 /* Make ADCs turn on when recording
795 * even if not mixed from any inputs */
796 {"Left ADC", NULL, "Internal ADC Source"},
797 {"Right ADC", NULL, "Internal ADC Source"},
798
799 /* Input Side */
800 /* LIN12 PGA */
801 {"LIN12 PGA", "LIN1 Switch", "LIN1"},
802 {"LIN12 PGA", "LIN2 Switch", "LIN2"},
803 /* LIN34 PGA */
804 {"LIN34 PGA", "LIN3 Switch", "LIN3"},
805 {"LIN34 PGA", "LIN4 Switch", "LIN4/RXN"},
806 /* INMIXL */
807 {"INMIXL", "Record Left Volume", "LOMIX"},
808 {"INMIXL", "LIN2 Volume", "LIN2"},
809 {"INMIXL", "LINPGA12 Switch", "LIN12 PGA"},
810 {"INMIXL", "LINPGA34 Switch", "LIN34 PGA"},
811 /* AILNMUX */
812 {"AILNMUX", "INMIXL Mix", "INMIXL"},
813 {"AILNMUX", "DIFFINL Mix", "LIN12 PGA"},
814 {"AILNMUX", "DIFFINL Mix", "LIN34 PGA"},
815 {"AILNMUX", "RXVOICE Mix", "LIN4/RXN"},
816 {"AILNMUX", "RXVOICE Mix", "RIN4/RXP"},
817 /* ADC */
818 {"Left ADC", NULL, "AILNMUX"},
819
820 /* RIN12 PGA */
821 {"RIN12 PGA", "RIN1 Switch", "RIN1"},
822 {"RIN12 PGA", "RIN2 Switch", "RIN2"},
823 /* RIN34 PGA */
824 {"RIN34 PGA", "RIN3 Switch", "RIN3"},
825 {"RIN34 PGA", "RIN4 Switch", "RIN4/RXP"},
826 /* INMIXL */
827 {"INMIXR", "Record Right Volume", "ROMIX"},
828 {"INMIXR", "RIN2 Volume", "RIN2"},
829 {"INMIXR", "RINPGA12 Switch", "RIN12 PGA"},
830 {"INMIXR", "RINPGA34 Switch", "RIN34 PGA"},
831 /* AIRNMUX */
832 {"AIRNMUX", "INMIXR Mix", "INMIXR"},
833 {"AIRNMUX", "DIFFINR Mix", "RIN12 PGA"},
834 {"AIRNMUX", "DIFFINR Mix", "RIN34 PGA"},
835 {"AIRNMUX", "RXVOICE Mix", "LIN4/RXN"},
836 {"AIRNMUX", "RXVOICE Mix", "RIN4/RXP"},
837 /* ADC */
838 {"Right ADC", NULL, "AIRNMUX"},
839
840 /* LOMIX */
841 {"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"},
842 {"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"},
843 {"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
844 {"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
845 {"LOMIX", "LOMIX Right ADC Bypass Switch", "AIRNMUX"},
846 {"LOMIX", "LOMIX Left ADC Bypass Switch", "AILNMUX"},
847 {"LOMIX", "LOMIX Left DAC Switch", "Left DAC"},
848
849 /* ROMIX */
850 {"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"},
851 {"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"},
852 {"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
853 {"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
854 {"ROMIX", "ROMIX Right ADC Bypass Switch", "AIRNMUX"},
855 {"ROMIX", "ROMIX Left ADC Bypass Switch", "AILNMUX"},
856 {"ROMIX", "ROMIX Right DAC Switch", "Right DAC"},
857
858 /* SPKMIX */
859 {"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"},
860 {"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"},
861 {"SPKMIX", "SPKMIX LADC Bypass Switch", "AILNMUX"},
862 {"SPKMIX", "SPKMIX RADC Bypass Switch", "AIRNMUX"},
863 {"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"},
864 {"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"},
865 {"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"},
866 {"SPKMIX", "SPKMIX Left DAC Switch", "Right DAC"},
867
868 /* LONMIX */
869 {"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"},
870 {"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"},
871 {"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"},
872
873 /* LOPMIX */
874 {"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"},
875 {"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"},
876 {"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"},
877
878 /* OUT3MIX */
879 {"OUT3MIX", "OUT3MIX LIN4/RXP Bypass Switch", "LIN4/RXN"},
880 {"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"},
881
882 /* OUT4MIX */
883 {"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"},
884 {"OUT4MIX", "OUT4MIX RIN4/RXP Bypass Switch", "RIN4/RXP"},
885
886 /* RONMIX */
887 {"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"},
888 {"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"},
889 {"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"},
890
891 /* ROPMIX */
892 {"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"},
893 {"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"},
894 {"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"},
895
896 /* Out Mixer PGAs */
897 {"LOPGA", NULL, "LOMIX"},
898 {"ROPGA", NULL, "ROMIX"},
899
900 {"LOUT PGA", NULL, "LOMIX"},
901 {"ROUT PGA", NULL, "ROMIX"},
902
903 /* Output Pins */
904 {"LON", NULL, "LONMIX"},
905 {"LOP", NULL, "LOPMIX"},
906 {"OUT3", NULL, "OUT3MIX"},
907 {"LOUT", NULL, "LOUT PGA"},
908 {"SPKN", NULL, "SPKMIX"},
909 {"ROUT", NULL, "ROUT PGA"},
910 {"OUT4", NULL, "OUT4MIX"},
911 {"ROP", NULL, "ROPMIX"},
912 {"RON", NULL, "RONMIX"},
913};
914
915static int wm8400_add_widgets(struct snd_soc_codec *codec)
916{
917 snd_soc_dapm_new_controls(codec, wm8400_dapm_widgets,
918 ARRAY_SIZE(wm8400_dapm_widgets));
919
920 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
921
922 snd_soc_dapm_new_widgets(codec);
923 return 0;
924}
925
926/*
927 * Clock after FLL and dividers
928 */
929static int wm8400_set_dai_sysclk(struct snd_soc_dai *codec_dai,
930 int clk_id, unsigned int freq, int dir)
931{
932 struct snd_soc_codec *codec = codec_dai->codec;
933 struct wm8400_priv *wm8400 = codec->private_data;
934
935 wm8400->sysclk = freq;
936 return 0;
937}
938
939/*
940 * Sets ADC and Voice DAC format.
941 */
942static int wm8400_set_dai_fmt(struct snd_soc_dai *codec_dai,
943 unsigned int fmt)
944{
945 struct snd_soc_codec *codec = codec_dai->codec;
946 u16 audio1, audio3;
947
948 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
949 audio3 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_3);
950
951 /* set master/slave audio interface */
952 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
953 case SND_SOC_DAIFMT_CBS_CFS:
954 audio3 &= ~WM8400_AIF_MSTR1;
955 break;
956 case SND_SOC_DAIFMT_CBM_CFM:
957 audio3 |= WM8400_AIF_MSTR1;
958 break;
959 default:
960 return -EINVAL;
961 }
962
963 audio1 &= ~WM8400_AIF_FMT_MASK;
964
965 /* interface format */
966 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
967 case SND_SOC_DAIFMT_I2S:
968 audio1 |= WM8400_AIF_FMT_I2S;
969 audio1 &= ~WM8400_AIF_LRCLK_INV;
970 break;
971 case SND_SOC_DAIFMT_RIGHT_J:
972 audio1 |= WM8400_AIF_FMT_RIGHTJ;
973 audio1 &= ~WM8400_AIF_LRCLK_INV;
974 break;
975 case SND_SOC_DAIFMT_LEFT_J:
976 audio1 |= WM8400_AIF_FMT_LEFTJ;
977 audio1 &= ~WM8400_AIF_LRCLK_INV;
978 break;
979 case SND_SOC_DAIFMT_DSP_A:
980 audio1 |= WM8400_AIF_FMT_DSP;
981 audio1 &= ~WM8400_AIF_LRCLK_INV;
982 break;
983 case SND_SOC_DAIFMT_DSP_B:
984 audio1 |= WM8400_AIF_FMT_DSP | WM8400_AIF_LRCLK_INV;
985 break;
986 default:
987 return -EINVAL;
988 }
989
990 wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
991 wm8400_write(codec, WM8400_AUDIO_INTERFACE_3, audio3);
992 return 0;
993}
994
995static int wm8400_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
996 int div_id, int div)
997{
998 struct snd_soc_codec *codec = codec_dai->codec;
999 u16 reg;
1000
1001 switch (div_id) {
1002 case WM8400_MCLK_DIV:
1003 reg = wm8400_read(codec, WM8400_CLOCKING_2) &
1004 ~WM8400_MCLK_DIV_MASK;
1005 wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
1006 break;
1007 case WM8400_DACCLK_DIV:
1008 reg = wm8400_read(codec, WM8400_CLOCKING_2) &
1009 ~WM8400_DAC_CLKDIV_MASK;
1010 wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
1011 break;
1012 case WM8400_ADCCLK_DIV:
1013 reg = wm8400_read(codec, WM8400_CLOCKING_2) &
1014 ~WM8400_ADC_CLKDIV_MASK;
1015 wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
1016 break;
1017 case WM8400_BCLK_DIV:
1018 reg = wm8400_read(codec, WM8400_CLOCKING_1) &
1019 ~WM8400_BCLK_DIV_MASK;
1020 wm8400_write(codec, WM8400_CLOCKING_1, reg | div);
1021 break;
1022 default:
1023 return -EINVAL;
1024 }
1025
1026 return 0;
1027}
1028
1029/*
1030 * Set PCM DAI bit size and sample rate.
1031 */
1032static int wm8400_hw_params(struct snd_pcm_substream *substream,
1033 struct snd_pcm_hw_params *params,
1034 struct snd_soc_dai *dai)
1035{
1036 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1037 struct snd_soc_device *socdev = rtd->socdev;
1038 struct snd_soc_codec *codec = socdev->card->codec;
1039 u16 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
1040
1041 audio1 &= ~WM8400_AIF_WL_MASK;
1042 /* bit size */
1043 switch (params_format(params)) {
1044 case SNDRV_PCM_FORMAT_S16_LE:
1045 break;
1046 case SNDRV_PCM_FORMAT_S20_3LE:
1047 audio1 |= WM8400_AIF_WL_20BITS;
1048 break;
1049 case SNDRV_PCM_FORMAT_S24_LE:
1050 audio1 |= WM8400_AIF_WL_24BITS;
1051 break;
1052 case SNDRV_PCM_FORMAT_S32_LE:
1053 audio1 |= WM8400_AIF_WL_32BITS;
1054 break;
1055 }
1056
1057 wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
1058 return 0;
1059}
1060
1061static int wm8400_mute(struct snd_soc_dai *dai, int mute)
1062{
1063 struct snd_soc_codec *codec = dai->codec;
1064 u16 val = wm8400_read(codec, WM8400_DAC_CTRL) & ~WM8400_DAC_MUTE;
1065
1066 if (mute)
1067 wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
1068 else
1069 wm8400_write(codec, WM8400_DAC_CTRL, val);
1070
1071 return 0;
1072}
1073
1074/* TODO: set bias for best performance at standby */
1075static int wm8400_set_bias_level(struct snd_soc_codec *codec,
1076 enum snd_soc_bias_level level)
1077{
1078 struct wm8400_priv *wm8400 = codec->private_data;
1079 u16 val;
1080 int ret;
1081
1082 switch (level) {
1083 case SND_SOC_BIAS_ON:
1084 break;
1085
1086 case SND_SOC_BIAS_PREPARE:
1087 /* VMID=2*50k */
1088 val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) &
1089 ~WM8400_VMID_MODE_MASK;
1090 wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x2);
1091 break;
1092
1093 case SND_SOC_BIAS_STANDBY:
1094 if (codec->bias_level == SND_SOC_BIAS_OFF) {
1095 ret = regulator_bulk_enable(ARRAY_SIZE(power),
1096 &power[0]);
1097 if (ret != 0) {
1098 dev_err(wm8400->wm8400->dev,
1099 "Failed to enable regulators: %d\n",
1100 ret);
1101 return ret;
1102 }
1103
1104 wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
1105 WM8400_CODEC_ENA | WM8400_SYSCLK_ENA);
1106
1107 /* Enable all output discharge bits */
1108 wm8400_write(codec, WM8400_ANTIPOP1, WM8400_DIS_LLINE |
1109 WM8400_DIS_RLINE | WM8400_DIS_OUT3 |
1110 WM8400_DIS_OUT4 | WM8400_DIS_LOUT |
1111 WM8400_DIS_ROUT);
1112
1113 /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
1114 wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
1115 WM8400_BUFDCOPEN | WM8400_POBCTRL);
1116
1117 msleep(500);
1118
1119 /* Enable outputs */
1120 val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
1121 val |= WM8400_SPK_ENA | WM8400_OUT3_ENA |
1122 WM8400_OUT4_ENA | WM8400_LOUT_ENA |
1123 WM8400_ROUT_ENA;
1124 wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
1125
1126 /* disable all output discharge bits */
1127 wm8400_write(codec, WM8400_ANTIPOP1, 0);
1128
1129 /* Enable VREF & VMID at 2x50k */
1130 val |= 0x2 | WM8400_VREF_ENA;
1131 wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
1132
1133 msleep(600);
1134
1135 /* Enable BUFIOEN */
1136 wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
1137 WM8400_BUFDCOPEN | WM8400_POBCTRL |
1138 WM8400_BUFIOEN);
1139
1140 /* Disable outputs */
1141 val &= ~(WM8400_SPK_ENA | WM8400_OUT3_ENA |
1142 WM8400_OUT4_ENA | WM8400_LOUT_ENA |
1143 WM8400_ROUT_ENA);
1144 wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
1145
1146 /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
1147 wm8400_write(codec, WM8400_ANTIPOP2, WM8400_BUFIOEN);
1148 }
1149
1150 /* VMID=2*300k */
1151 val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) &
1152 ~WM8400_VMID_MODE_MASK;
1153 wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x4);
1154 break;
1155
1156 case SND_SOC_BIAS_OFF:
1157 /* Enable POBCTRL and SOFT_ST */
1158 wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
1159 WM8400_POBCTRL | WM8400_BUFIOEN);
1160
1161 /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
1162 wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
1163 WM8400_BUFDCOPEN | WM8400_POBCTRL |
1164 WM8400_BUFIOEN);
1165
1166 /* mute DAC */
1167 val = wm8400_read(codec, WM8400_DAC_CTRL);
1168 wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
1169
1170 /* Enable any disabled outputs */
1171 val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
1172 val |= WM8400_SPK_ENA | WM8400_OUT3_ENA |
1173 WM8400_OUT4_ENA | WM8400_LOUT_ENA |
1174 WM8400_ROUT_ENA;
1175 wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
1176
1177 /* Disable VMID */
1178 val &= ~WM8400_VMID_MODE_MASK;
1179 wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
1180
1181 msleep(300);
1182
1183 /* Enable all output discharge bits */
1184 wm8400_write(codec, WM8400_ANTIPOP1, WM8400_DIS_LLINE |
1185 WM8400_DIS_RLINE | WM8400_DIS_OUT3 |
1186 WM8400_DIS_OUT4 | WM8400_DIS_LOUT |
1187 WM8400_DIS_ROUT);
1188
1189 /* Disable VREF */
1190 val &= ~WM8400_VREF_ENA;
1191 wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
1192
1193 /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
1194 wm8400_write(codec, WM8400_ANTIPOP2, 0x0);
1195
1196 ret = regulator_bulk_disable(ARRAY_SIZE(power),
1197 &power[0]);
1198 if (ret != 0)
1199 return ret;
1200
1201 break;
1202 }
1203
1204 codec->bias_level = level;
1205 return 0;
1206}
1207
1208#define WM8400_RATES SNDRV_PCM_RATE_8000_96000
1209
1210#define WM8400_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
1211 SNDRV_PCM_FMTBIT_S24_LE)
1212
1213static struct snd_soc_dai_ops wm8400_dai_ops = {
1214 .hw_params = wm8400_hw_params,
1215 .digital_mute = wm8400_mute,
1216 .set_fmt = wm8400_set_dai_fmt,
1217 .set_clkdiv = wm8400_set_dai_clkdiv,
1218 .set_sysclk = wm8400_set_dai_sysclk,
1219};
1220
1221/*
1222 * The WM8400 supports 2 different and mutually exclusive DAI
1223 * configurations.
1224 *
1225 * 1. ADC/DAC on Primary Interface
1226 * 2. ADC on Primary Interface/DAC on secondary
1227 */
1228struct snd_soc_dai wm8400_dai = {
1229/* ADC/DAC on primary */
1230 .name = "WM8400 ADC/DAC Primary",
1231 .id = 1,
1232 .playback = {
1233 .stream_name = "Playback",
1234 .channels_min = 1,
1235 .channels_max = 2,
1236 .rates = WM8400_RATES,
1237 .formats = WM8400_FORMATS,
1238 },
1239 .capture = {
1240 .stream_name = "Capture",
1241 .channels_min = 1,
1242 .channels_max = 2,
1243 .rates = WM8400_RATES,
1244 .formats = WM8400_FORMATS,
1245 },
1246 .ops = &wm8400_dai_ops,
1247};
1248EXPORT_SYMBOL_GPL(wm8400_dai);
1249
1250static int wm8400_suspend(struct platform_device *pdev, pm_message_t state)
1251{
1252 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1253 struct snd_soc_codec *codec = socdev->card->codec;
1254
1255 wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
1256
1257 return 0;
1258}
1259
1260static int wm8400_resume(struct platform_device *pdev)
1261{
1262 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1263 struct snd_soc_codec *codec = socdev->card->codec;
1264
1265 wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1266
1267 return 0;
1268}
1269
1270static struct snd_soc_codec *wm8400_codec;
1271
1272static int wm8400_probe(struct platform_device *pdev)
1273{
1274 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1275 struct snd_soc_codec *codec;
1276 int ret;
1277
1278 if (!wm8400_codec) {
1279 dev_err(&pdev->dev, "wm8400 not yet discovered\n");
1280 return -ENODEV;
1281 }
1282 codec = wm8400_codec;
1283
1284 socdev->card->codec = codec;
1285
1286 /* register pcms */
1287 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
1288 if (ret < 0) {
1289 dev_err(&pdev->dev, "failed to create pcms\n");
1290 goto pcm_err;
1291 }
1292
1293 wm8400_add_controls(codec);
1294 wm8400_add_widgets(codec);
1295
1296 ret = snd_soc_init_card(socdev);
1297 if (ret < 0) {
1298 dev_err(&pdev->dev, "failed to register card\n");
1299 goto card_err;
1300 }
1301
1302 return ret;
1303
1304card_err:
1305 snd_soc_free_pcms(socdev);
1306 snd_soc_dapm_free(socdev);
1307pcm_err:
1308 return ret;
1309}
1310
1311/* power down chip */
1312static int wm8400_remove(struct platform_device *pdev)
1313{
1314 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1315
1316 snd_soc_free_pcms(socdev);
1317 snd_soc_dapm_free(socdev);
1318
1319 return 0;
1320}
1321
1322struct snd_soc_codec_device soc_codec_dev_wm8400 = {
1323 .probe = wm8400_probe,
1324 .remove = wm8400_remove,
1325 .suspend = wm8400_suspend,
1326 .resume = wm8400_resume,
1327};
1328
1329static void wm8400_probe_deferred(struct work_struct *work)
1330{
1331 struct wm8400_priv *priv = container_of(work, struct wm8400_priv,
1332 work);
1333 struct snd_soc_codec *codec = &priv->codec;
1334 int ret;
1335
1336 /* charge output caps */
1337 wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1338
1339 /* We're done, tell the subsystem. */
1340 ret = snd_soc_register_codec(codec);
1341 if (ret != 0) {
1342 dev_err(priv->wm8400->dev,
1343 "Failed to register codec: %d\n", ret);
1344 goto err;
1345 }
1346
1347 ret = snd_soc_register_dai(&wm8400_dai);
1348 if (ret != 0) {
1349 dev_err(priv->wm8400->dev,
1350 "Failed to register DAI: %d\n", ret);
1351 goto err_codec;
1352 }
1353
1354 return;
1355
1356err_codec:
1357 snd_soc_unregister_codec(codec);
1358err:
1359 wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
1360}
1361
1362static int wm8400_codec_probe(struct platform_device *dev)
1363{
1364 struct wm8400_priv *priv;
1365 int ret;
1366 u16 reg;
1367 struct snd_soc_codec *codec;
1368
1369 priv = kzalloc(sizeof(struct wm8400_priv), GFP_KERNEL);
1370 if (priv == NULL)
1371 return -ENOMEM;
1372
1373 codec = &priv->codec;
1374 codec->private_data = priv;
1375 codec->control_data = dev->dev.driver_data;
1376 priv->wm8400 = dev->dev.driver_data;
1377
1378 ret = regulator_bulk_get(priv->wm8400->dev,
1379 ARRAY_SIZE(power), &power[0]);
1380 if (ret != 0) {
1381 dev_err(&dev->dev, "Failed to get regulators: %d\n", ret);
1382 goto err;
1383 }
1384
1385 codec->dev = &dev->dev;
1386 wm8400_dai.dev = &dev->dev;
1387
1388 codec->name = "WM8400";
1389 codec->owner = THIS_MODULE;
1390 codec->read = wm8400_read;
1391 codec->write = wm8400_write;
1392 codec->bias_level = SND_SOC_BIAS_OFF;
1393 codec->set_bias_level = wm8400_set_bias_level;
1394 codec->dai = &wm8400_dai;
1395 codec->num_dai = 1;
1396 codec->reg_cache_size = WM8400_REGISTER_COUNT;
1397 mutex_init(&codec->mutex);
1398 INIT_LIST_HEAD(&codec->dapm_widgets);
1399 INIT_LIST_HEAD(&codec->dapm_paths);
1400 INIT_WORK(&priv->work, wm8400_probe_deferred);
1401
1402 wm8400_codec_reset(codec);
1403
1404 reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
1405 wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, reg | WM8400_CODEC_ENA);
1406
1407 /* Latch volume update bits */
1408 reg = wm8400_read(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME);
1409 wm8400_write(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
1410 reg & WM8400_IPVU);
1411 reg = wm8400_read(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME);
1412 wm8400_write(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
1413 reg & WM8400_IPVU);
1414
1415 wm8400_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
1416 wm8400_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
1417
1418 wm8400_codec = codec;
1419
1420 if (!schedule_work(&priv->work)) {
1421 ret = -EINVAL;
1422 goto err_regulator;
1423 }
1424
1425 return 0;
1426
1427err_regulator:
1428 wm8400_codec = NULL;
1429 regulator_bulk_free(ARRAY_SIZE(power), power);
1430err:
1431 kfree(priv);
1432 return ret;
1433}
1434
1435static int __exit wm8400_codec_remove(struct platform_device *dev)
1436{
1437 struct wm8400_priv *priv = wm8400_codec->private_data;
1438 u16 reg;
1439
1440 snd_soc_unregister_dai(&wm8400_dai);
1441 snd_soc_unregister_codec(wm8400_codec);
1442
1443 reg = wm8400_read(wm8400_codec, WM8400_POWER_MANAGEMENT_1);
1444 wm8400_write(wm8400_codec, WM8400_POWER_MANAGEMENT_1,
1445 reg & (~WM8400_CODEC_ENA));
1446
1447 regulator_bulk_free(ARRAY_SIZE(power), power);
1448 kfree(priv);
1449
1450 wm8400_codec = NULL;
1451
1452 return 0;
1453}
1454
1455static struct platform_driver wm8400_codec_driver = {
1456 .driver = {
1457 .name = "wm8400-codec",
1458 .owner = THIS_MODULE,
1459 },
1460 .probe = wm8400_codec_probe,
1461 .remove = __exit_p(wm8400_codec_remove),
1462};
1463
1464static int __init wm8400_codec_init(void)
1465{
1466 return platform_driver_register(&wm8400_codec_driver);
1467}
1468module_init(wm8400_codec_init);
1469
1470static void __exit wm8400_codec_exit(void)
1471{
1472 platform_driver_unregister(&wm8400_codec_driver);
1473}
1474module_exit(wm8400_codec_exit);
1475
1476EXPORT_SYMBOL_GPL(soc_codec_dev_wm8400);
1477
1478MODULE_DESCRIPTION("ASoC WM8400 driver");
1479MODULE_AUTHOR("Mark Brown");
1480MODULE_LICENSE("GPL");
1481MODULE_ALIAS("platform:wm8400-codec");
diff --git a/sound/soc/codecs/wm8400.h b/sound/soc/codecs/wm8400.h
new file mode 100644
index 000000000000..79c5934d4776
--- /dev/null
+++ b/sound/soc/codecs/wm8400.h
@@ -0,0 +1,62 @@
1/*
2 * wm8400.h -- audio driver for WM8400
3 *
4 * Copyright 2008 Wolfson Microelectronics PLC.
5 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13
14#ifndef _WM8400_CODEC_H
15#define _WM8400_CODEC_H
16
17#define WM8400_MCLK_DIV 0
18#define WM8400_DACCLK_DIV 1
19#define WM8400_ADCCLK_DIV 2
20#define WM8400_BCLK_DIV 3
21
22#define WM8400_MCLK_DIV_1 0x400
23#define WM8400_MCLK_DIV_2 0x800
24
25#define WM8400_DAC_CLKDIV_1 0x00
26#define WM8400_DAC_CLKDIV_1_5 0x04
27#define WM8400_DAC_CLKDIV_2 0x08
28#define WM8400_DAC_CLKDIV_3 0x0c
29#define WM8400_DAC_CLKDIV_4 0x10
30#define WM8400_DAC_CLKDIV_5_5 0x14
31#define WM8400_DAC_CLKDIV_6 0x18
32
33#define WM8400_ADC_CLKDIV_1 0x00
34#define WM8400_ADC_CLKDIV_1_5 0x20
35#define WM8400_ADC_CLKDIV_2 0x40
36#define WM8400_ADC_CLKDIV_3 0x60
37#define WM8400_ADC_CLKDIV_4 0x80
38#define WM8400_ADC_CLKDIV_5_5 0xa0
39#define WM8400_ADC_CLKDIV_6 0xc0
40
41
42#define WM8400_BCLK_DIV_1 (0x0 << 1)
43#define WM8400_BCLK_DIV_1_5 (0x1 << 1)
44#define WM8400_BCLK_DIV_2 (0x2 << 1)
45#define WM8400_BCLK_DIV_3 (0x3 << 1)
46#define WM8400_BCLK_DIV_4 (0x4 << 1)
47#define WM8400_BCLK_DIV_5_5 (0x5 << 1)
48#define WM8400_BCLK_DIV_6 (0x6 << 1)
49#define WM8400_BCLK_DIV_8 (0x7 << 1)
50#define WM8400_BCLK_DIV_11 (0x8 << 1)
51#define WM8400_BCLK_DIV_12 (0x9 << 1)
52#define WM8400_BCLK_DIV_16 (0xA << 1)
53#define WM8400_BCLK_DIV_22 (0xB << 1)
54#define WM8400_BCLK_DIV_24 (0xC << 1)
55#define WM8400_BCLK_DIV_32 (0xD << 1)
56#define WM8400_BCLK_DIV_44 (0xE << 1)
57#define WM8400_BCLK_DIV_48 (0xF << 1)
58
59extern struct snd_soc_dai wm8400_dai;
60extern struct snd_soc_codec_device soc_codec_dev_wm8400;
61
62#endif
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index cc975a62fa5c..6a4cea09c45d 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -336,7 +336,7 @@ static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai,
336 return 0; 336 return 0;
337 } 337 }
338 338
339 pll_factors(freq_out*8, freq_in); 339 pll_factors(freq_out*4, freq_in);
340 340
341 wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n); 341 wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n);
342 wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18); 342 wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18);
@@ -367,7 +367,7 @@ static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
367 wm8510_write(codec, WM8510_GPIO, reg | div); 367 wm8510_write(codec, WM8510_GPIO, reg | div);
368 break; 368 break;
369 case WM8510_MCLKDIV: 369 case WM8510_MCLKDIV:
370 reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1f; 370 reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x11f;
371 wm8510_write(codec, WM8510_CLOCK, reg | div); 371 wm8510_write(codec, WM8510_CLOCK, reg | div);
372 break; 372 break;
373 case WM8510_ADCCLK: 373 case WM8510_ADCCLK:
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index ee0af23a1acc..27f9e231bf69 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -35,8 +35,6 @@
35 35
36#include "wm8580.h" 36#include "wm8580.h"
37 37
38#define WM8580_VERSION "0.1"
39
40struct pll_state { 38struct pll_state {
41 unsigned int in; 39 unsigned int in;
42 unsigned int out; 40 unsigned int out;
@@ -976,8 +974,6 @@ static int wm8580_probe(struct platform_device *pdev)
976 struct wm8580_priv *wm8580; 974 struct wm8580_priv *wm8580;
977 int ret = 0; 975 int ret = 0;
978 976
979 pr_info("WM8580 Audio Codec %s\n", WM8580_VERSION);
980
981 setup = socdev->codec_data; 977 setup = socdev->codec_data;
982 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); 978 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
983 if (codec == NULL) 979 if (codec == NULL)
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index cc6e57f9acf8..a6e8f3f7f052 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -51,11 +51,6 @@
51 51
52#include "wm8753.h" 52#include "wm8753.h"
53 53
54#ifdef CONFIG_SPI_MASTER
55static struct spi_driver wm8753_spi_driver;
56static int wm8753_spi_write(struct spi_device *spi, const char *data, int len);
57#endif
58
59static int caps_charge = 2000; 54static int caps_charge = 2000;
60module_param(caps_charge, int, 0); 55module_param(caps_charge, int, 0);
61MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); 56MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index b502741692d6..bd7392c9657e 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -20,7 +20,7 @@ config SND_DAVINCI_SOC_EVM
20 20
21config SND_DAVINCI_SOC_SFFSDR 21config SND_DAVINCI_SOC_SFFSDR
22 tristate "SoC Audio support for SFFSDR" 22 tristate "SoC Audio support for SFFSDR"
23 depends on SND_DAVINCI_SOC && MACH_DAVINCI_SFFSDR 23 depends on SND_DAVINCI_SOC && MACH_SFFSDR
24 select SND_DAVINCI_SOC_I2S 24 select SND_DAVINCI_SOC_I2S
25 select SND_SOC_PCM3008 25 select SND_SOC_PCM3008
26 select SFFSDR_FPGA 26 select SFFSDR_FPGA
diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c
index 0bf81abba8c7..40eccfe9e358 100644
--- a/sound/soc/davinci/davinci-sffsdr.c
+++ b/sound/soc/davinci/davinci-sffsdr.c
@@ -36,9 +36,16 @@
36#include "davinci-pcm.h" 36#include "davinci-pcm.h"
37#include "davinci-i2s.h" 37#include "davinci-i2s.h"
38 38
39/*
40 * CLKX and CLKR are the inputs for the Sample Rate Generator.
41 * FSX and FSR are outputs, driven by the sample Rate Generator.
42 */
43#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
44 SND_SOC_DAIFMT_CBM_CFS | \
45 SND_SOC_DAIFMT_IB_NF)
46
39static int sffsdr_hw_params(struct snd_pcm_substream *substream, 47static int sffsdr_hw_params(struct snd_pcm_substream *substream,
40 struct snd_pcm_hw_params *params, 48 struct snd_pcm_hw_params *params)
41 struct snd_soc_dai *dai)
42{ 49{
43 struct snd_soc_pcm_runtime *rtd = substream->private_data; 50 struct snd_soc_pcm_runtime *rtd = substream->private_data;
44 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 51 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
@@ -56,13 +63,8 @@ static int sffsdr_hw_params(struct snd_pcm_substream *substream,
56 } 63 }
57#endif 64#endif
58 65
59 /* Set cpu DAI configuration: 66 /* set cpu DAI configuration */
60 * CLKX and CLKR are the inputs for the Sample Rate Generator. 67 ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
61 * FSX and FSR are outputs, driven by the sample Rate Generator. */
62 ret = snd_soc_dai_set_fmt(cpu_dai,
63 SND_SOC_DAIFMT_RIGHT_J |
64 SND_SOC_DAIFMT_CBM_CFS |
65 SND_SOC_DAIFMT_IB_NF);
66 if (ret < 0) 68 if (ret < 0)
67 return ret; 69 return ret;
68 70
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 58a3fa497503..b3eb8570cd7b 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -142,7 +142,8 @@ static const struct snd_pcm_hardware fsl_dma_hardware = {
142 .info = SNDRV_PCM_INFO_INTERLEAVED | 142 .info = SNDRV_PCM_INFO_INTERLEAVED |
143 SNDRV_PCM_INFO_MMAP | 143 SNDRV_PCM_INFO_MMAP |
144 SNDRV_PCM_INFO_MMAP_VALID | 144 SNDRV_PCM_INFO_MMAP_VALID |
145 SNDRV_PCM_INFO_JOINT_DUPLEX, 145 SNDRV_PCM_INFO_JOINT_DUPLEX |
146 SNDRV_PCM_INFO_PAUSE,
146 .formats = FSLDMA_PCM_FORMATS, 147 .formats = FSLDMA_PCM_FORMATS,
147 .rates = FSLDMA_PCM_RATES, 148 .rates = FSLDMA_PCM_RATES,
148 .rate_min = 5512, 149 .rate_min = 5512,
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 0fddd437a7c9..169bca295b78 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -72,6 +72,7 @@
72 * @dev: struct device pointer 72 * @dev: struct device pointer
73 * @playback: the number of playback streams opened 73 * @playback: the number of playback streams opened
74 * @capture: the number of capture streams opened 74 * @capture: the number of capture streams opened
75 * @asynchronous: 0=synchronous mode, 1=asynchronous mode
75 * @cpu_dai: the CPU DAI for this device 76 * @cpu_dai: the CPU DAI for this device
76 * @dev_attr: the sysfs device attribute structure 77 * @dev_attr: the sysfs device attribute structure
77 * @stats: SSI statistics 78 * @stats: SSI statistics
@@ -86,6 +87,7 @@ struct fsl_ssi_private {
86 struct device *dev; 87 struct device *dev;
87 unsigned int playback; 88 unsigned int playback;
88 unsigned int capture; 89 unsigned int capture;
90 int asynchronous;
89 struct snd_soc_dai cpu_dai; 91 struct snd_soc_dai cpu_dai;
90 struct device_attribute dev_attr; 92 struct device_attribute dev_attr;
91 93
@@ -301,9 +303,10 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
301 * 303 *
302 * FIXME: Little-endian samples require a different shift dir 304 * FIXME: Little-endian samples require a different shift dir
303 */ 305 */
304 clrsetbits_be32(&ssi->scr, CCSR_SSI_SCR_I2S_MODE_MASK, 306 clrsetbits_be32(&ssi->scr,
305 CCSR_SSI_SCR_TFR_CLK_DIS | 307 CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
306 CCSR_SSI_SCR_I2S_MODE_SLAVE | CCSR_SSI_SCR_SYN); 308 CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE
309 | (ssi_private->asynchronous ? 0 : CCSR_SSI_SCR_SYN));
307 310
308 out_be32(&ssi->stcr, 311 out_be32(&ssi->stcr,
309 CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 | 312 CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
@@ -382,10 +385,15 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
382 SNDRV_PCM_HW_PARAM_RATE, 385 SNDRV_PCM_HW_PARAM_RATE,
383 first_runtime->rate, first_runtime->rate); 386 first_runtime->rate, first_runtime->rate);
384 387
385 snd_pcm_hw_constraint_minmax(substream->runtime, 388 /* If we're in synchronous mode, then we need to constrain
386 SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 389 * the sample size as well. We don't support independent sample
387 first_runtime->sample_bits, 390 * rates in asynchronous mode.
388 first_runtime->sample_bits); 391 */
392 if (!ssi_private->asynchronous)
393 snd_pcm_hw_constraint_minmax(substream->runtime,
394 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
395 first_runtime->sample_bits,
396 first_runtime->sample_bits);
389 397
390 ssi_private->second_stream = substream; 398 ssi_private->second_stream = substream;
391 } 399 }
@@ -421,13 +429,18 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
421 struct ccsr_ssi __iomem *ssi = ssi_private->ssi; 429 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
422 unsigned int sample_size = 430 unsigned int sample_size =
423 snd_pcm_format_width(params_format(hw_params)); 431 snd_pcm_format_width(params_format(hw_params));
424 u32 wl; 432 u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
425 433
426 /* The SSI should always be disabled at this points (SSIEN=0) */ 434 /* The SSI should always be disabled at this points (SSIEN=0) */
427 wl = CCSR_SSI_SxCCR_WL(sample_size);
428 435
429 /* In synchronous mode, the SSI uses STCCR for capture */ 436 /* In synchronous mode, the SSI uses STCCR for capture */
430 clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl); 437 if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
438 !ssi_private->asynchronous)
439 clrsetbits_be32(&ssi->stccr,
440 CCSR_SSI_SxCCR_WL_MASK, wl);
441 else
442 clrsetbits_be32(&ssi->srccr,
443 CCSR_SSI_SxCCR_WL_MASK, wl);
431 } 444 }
432 445
433 return 0; 446 return 0;
@@ -451,28 +464,33 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
451 464
452 switch (cmd) { 465 switch (cmd) {
453 case SNDRV_PCM_TRIGGER_START: 466 case SNDRV_PCM_TRIGGER_START:
454 case SNDRV_PCM_TRIGGER_RESUME: 467 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
455 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 468 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
456 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 469 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
457 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
458 setbits32(&ssi->scr, 470 setbits32(&ssi->scr,
459 CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE); 471 CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE);
460 } else { 472 } else {
461 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN); 473 long timeout = jiffies + 10;
474
462 setbits32(&ssi->scr, 475 setbits32(&ssi->scr,
463 CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE); 476 CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE);
464 477
465 /* 478 /* Wait until the SSI has filled its FIFO. Without this
466 * I think we need this delay to allow time for the SSI 479 * delay, ALSA complains about overruns. When the FIFO
467 * to put data into its FIFO. Without it, ALSA starts 480 * is full, the DMA controller initiates its first
468 * to complain about overruns. 481 * transfer. Until then, however, the DMA's DAR
482 * register is zero, which translates to an
483 * out-of-bounds pointer. This makes ALSA think an
484 * overrun has occurred.
469 */ 485 */
470 mdelay(1); 486 while (!(in_be32(&ssi->sisr) & CCSR_SSI_SISR_RFF0) &&
487 (jiffies < timeout));
488 if (!(in_be32(&ssi->sisr) & CCSR_SSI_SISR_RFF0))
489 return -EIO;
471 } 490 }
472 break; 491 break;
473 492
474 case SNDRV_PCM_TRIGGER_STOP: 493 case SNDRV_PCM_TRIGGER_STOP:
475 case SNDRV_PCM_TRIGGER_SUSPEND:
476 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 494 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
477 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 495 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
478 clrbits32(&ssi->scr, CCSR_SSI_SCR_TE); 496 clrbits32(&ssi->scr, CCSR_SSI_SCR_TE);
@@ -655,6 +673,7 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
655 ssi_private->ssi_phys = ssi_info->ssi_phys; 673 ssi_private->ssi_phys = ssi_info->ssi_phys;
656 ssi_private->irq = ssi_info->irq; 674 ssi_private->irq = ssi_info->irq;
657 ssi_private->dev = ssi_info->dev; 675 ssi_private->dev = ssi_info->dev;
676 ssi_private->asynchronous = ssi_info->asynchronous;
658 677
659 ssi_private->dev->driver_data = fsl_ssi_dai; 678 ssi_private->dev->driver_data = fsl_ssi_dai;
660 679
@@ -705,6 +724,14 @@ void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai)
705} 724}
706EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai); 725EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai);
707 726
727static int __init fsl_ssi_init(void)
728{
729 printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n");
730
731 return 0;
732}
733module_init(fsl_ssi_init);
734
708MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); 735MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
709MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver"); 736MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
710MODULE_LICENSE("GPL"); 737MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
index 83b44d700e33..eade01feaab6 100644
--- a/sound/soc/fsl/fsl_ssi.h
+++ b/sound/soc/fsl/fsl_ssi.h
@@ -208,6 +208,7 @@ struct ccsr_ssi {
208 * ssi_phys: physical address of the SSI registers 208 * ssi_phys: physical address of the SSI registers
209 * irq: IRQ of this SSI 209 * irq: IRQ of this SSI
210 * dev: struct device, used to create the sysfs statistics file 210 * dev: struct device, used to create the sysfs statistics file
211 * asynchronous: 0=synchronous mode, 1=asynchronous mode
211*/ 212*/
212struct fsl_ssi_info { 213struct fsl_ssi_info {
213 unsigned int id; 214 unsigned int id;
@@ -215,6 +216,7 @@ struct fsl_ssi_info {
215 dma_addr_t ssi_phys; 216 dma_addr_t ssi_phys;
216 unsigned int irq; 217 unsigned int irq;
217 struct device *dev; 218 struct device *dev;
219 int asynchronous;
218}; 220};
219 221
220struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info); 222struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info);
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index acf39a646b2f..ef67d1cdffe7 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -353,6 +353,11 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev,
353 } 353 }
354 ssi_info.irq = machine_data->ssi_irq; 354 ssi_info.irq = machine_data->ssi_irq;
355 355
356 /* Do we want to use asynchronous mode? */
357 ssi_info.asynchronous =
358 of_find_property(np, "fsl,ssi-asynchronous", NULL) ? 1 : 0;
359 if (ssi_info.asynchronous)
360 dev_info(&ofdev->dev, "using asynchronous mode\n");
356 361
357 /* Map the global utilities registers. */ 362 /* Map the global utilities registers. */
358 guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts"); 363 guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
index cd41a948df7b..a952a4eb3361 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/omap/osk5912.c
@@ -186,13 +186,6 @@ static int __init osk_soc_init(void)
186 return -ENODEV; 186 return -ENODEV;
187 } 187 }
188 188
189 if (clk_get_usecount(tlv320aic23_mclk) > 0) {
190 /* MCLK is already in use */
191 printk(KERN_WARNING
192 "MCLK in use at %d Hz. We change it to %d Hz\n",
193 (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK);
194 }
195
196 /* 189 /*
197 * Configure 12 MHz output on MCLK. 190 * Configure 12 MHz output on MCLK.
198 */ 191 */
@@ -205,9 +198,8 @@ static int __init osk_soc_init(void)
205 } 198 }
206 } 199 }
207 200
208 printk(KERN_INFO "MCLK = %d [%d], usecount = %d\n", 201 printk(KERN_INFO "MCLK = %d [%d]\n",
209 (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK, 202 (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK);
210 clk_get_usecount(tlv320aic23_mclk));
211 203
212 return 0; 204 return 0;
213err1: 205err1:
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index e226fa75669c..715c648203a4 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -28,6 +28,7 @@
28#include <sound/pcm.h> 28#include <sound/pcm.h>
29#include <sound/soc.h> 29#include <sound/soc.h>
30#include <sound/soc-dapm.h> 30#include <sound/soc-dapm.h>
31#include <sound/jack.h>
31 32
32#include <asm/mach-types.h> 33#include <asm/mach-types.h>
33#include <mach/hardware.h> 34#include <mach/hardware.h>
@@ -81,12 +82,97 @@ static struct snd_soc_ops sdp3430_ops = {
81 .hw_params = sdp3430_hw_params, 82 .hw_params = sdp3430_hw_params,
82}; 83};
83 84
85/* SDP3430 machine DAPM */
86static const struct snd_soc_dapm_widget sdp3430_twl4030_dapm_widgets[] = {
87 SND_SOC_DAPM_MIC("Ext Mic", NULL),
88 SND_SOC_DAPM_SPK("Ext Spk", NULL),
89 SND_SOC_DAPM_HP("Headset Jack", NULL),
90};
91
92static const struct snd_soc_dapm_route audio_map[] = {
93 /* External Mics: MAINMIC, SUBMIC with bias*/
94 {"MAINMIC", NULL, "Mic Bias 1"},
95 {"SUBMIC", NULL, "Mic Bias 2"},
96 {"Mic Bias 1", NULL, "Ext Mic"},
97 {"Mic Bias 2", NULL, "Ext Mic"},
98
99 /* External Speakers: HFL, HFR */
100 {"Ext Spk", NULL, "HFL"},
101 {"Ext Spk", NULL, "HFR"},
102
103 /* Headset: HSMIC (with bias), HSOL, HSOR */
104 {"Headset Jack", NULL, "HSOL"},
105 {"Headset Jack", NULL, "HSOR"},
106 {"HSMIC", NULL, "Headset Mic Bias"},
107 {"Headset Mic Bias", NULL, "Headset Jack"},
108};
109
110static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
111{
112 int ret;
113
114 /* Add SDP3430 specific widgets */
115 ret = snd_soc_dapm_new_controls(codec, sdp3430_twl4030_dapm_widgets,
116 ARRAY_SIZE(sdp3430_twl4030_dapm_widgets));
117 if (ret)
118 return ret;
119
120 /* Set up SDP3430 specific audio path audio_map */
121 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
122
123 /* SDP3430 connected pins */
124 snd_soc_dapm_enable_pin(codec, "Ext Mic");
125 snd_soc_dapm_enable_pin(codec, "Ext Spk");
126 snd_soc_dapm_disable_pin(codec, "Headset Jack");
127
128 /* TWL4030 not connected pins */
129 snd_soc_dapm_nc_pin(codec, "AUXL");
130 snd_soc_dapm_nc_pin(codec, "AUXR");
131 snd_soc_dapm_nc_pin(codec, "CARKITMIC");
132 snd_soc_dapm_nc_pin(codec, "DIGIMIC0");
133 snd_soc_dapm_nc_pin(codec, "DIGIMIC1");
134
135 snd_soc_dapm_nc_pin(codec, "OUTL");
136 snd_soc_dapm_nc_pin(codec, "OUTR");
137 snd_soc_dapm_nc_pin(codec, "EARPIECE");
138 snd_soc_dapm_nc_pin(codec, "PREDRIVEL");
139 snd_soc_dapm_nc_pin(codec, "PREDRIVER");
140 snd_soc_dapm_nc_pin(codec, "CARKITL");
141 snd_soc_dapm_nc_pin(codec, "CARKITR");
142
143 ret = snd_soc_dapm_sync(codec);
144
145 return ret;
146}
147
148/* Headset jack */
149static struct snd_soc_jack hs_jack;
150
151/* Headset jack detection DAPM pins */
152static struct snd_soc_jack_pin hs_jack_pins[] = {
153 {
154 .pin = "Headset Jack",
155 .mask = SND_JACK_HEADSET,
156 },
157};
158
159/* Headset jack detection gpios */
160static struct snd_soc_jack_gpio hs_jack_gpios[] = {
161 {
162 .gpio = (OMAP_MAX_GPIO_LINES + 2),
163 .name = "hsdet-gpio",
164 .report = SND_JACK_HEADSET,
165 .debounce_time = 200,
166 },
167};
168
84/* Digital audio interface glue - connects codec <--> CPU */ 169/* Digital audio interface glue - connects codec <--> CPU */
85static struct snd_soc_dai_link sdp3430_dai = { 170static struct snd_soc_dai_link sdp3430_dai = {
86 .name = "TWL4030", 171 .name = "TWL4030",
87 .stream_name = "TWL4030", 172 .stream_name = "TWL4030",
88 .cpu_dai = &omap_mcbsp_dai[0], 173 .cpu_dai = &omap_mcbsp_dai[0],
89 .codec_dai = &twl4030_dai, 174 .codec_dai = &twl4030_dai,
175 .init = sdp3430_twl4030_init,
90 .ops = &sdp3430_ops, 176 .ops = &sdp3430_ops,
91}; 177};
92 178
@@ -130,7 +216,21 @@ static int __init sdp3430_soc_init(void)
130 if (ret) 216 if (ret)
131 goto err1; 217 goto err1;
132 218
133 return 0; 219 /* Headset jack detection */
220 ret = snd_soc_jack_new(&snd_soc_sdp3430, "SDP3430 headset jack",
221 SND_JACK_HEADSET, &hs_jack);
222 if (ret)
223 return ret;
224
225 ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
226 hs_jack_pins);
227 if (ret)
228 return ret;
229
230 ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
231 hs_jack_gpios);
232
233 return ret;
134 234
135err1: 235err1:
136 printk(KERN_ERR "Unable to add platform device\n"); 236 printk(KERN_ERR "Unable to add platform device\n");
@@ -142,6 +242,9 @@ module_init(sdp3430_soc_init);
142 242
143static void __exit sdp3430_soc_exit(void) 243static void __exit sdp3430_soc_exit(void)
144{ 244{
245 snd_soc_jack_free_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
246 hs_jack_gpios);
247
145 platform_device_unregister(sdp3430_snd_device); 248 platform_device_unregister(sdp3430_snd_device);
146} 249}
147module_exit(sdp3430_soc_exit); 250module_exit(sdp3430_soc_exit);
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 3e18064e86b2..d3fa6357a9fd 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -300,7 +300,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
300 int val; 300 int val;
301 301
302 u32 sscr0 = ssp_read_reg(ssp, SSCR0) & 302 u32 sscr0 = ssp_read_reg(ssp, SSCR0) &
303 ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ADC); 303 ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
304 304
305 dev_dbg(&ssp->pdev->dev, 305 dev_dbg(&ssp->pdev->dev,
306 "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n", 306 "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n",
@@ -328,7 +328,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
328 case PXA_SSP_CLK_AUDIO: 328 case PXA_SSP_CLK_AUDIO:
329 priv->sysclk = 0; 329 priv->sysclk = 0;
330 ssp_set_scr(&priv->dev, 1); 330 ssp_set_scr(&priv->dev, 1);
331 sscr0 |= SSCR0_ADC; 331 sscr0 |= SSCR0_ACS;
332 break; 332 break;
333 default: 333 default:
334 return -ENODEV; 334 return -ENODEV;
@@ -522,9 +522,20 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
522 u32 sscr1; 522 u32 sscr1;
523 u32 sspsp; 523 u32 sspsp;
524 524
525 /* check if we need to change anything at all */
526 if (priv->dai_fmt == fmt)
527 return 0;
528
529 /* we can only change the settings if the port is not in use */
530 if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) {
531 dev_err(&ssp->pdev->dev,
532 "can't change hardware dai format: stream is in use");
533 return -EINVAL;
534 }
535
525 /* reset port settings */ 536 /* reset port settings */
526 sscr0 = ssp_read_reg(ssp, SSCR0) & 537 sscr0 = ssp_read_reg(ssp, SSCR0) &
527 (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ADC); 538 (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
528 sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7); 539 sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
529 sspsp = 0; 540 sspsp = 0;
530 541
@@ -644,8 +655,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
644 sscr0 |= SSCR0_FPCKE; 655 sscr0 |= SSCR0_FPCKE;
645#endif 656#endif
646 sscr0 |= SSCR0_DataSize(16); 657 sscr0 |= SSCR0_DataSize(16);
647 if (params_channels(params) > 1) 658 /* use network mode (2 slots) for 16 bit stereo */
648 sscr0 |= SSCR0_EDSS;
649 break; 659 break;
650 case SNDRV_PCM_FORMAT_S24_LE: 660 case SNDRV_PCM_FORMAT_S24_LE:
651 sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8)); 661 sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8));
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index 11cd0f289c16..cf809049272a 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -106,13 +106,13 @@ static int pxa2xx_ac97_resume(struct snd_soc_dai *dai)
106static int pxa2xx_ac97_probe(struct platform_device *pdev, 106static int pxa2xx_ac97_probe(struct platform_device *pdev,
107 struct snd_soc_dai *dai) 107 struct snd_soc_dai *dai)
108{ 108{
109 return pxa2xx_ac97_hw_probe(pdev); 109 return pxa2xx_ac97_hw_probe(to_platform_device(dai->dev));
110} 110}
111 111
112static void pxa2xx_ac97_remove(struct platform_device *pdev, 112static void pxa2xx_ac97_remove(struct platform_device *pdev,
113 struct snd_soc_dai *dai) 113 struct snd_soc_dai *dai)
114{ 114{
115 pxa2xx_ac97_hw_remove(pdev); 115 pxa2xx_ac97_hw_remove(to_platform_device(dai->dev));
116} 116}
117 117
118static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, 118static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
@@ -230,15 +230,45 @@ struct snd_soc_dai pxa_ac97_dai[] = {
230EXPORT_SYMBOL_GPL(pxa_ac97_dai); 230EXPORT_SYMBOL_GPL(pxa_ac97_dai);
231EXPORT_SYMBOL_GPL(soc_ac97_ops); 231EXPORT_SYMBOL_GPL(soc_ac97_ops);
232 232
233static int __init pxa_ac97_init(void) 233static int __devinit pxa2xx_ac97_dev_probe(struct platform_device *pdev)
234{ 234{
235 int i;
236
237 for (i = 0; i < ARRAY_SIZE(pxa_ac97_dai); i++)
238 pxa_ac97_dai[i].dev = &pdev->dev;
239
240 /* Punt most of the init to the SoC probe; we may need the machine
241 * driver to do interesting things with the clocking to get us up
242 * and running.
243 */
235 return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai)); 244 return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
236} 245}
246
247static int __devexit pxa2xx_ac97_dev_remove(struct platform_device *pdev)
248{
249 snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
250
251 return 0;
252}
253
254static struct platform_driver pxa2xx_ac97_driver = {
255 .probe = pxa2xx_ac97_dev_probe,
256 .remove = __devexit_p(pxa2xx_ac97_dev_remove),
257 .driver = {
258 .name = "pxa2xx-ac97",
259 .owner = THIS_MODULE,
260 },
261};
262
263static int __init pxa_ac97_init(void)
264{
265 return platform_driver_register(&pxa2xx_ac97_driver);
266}
237module_init(pxa_ac97_init); 267module_init(pxa_ac97_init);
238 268
239static void __exit pxa_ac97_exit(void) 269static void __exit pxa_ac97_exit(void)
240{ 270{
241 snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai)); 271 platform_driver_unregister(&pxa2xx_ac97_driver);
242} 272}
243module_exit(pxa_ac97_exit); 273module_exit(pxa_ac97_exit);
244 274
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c
index 0140a250db24..9f6116edbb84 100644
--- a/sound/soc/pxa/zylonite.c
+++ b/sound/soc/pxa/zylonite.c
@@ -127,8 +127,11 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
127 if (ret < 0) 127 if (ret < 0)
128 return ret; 128 return ret;
129 129
130 /* We're not really in network mode but the emulation wants this. */ 130 /* Use network mode for stereo, one slot per channel. */
131 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1); 131 if (params_channels(params) > 1)
132 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 2);
133 else
134 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1);
132 if (ret < 0) 135 if (ret < 0)
133 return ret; 136 return ret;
134 137
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index e05a71084c32..2f3a21eee051 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -1,19 +1,31 @@
1config SND_S3C24XX_SOC 1config SND_S3C24XX_SOC
2 tristate "SoC Audio for the Samsung S3C24XX chips" 2 tristate "SoC Audio for the Samsung S3CXXXX chips"
3 depends on ARCH_S3C2410 3 depends on ARCH_S3C2410 || ARCH_S3C64XX
4 help 4 help
5 Say Y or M if you want to add support for codecs attached to 5 Say Y or M if you want to add support for codecs attached to
6 the S3C24XX AC97, I2S or SSP interface. You will also need 6 the S3C24XX and S3C64XX AC97, I2S or SSP interface. You will
7 to select the audio interfaces to support below. 7 also need to select the audio interfaces to support below.
8 8
9config SND_S3C24XX_SOC_I2S 9config SND_S3C24XX_SOC_I2S
10 tristate 10 tristate
11 select S3C2410_DMA
12
13config SND_S3C_I2SV2_SOC
14 tristate
11 15
12config SND_S3C2412_SOC_I2S 16config SND_S3C2412_SOC_I2S
13 tristate 17 tristate
18 select SND_S3C_I2SV2_SOC
19 select S3C2410_DMA
20
21config SND_S3C64XX_SOC_I2S
22 tristate
23 select SND_S3C_I2SV2_SOC
24 select S3C64XX_DMA
14 25
15config SND_S3C2443_SOC_AC97 26config SND_S3C2443_SOC_AC97
16 tristate 27 tristate
28 select S3C2410_DMA
17 select AC97_BUS 29 select AC97_BUS
18 select SND_SOC_AC97_BUS 30 select SND_SOC_AC97_BUS
19 31
@@ -26,6 +38,14 @@ config SND_S3C24XX_SOC_NEO1973_WM8753
26 Say Y if you want to add support for SoC audio on smdk2440 38 Say Y if you want to add support for SoC audio on smdk2440
27 with the WM8753. 39 with the WM8753.
28 40
41config SND_S3C24XX_SOC_JIVE_WM8750
42 tristate "SoC I2S Audio support for Jive"
43 depends on SND_S3C24XX_SOC && MACH_JIVE
44 select SND_SOC_WM8750
45 select SND_S3C2412_SOC_I2S
46 help
47 Sat Y if you want to add support for SoC audio on the Jive.
48
29config SND_S3C24XX_SOC_SMDK2443_WM9710 49config SND_S3C24XX_SOC_SMDK2443_WM9710
30 tristate "SoC AC97 Audio support for SMDK2443 - WM9710" 50 tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
31 depends on SND_S3C24XX_SOC && MACH_SMDK2443 51 depends on SND_S3C24XX_SOC && MACH_SMDK2443
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 96b3f3f617d4..07a93a2ebe5f 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -2,19 +2,25 @@
2snd-soc-s3c24xx-objs := s3c24xx-pcm.o 2snd-soc-s3c24xx-objs := s3c24xx-pcm.o
3snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o 3snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
4snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o 4snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
5snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o
5snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o 6snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o
7snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
6 8
7obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o 9obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
8obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o 10obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
9obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o 11obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o
10obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o 12obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
13obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
14obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
11 15
12# S3C24XX Machine Support 16# S3C24XX Machine Support
17snd-soc-jive-wm8750-objs := jive_wm8750.o
13snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o 18snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
14snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o 19snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
15snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o 20snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o
16snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o 21snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
17 22
23obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o
18obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o 24obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
19obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o 25obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
20obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o 26obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c
new file mode 100644
index 000000000000..32063790d95b
--- /dev/null
+++ b/sound/soc/s3c24xx/jive_wm8750.c
@@ -0,0 +1,201 @@
1/* sound/soc/s3c24xx/jive_wm8750.c
2 *
3 * Copyright 2007,2008 Simtec Electronics
4 *
5 * Based on sound/soc/pxa/spitz.c
6 * Copyright 2005 Wolfson Microelectronics PLC.
7 * Copyright 2005 Openedhand Ltd.
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#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/timer.h>
17#include <linux/interrupt.h>
18#include <linux/platform_device.h>
19#include <linux/clk.h>
20
21#include <sound/core.h>
22#include <sound/pcm.h>
23#include <sound/soc.h>
24#include <sound/soc-dapm.h>
25
26#include <asm/mach-types.h>
27
28#include "s3c24xx-pcm.h"
29#include "s3c2412-i2s.h"
30
31#include "../codecs/wm8750.h"
32
33static const struct snd_soc_dapm_route audio_map[] = {
34 { "Headphone Jack", NULL, "LOUT1" },
35 { "Headphone Jack", NULL, "ROUT1" },
36 { "Internal Speaker", NULL, "LOUT2" },
37 { "Internal Speaker", NULL, "ROUT2" },
38 { "LINPUT1", NULL, "Line Input" },
39 { "RINPUT1", NULL, "Line Input" },
40};
41
42static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
43 SND_SOC_DAPM_HP("Headphone Jack", NULL),
44 SND_SOC_DAPM_SPK("Internal Speaker", NULL),
45 SND_SOC_DAPM_LINE("Line In", NULL),
46};
47
48static int jive_hw_params(struct snd_pcm_substream *substream,
49 struct snd_pcm_hw_params *params)
50{
51 struct snd_soc_pcm_runtime *rtd = substream->private_data;
52 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
53 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
54 struct s3c_i2sv2_rate_calc div;
55 unsigned int clk = 0;
56 int ret = 0;
57
58 switch (params_rate(params)) {
59 case 8000:
60 case 16000:
61 case 48000:
62 case 96000:
63 clk = 12288000;
64 break;
65 case 11025:
66 case 22050:
67 case 44100:
68 clk = 11289600;
69 break;
70 }
71
72 s3c_i2sv2_calc_rate(&div, NULL, params_rate(params),
73 s3c2412_get_iisclk());
74
75 /* set codec DAI configuration */
76 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
77 SND_SOC_DAIFMT_NB_NF |
78 SND_SOC_DAIFMT_CBS_CFS);
79 if (ret < 0)
80 return ret;
81
82 /* set cpu DAI configuration */
83 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
84 SND_SOC_DAIFMT_NB_NF |
85 SND_SOC_DAIFMT_CBS_CFS);
86 if (ret < 0)
87 return ret;
88
89 /* set the codec system clock for DAC and ADC */
90 ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
91 SND_SOC_CLOCK_IN);
92 if (ret < 0)
93 return ret;
94
95 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_RCLK, div.fs_div);
96 if (ret < 0)
97 return ret;
98
99 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER,
100 div.clk_div - 1);
101 if (ret < 0)
102 return ret;
103
104 return 0;
105}
106
107static struct snd_soc_ops jive_ops = {
108 .hw_params = jive_hw_params,
109};
110
111static int jive_wm8750_init(struct snd_soc_codec *codec)
112{
113 int err;
114
115 /* These endpoints are not being used. */
116 snd_soc_dapm_nc_pin(codec, "LINPUT2");
117 snd_soc_dapm_nc_pin(codec, "RINPUT2");
118 snd_soc_dapm_nc_pin(codec, "LINPUT3");
119 snd_soc_dapm_nc_pin(codec, "RINPUT3");
120 snd_soc_dapm_nc_pin(codec, "OUT3");
121 snd_soc_dapm_nc_pin(codec, "MONO");
122
123 /* Add jive specific widgets */
124 err = snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets,
125 ARRAY_SIZE(wm8750_dapm_widgets));
126 if (err) {
127 printk(KERN_ERR "%s: failed to add widgets (%d)\n",
128 __func__, err);
129 return err;
130 }
131
132 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
133 snd_soc_dapm_sync(codec);
134
135 return 0;
136}
137
138static struct snd_soc_dai_link jive_dai = {
139 .name = "wm8750",
140 .stream_name = "WM8750",
141 .cpu_dai = &s3c2412_i2s_dai,
142 .codec_dai = &wm8750_dai,
143 .init = jive_wm8750_init,
144 .ops = &jive_ops,
145};
146
147/* jive audio machine driver */
148static struct snd_soc_machine snd_soc_machine_jive = {
149 .name = "Jive",
150 .dai_link = &jive_dai,
151 .num_links = 1,
152};
153
154/* jive audio private data */
155static struct wm8750_setup_data jive_wm8750_setup = {
156};
157
158/* jive audio subsystem */
159static struct snd_soc_device jive_snd_devdata = {
160 .machine = &snd_soc_machine_jive,
161 .platform = &s3c24xx_soc_platform,
162 .codec_dev = &soc_codec_dev_wm8750_spi,
163 .codec_data = &jive_wm8750_setup,
164};
165
166static struct platform_device *jive_snd_device;
167
168static int __init jive_init(void)
169{
170 int ret;
171
172 if (!machine_is_jive())
173 return 0;
174
175 printk("JIVE WM8750 Audio support\n");
176
177 jive_snd_device = platform_device_alloc("soc-audio", -1);
178 if (!jive_snd_device)
179 return -ENOMEM;
180
181 platform_set_drvdata(jive_snd_device, &jive_snd_devdata);
182 jive_snd_devdata.dev = &jive_snd_device->dev;
183 ret = platform_device_add(jive_snd_device);
184
185 if (ret)
186 platform_device_put(jive_snd_device);
187
188 return ret;
189}
190
191static void __exit jive_exit(void)
192{
193 platform_device_unregister(jive_snd_device);
194}
195
196module_init(jive_init);
197module_exit(jive_exit);
198
199MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
200MODULE_DESCRIPTION("ALSA SoC Jive Audio support");
201MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index 286e11ad50ea..5f6aeec0437d 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -29,25 +29,17 @@
29#include <mach/regs-clock.h> 29#include <mach/regs-clock.h>
30#include <mach/regs-gpio.h> 30#include <mach/regs-gpio.h>
31#include <mach/hardware.h> 31#include <mach/hardware.h>
32#include <mach/audio.h> 32#include <plat/audio.h>
33#include <linux/io.h> 33#include <linux/io.h>
34#include <mach/spi-gpio.h> 34#include <mach/spi-gpio.h>
35 35
36#include <asm/plat-s3c24xx/regs-iis.h> 36#include <plat/regs-iis.h>
37 37
38#include "../codecs/wm8753.h" 38#include "../codecs/wm8753.h"
39#include "lm4857.h" 39#include "lm4857.h"
40#include "s3c24xx-pcm.h" 40#include "s3c24xx-pcm.h"
41#include "s3c24xx-i2s.h" 41#include "s3c24xx-i2s.h"
42 42
43/* Debugging stuff */
44#define S3C24XX_SOC_NEO1973_WM8753_DEBUG 0
45#if S3C24XX_SOC_NEO1973_WM8753_DEBUG
46#define DBG(x...) printk(KERN_DEBUG "s3c24xx-soc-neo1973-wm8753: " x)
47#else
48#define DBG(x...)
49#endif
50
51/* define the scenarios */ 43/* define the scenarios */
52#define NEO_AUDIO_OFF 0 44#define NEO_AUDIO_OFF 0
53#define NEO_GSM_CALL_AUDIO_HANDSET 1 45#define NEO_GSM_CALL_AUDIO_HANDSET 1
@@ -72,7 +64,7 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
72 int ret = 0; 64 int ret = 0;
73 unsigned long iis_clkrate; 65 unsigned long iis_clkrate;
74 66
75 DBG("Entered %s\n", __func__); 67 pr_debug("Entered %s\n", __func__);
76 68
77 iis_clkrate = s3c24xx_i2s_get_clockrate(); 69 iis_clkrate = s3c24xx_i2s_get_clockrate();
78 70
@@ -158,7 +150,7 @@ static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
158 struct snd_soc_pcm_runtime *rtd = substream->private_data; 150 struct snd_soc_pcm_runtime *rtd = substream->private_data;
159 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; 151 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
160 152
161 DBG("Entered %s\n", __func__); 153 pr_debug("Entered %s\n", __func__);
162 154
163 /* disable the PLL */ 155 /* disable the PLL */
164 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); 156 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0);
@@ -181,7 +173,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
181 int ret = 0; 173 int ret = 0;
182 unsigned long iis_clkrate; 174 unsigned long iis_clkrate;
183 175
184 DBG("Entered %s\n", __func__); 176 pr_debug("Entered %s\n", __func__);
185 177
186 iis_clkrate = s3c24xx_i2s_get_clockrate(); 178 iis_clkrate = s3c24xx_i2s_get_clockrate();
187 179
@@ -224,7 +216,7 @@ static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
224 struct snd_soc_pcm_runtime *rtd = substream->private_data; 216 struct snd_soc_pcm_runtime *rtd = substream->private_data;
225 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; 217 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
226 218
227 DBG("Entered %s\n", __func__); 219 pr_debug("Entered %s\n", __func__);
228 220
229 /* disable the PLL */ 221 /* disable the PLL */
230 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); 222 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0);
@@ -246,7 +238,7 @@ static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
246 238
247static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario) 239static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
248{ 240{
249 DBG("Entered %s\n", __func__); 241 pr_debug("Entered %s\n", __func__);
250 242
251 switch (neo1973_scenario) { 243 switch (neo1973_scenario) {
252 case NEO_AUDIO_OFF: 244 case NEO_AUDIO_OFF:
@@ -330,7 +322,7 @@ static int neo1973_set_scenario(struct snd_kcontrol *kcontrol,
330{ 322{
331 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 323 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
332 324
333 DBG("Entered %s\n", __func__); 325 pr_debug("Entered %s\n", __func__);
334 326
335 if (neo1973_scenario == ucontrol->value.integer.value[0]) 327 if (neo1973_scenario == ucontrol->value.integer.value[0])
336 return 0; 328 return 0;
@@ -344,7 +336,7 @@ static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
344 336
345static void lm4857_write_regs(void) 337static void lm4857_write_regs(void)
346{ 338{
347 DBG("Entered %s\n", __func__); 339 pr_debug("Entered %s\n", __func__);
348 340
349 if (i2c_master_send(i2c, lm4857_regs, 4) != 4) 341 if (i2c_master_send(i2c, lm4857_regs, 4) != 4)
350 printk(KERN_ERR "lm4857: i2c write failed\n"); 342 printk(KERN_ERR "lm4857: i2c write failed\n");
@@ -357,7 +349,7 @@ static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
357 int shift = (kcontrol->private_value >> 8) & 0x0F; 349 int shift = (kcontrol->private_value >> 8) & 0x0F;
358 int mask = (kcontrol->private_value >> 16) & 0xFF; 350 int mask = (kcontrol->private_value >> 16) & 0xFF;
359 351
360 DBG("Entered %s\n", __func__); 352 pr_debug("Entered %s\n", __func__);
361 353
362 ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask; 354 ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
363 return 0; 355 return 0;
@@ -385,7 +377,7 @@ static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
385{ 377{
386 u8 value = lm4857_regs[LM4857_CTRL] & 0x0F; 378 u8 value = lm4857_regs[LM4857_CTRL] & 0x0F;
387 379
388 DBG("Entered %s\n", __func__); 380 pr_debug("Entered %s\n", __func__);
389 381
390 if (value) 382 if (value)
391 value -= 5; 383 value -= 5;
@@ -399,7 +391,7 @@ static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
399{ 391{
400 u8 value = ucontrol->value.integer.value[0]; 392 u8 value = ucontrol->value.integer.value[0];
401 393
402 DBG("Entered %s\n", __func__); 394 pr_debug("Entered %s\n", __func__);
403 395
404 if (value) 396 if (value)
405 value += 5; 397 value += 5;
@@ -508,7 +500,7 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec)
508{ 500{
509 int i, err; 501 int i, err;
510 502
511 DBG("Entered %s\n", __func__); 503 pr_debug("Entered %s\n", __func__);
512 504
513 /* set up NC codec pins */ 505 /* set up NC codec pins */
514 snd_soc_dapm_nc_pin(codec, "LOUT2"); 506 snd_soc_dapm_nc_pin(codec, "LOUT2");
@@ -593,7 +585,7 @@ static struct snd_soc_device neo1973_snd_devdata = {
593static int lm4857_i2c_probe(struct i2c_client *client, 585static int lm4857_i2c_probe(struct i2c_client *client,
594 const struct i2c_device_id *id) 586 const struct i2c_device_id *id)
595{ 587{
596 DBG("Entered %s\n", __func__); 588 pr_debug("Entered %s\n", __func__);
597 589
598 i2c = client; 590 i2c = client;
599 591
@@ -603,7 +595,7 @@ static int lm4857_i2c_probe(struct i2c_client *client,
603 595
604static int lm4857_i2c_remove(struct i2c_client *client) 596static int lm4857_i2c_remove(struct i2c_client *client)
605{ 597{
606 DBG("Entered %s\n", __func__); 598 pr_debug("Entered %s\n", __func__);
607 599
608 i2c = NULL; 600 i2c = NULL;
609 601
@@ -614,7 +606,7 @@ static u8 lm4857_state;
614 606
615static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) 607static int lm4857_suspend(struct i2c_client *dev, pm_message_t state)
616{ 608{
617 DBG("Entered %s\n", __func__); 609 pr_debug("Entered %s\n", __func__);
618 610
619 dev_dbg(&dev->dev, "lm4857_suspend\n"); 611 dev_dbg(&dev->dev, "lm4857_suspend\n");
620 lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf; 612 lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf;
@@ -627,7 +619,7 @@ static int lm4857_suspend(struct i2c_client *dev, pm_message_t state)
627 619
628static int lm4857_resume(struct i2c_client *dev) 620static int lm4857_resume(struct i2c_client *dev)
629{ 621{
630 DBG("Entered %s\n", __func__); 622 pr_debug("Entered %s\n", __func__);
631 623
632 if (lm4857_state) { 624 if (lm4857_state) {
633 lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f); 625 lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f);
@@ -638,7 +630,7 @@ static int lm4857_resume(struct i2c_client *dev)
638 630
639static void lm4857_shutdown(struct i2c_client *dev) 631static void lm4857_shutdown(struct i2c_client *dev)
640{ 632{
641 DBG("Entered %s\n", __func__); 633 pr_debug("Entered %s\n", __func__);
642 634
643 dev_dbg(&dev->dev, "lm4857_shutdown\n"); 635 dev_dbg(&dev->dev, "lm4857_shutdown\n");
644 lm4857_regs[LM4857_CTRL] &= 0xf0; 636 lm4857_regs[LM4857_CTRL] &= 0xf0;
@@ -669,7 +661,7 @@ static int __init neo1973_init(void)
669{ 661{
670 int ret; 662 int ret;
671 663
672 DBG("Entered %s\n", __func__); 664 pr_debug("Entered %s\n", __func__);
673 665
674 if (!machine_is_neo1973_gta01()) { 666 if (!machine_is_neo1973_gta01()) {
675 printk(KERN_INFO 667 printk(KERN_INFO
@@ -700,7 +692,7 @@ static int __init neo1973_init(void)
700 692
701static void __exit neo1973_exit(void) 693static void __exit neo1973_exit(void)
702{ 694{
703 DBG("Entered %s\n", __func__); 695 pr_debug("Entered %s\n", __func__);
704 696
705 i2c_del_driver(&lm4857_i2c_driver); 697 i2c_del_driver(&lm4857_i2c_driver);
706 platform_device_unregister(neo1973_snd_device); 698 platform_device_unregister(neo1973_snd_device);
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
new file mode 100644
index 000000000000..295a4c910262
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -0,0 +1,638 @@
1/* sound/soc/s3c24xx/s3c-i2c-v2.c
2 *
3 * ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
4 *
5 * Copyright (c) 2006 Wolfson Microelectronics PLC.
6 * Graeme Gregory graeme.gregory@wolfsonmicro.com
7 * linux@wolfsonmicro.com
8 *
9 * Copyright (c) 2008, 2007, 2004-2005 Simtec Electronics
10 * http://armlinux.simtec.co.uk/
11 * Ben Dooks <ben@simtec.co.uk>
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version.
17 */
18
19#include <linux/init.h>
20#include <linux/module.h>
21#include <linux/device.h>
22#include <linux/delay.h>
23#include <linux/clk.h>
24#include <linux/kernel.h>
25#include <linux/io.h>
26
27#include <sound/core.h>
28#include <sound/pcm.h>
29#include <sound/pcm_params.h>
30#include <sound/initval.h>
31#include <sound/soc.h>
32
33#include <plat/regs-s3c2412-iis.h>
34
35#include <plat/audio.h>
36#include <mach/dma.h>
37
38#include "s3c-i2s-v2.h"
39
40#define S3C2412_I2S_DEBUG_CON 0
41
42static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
43{
44 return cpu_dai->private_data;
45}
46
47#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
48
49#if S3C2412_I2S_DEBUG_CON
50static void dbg_showcon(const char *fn, u32 con)
51{
52 printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
53 bit_set(con, S3C2412_IISCON_LRINDEX),
54 bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
55 bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
56 bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
57 bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
58
59 printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
60 fn,
61 bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
62 bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
63 bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
64 bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
65 printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
66 bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
67 bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
68 bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
69}
70#else
71static inline void dbg_showcon(const char *fn, u32 con)
72{
73}
74#endif
75
76
77/* Turn on or off the transmission path. */
78void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
79{
80 void __iomem *regs = i2s->regs;
81 u32 fic, con, mod;
82
83 pr_debug("%s(%d)\n", __func__, on);
84
85 fic = readl(regs + S3C2412_IISFIC);
86 con = readl(regs + S3C2412_IISCON);
87 mod = readl(regs + S3C2412_IISMOD);
88
89 pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
90
91 if (on) {
92 con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
93 con &= ~S3C2412_IISCON_TXDMA_PAUSE;
94 con &= ~S3C2412_IISCON_TXCH_PAUSE;
95
96 switch (mod & S3C2412_IISMOD_MODE_MASK) {
97 case S3C2412_IISMOD_MODE_TXONLY:
98 case S3C2412_IISMOD_MODE_TXRX:
99 /* do nothing, we are in the right mode */
100 break;
101
102 case S3C2412_IISMOD_MODE_RXONLY:
103 mod &= ~S3C2412_IISMOD_MODE_MASK;
104 mod |= S3C2412_IISMOD_MODE_TXRX;
105 break;
106
107 default:
108 dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n");
109 }
110
111 writel(con, regs + S3C2412_IISCON);
112 writel(mod, regs + S3C2412_IISMOD);
113 } else {
114 /* Note, we do not have any indication that the FIFO problems
115 * tha the S3C2410/2440 had apply here, so we should be able
116 * to disable the DMA and TX without resetting the FIFOS.
117 */
118
119 con |= S3C2412_IISCON_TXDMA_PAUSE;
120 con |= S3C2412_IISCON_TXCH_PAUSE;
121 con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
122
123 switch (mod & S3C2412_IISMOD_MODE_MASK) {
124 case S3C2412_IISMOD_MODE_TXRX:
125 mod &= ~S3C2412_IISMOD_MODE_MASK;
126 mod |= S3C2412_IISMOD_MODE_RXONLY;
127 break;
128
129 case S3C2412_IISMOD_MODE_TXONLY:
130 mod &= ~S3C2412_IISMOD_MODE_MASK;
131 con &= ~S3C2412_IISCON_IIS_ACTIVE;
132 break;
133
134 default:
135 dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n");
136 }
137
138 writel(mod, regs + S3C2412_IISMOD);
139 writel(con, regs + S3C2412_IISCON);
140 }
141
142 fic = readl(regs + S3C2412_IISFIC);
143 dbg_showcon(__func__, con);
144 pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
145}
146EXPORT_SYMBOL_GPL(s3c2412_snd_txctrl);
147
148void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
149{
150 void __iomem *regs = i2s->regs;
151 u32 fic, con, mod;
152
153 pr_debug("%s(%d)\n", __func__, on);
154
155 fic = readl(regs + S3C2412_IISFIC);
156 con = readl(regs + S3C2412_IISCON);
157 mod = readl(regs + S3C2412_IISMOD);
158
159 pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
160
161 if (on) {
162 con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
163 con &= ~S3C2412_IISCON_RXDMA_PAUSE;
164 con &= ~S3C2412_IISCON_RXCH_PAUSE;
165
166 switch (mod & S3C2412_IISMOD_MODE_MASK) {
167 case S3C2412_IISMOD_MODE_TXRX:
168 case S3C2412_IISMOD_MODE_RXONLY:
169 /* do nothing, we are in the right mode */
170 break;
171
172 case S3C2412_IISMOD_MODE_TXONLY:
173 mod &= ~S3C2412_IISMOD_MODE_MASK;
174 mod |= S3C2412_IISMOD_MODE_TXRX;
175 break;
176
177 default:
178 dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
179 }
180
181 writel(mod, regs + S3C2412_IISMOD);
182 writel(con, regs + S3C2412_IISCON);
183 } else {
184 /* See txctrl notes on FIFOs. */
185
186 con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
187 con |= S3C2412_IISCON_RXDMA_PAUSE;
188 con |= S3C2412_IISCON_RXCH_PAUSE;
189
190 switch (mod & S3C2412_IISMOD_MODE_MASK) {
191 case S3C2412_IISMOD_MODE_RXONLY:
192 con &= ~S3C2412_IISCON_IIS_ACTIVE;
193 mod &= ~S3C2412_IISMOD_MODE_MASK;
194 break;
195
196 case S3C2412_IISMOD_MODE_TXRX:
197 mod &= ~S3C2412_IISMOD_MODE_MASK;
198 mod |= S3C2412_IISMOD_MODE_TXONLY;
199 break;
200
201 default:
202 dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
203 }
204
205 writel(con, regs + S3C2412_IISCON);
206 writel(mod, regs + S3C2412_IISMOD);
207 }
208
209 fic = readl(regs + S3C2412_IISFIC);
210 pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
211}
212EXPORT_SYMBOL_GPL(s3c2412_snd_rxctrl);
213
214/*
215 * Wait for the LR signal to allow synchronisation to the L/R clock
216 * from the codec. May only be needed for slave mode.
217 */
218static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s)
219{
220 u32 iiscon;
221 unsigned long timeout = jiffies + msecs_to_jiffies(5);
222
223 pr_debug("Entered %s\n", __func__);
224
225 while (1) {
226 iiscon = readl(i2s->regs + S3C2412_IISCON);
227 if (iiscon & S3C2412_IISCON_LRINDEX)
228 break;
229
230 if (timeout < jiffies) {
231 printk(KERN_ERR "%s: timeout\n", __func__);
232 return -ETIMEDOUT;
233 }
234 }
235
236 return 0;
237}
238
239/*
240 * Set S3C2412 I2S DAI format
241 */
242static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
243 unsigned int fmt)
244{
245 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
246 u32 iismod;
247
248 pr_debug("Entered %s\n", __func__);
249
250 iismod = readl(i2s->regs + S3C2412_IISMOD);
251 pr_debug("hw_params r: IISMOD: %x \n", iismod);
252
253#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
254#define IISMOD_MASTER_MASK S3C2412_IISMOD_MASTER_MASK
255#define IISMOD_SLAVE S3C2412_IISMOD_SLAVE
256#define IISMOD_MASTER S3C2412_IISMOD_MASTER_INTERNAL
257#endif
258
259#if defined(CONFIG_PLAT_S3C64XX)
260/* From Rev1.1 datasheet, we have two master and two slave modes:
261 * IMS[11:10]:
262 * 00 = master mode, fed from PCLK
263 * 01 = master mode, fed from CLKAUDIO
264 * 10 = slave mode, using PCLK
265 * 11 = slave mode, using I2SCLK
266 */
267#define IISMOD_MASTER_MASK (1 << 11)
268#define IISMOD_SLAVE (1 << 11)
269#define IISMOD_MASTER (0x0)
270#endif
271
272 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
273 case SND_SOC_DAIFMT_CBM_CFM:
274 i2s->master = 0;
275 iismod &= ~IISMOD_MASTER_MASK;
276 iismod |= IISMOD_SLAVE;
277 break;
278 case SND_SOC_DAIFMT_CBS_CFS:
279 i2s->master = 1;
280 iismod &= ~IISMOD_MASTER_MASK;
281 iismod |= IISMOD_MASTER;
282 break;
283 default:
284 pr_debug("unknwon master/slave format\n");
285 return -EINVAL;
286 }
287
288 iismod &= ~S3C2412_IISMOD_SDF_MASK;
289
290 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
291 case SND_SOC_DAIFMT_RIGHT_J:
292 iismod |= S3C2412_IISMOD_SDF_MSB;
293 break;
294 case SND_SOC_DAIFMT_LEFT_J:
295 iismod |= S3C2412_IISMOD_SDF_LSB;
296 break;
297 case SND_SOC_DAIFMT_I2S:
298 iismod |= S3C2412_IISMOD_SDF_IIS;
299 break;
300 default:
301 pr_debug("Unknown data format\n");
302 return -EINVAL;
303 }
304
305 writel(iismod, i2s->regs + S3C2412_IISMOD);
306 pr_debug("hw_params w: IISMOD: %x \n", iismod);
307 return 0;
308}
309
310static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
311 struct snd_pcm_hw_params *params,
312 struct snd_soc_dai *socdai)
313{
314 struct snd_soc_pcm_runtime *rtd = substream->private_data;
315 struct snd_soc_dai_link *dai = rtd->dai;
316 struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai);
317 u32 iismod;
318
319 pr_debug("Entered %s\n", __func__);
320
321 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
322 dai->cpu_dai->dma_data = i2s->dma_playback;
323 else
324 dai->cpu_dai->dma_data = i2s->dma_capture;
325
326 /* Working copies of register */
327 iismod = readl(i2s->regs + S3C2412_IISMOD);
328 pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
329
330 switch (params_format(params)) {
331 case SNDRV_PCM_FORMAT_S8:
332 iismod |= S3C2412_IISMOD_8BIT;
333 break;
334 case SNDRV_PCM_FORMAT_S16_LE:
335 iismod &= ~S3C2412_IISMOD_8BIT;
336 break;
337 }
338
339 writel(iismod, i2s->regs + S3C2412_IISMOD);
340 pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
341 return 0;
342}
343
344static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
345 struct snd_soc_dai *dai)
346{
347 struct snd_soc_pcm_runtime *rtd = substream->private_data;
348 struct s3c_i2sv2_info *i2s = to_info(rtd->dai->cpu_dai);
349 int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
350 unsigned long irqs;
351 int ret = 0;
352
353 pr_debug("Entered %s\n", __func__);
354
355 switch (cmd) {
356 case SNDRV_PCM_TRIGGER_START:
357 /* On start, ensure that the FIFOs are cleared and reset. */
358
359 writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
360 i2s->regs + S3C2412_IISFIC);
361
362 /* clear again, just in case */
363 writel(0x0, i2s->regs + S3C2412_IISFIC);
364
365 case SNDRV_PCM_TRIGGER_RESUME:
366 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
367 if (!i2s->master) {
368 ret = s3c2412_snd_lrsync(i2s);
369 if (ret)
370 goto exit_err;
371 }
372
373 local_irq_save(irqs);
374
375 if (capture)
376 s3c2412_snd_rxctrl(i2s, 1);
377 else
378 s3c2412_snd_txctrl(i2s, 1);
379
380 local_irq_restore(irqs);
381 break;
382
383 case SNDRV_PCM_TRIGGER_STOP:
384 case SNDRV_PCM_TRIGGER_SUSPEND:
385 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
386 local_irq_save(irqs);
387
388 if (capture)
389 s3c2412_snd_rxctrl(i2s, 0);
390 else
391 s3c2412_snd_txctrl(i2s, 0);
392
393 local_irq_restore(irqs);
394 break;
395 default:
396 ret = -EINVAL;
397 break;
398 }
399
400exit_err:
401 return ret;
402}
403
404/*
405 * Set S3C2412 Clock dividers
406 */
407static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
408 int div_id, int div)
409{
410 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
411 u32 reg;
412
413 pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
414
415 switch (div_id) {
416 case S3C_I2SV2_DIV_BCLK:
417 reg = readl(i2s->regs + S3C2412_IISMOD);
418 reg &= ~S3C2412_IISMOD_BCLK_MASK;
419 writel(reg | div, i2s->regs + S3C2412_IISMOD);
420
421 pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
422 break;
423
424 case S3C_I2SV2_DIV_RCLK:
425 if (div > 3) {
426 /* convert value to bit field */
427
428 switch (div) {
429 case 256:
430 div = S3C2412_IISMOD_RCLK_256FS;
431 break;
432
433 case 384:
434 div = S3C2412_IISMOD_RCLK_384FS;
435 break;
436
437 case 512:
438 div = S3C2412_IISMOD_RCLK_512FS;
439 break;
440
441 case 768:
442 div = S3C2412_IISMOD_RCLK_768FS;
443 break;
444
445 default:
446 return -EINVAL;
447 }
448 }
449
450 reg = readl(i2s->regs + S3C2412_IISMOD);
451 reg &= ~S3C2412_IISMOD_RCLK_MASK;
452 writel(reg | div, i2s->regs + S3C2412_IISMOD);
453 pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
454 break;
455
456 case S3C_I2SV2_DIV_PRESCALER:
457 if (div >= 0) {
458 writel((div << 8) | S3C2412_IISPSR_PSREN,
459 i2s->regs + S3C2412_IISPSR);
460 } else {
461 writel(0x0, i2s->regs + S3C2412_IISPSR);
462 }
463 pr_debug("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
464 break;
465
466 default:
467 return -EINVAL;
468 }
469
470 return 0;
471}
472
473/* default table of all avaialable root fs divisors */
474static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 };
475
476int s3c2412_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
477 unsigned int *fstab,
478 unsigned int rate, struct clk *clk)
479{
480 unsigned long clkrate = clk_get_rate(clk);
481 unsigned int div;
482 unsigned int fsclk;
483 unsigned int actual;
484 unsigned int fs;
485 unsigned int fsdiv;
486 signed int deviation = 0;
487 unsigned int best_fs = 0;
488 unsigned int best_div = 0;
489 unsigned int best_rate = 0;
490 unsigned int best_deviation = INT_MAX;
491
492 if (fstab == NULL)
493 fstab = iis_fs_tab;
494
495 for (fs = 0; fs < ARRAY_SIZE(iis_fs_tab); fs++) {
496 fsdiv = iis_fs_tab[fs];
497
498 fsclk = clkrate / fsdiv;
499 div = fsclk / rate;
500
501 if ((fsclk % rate) > (rate / 2))
502 div++;
503
504 if (div <= 1)
505 continue;
506
507 actual = clkrate / (fsdiv * div);
508 deviation = actual - rate;
509
510 printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n",
511 fsdiv, div, actual, deviation);
512
513 deviation = abs(deviation);
514
515 if (deviation < best_deviation) {
516 best_fs = fsdiv;
517 best_div = div;
518 best_rate = actual;
519 best_deviation = deviation;
520 }
521
522 if (deviation == 0)
523 break;
524 }
525
526 printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n",
527 best_fs, best_div, best_rate);
528
529 info->fs_div = best_fs;
530 info->clk_div = best_div;
531
532 return 0;
533}
534EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate);
535
536int s3c_i2sv2_probe(struct platform_device *pdev,
537 struct snd_soc_dai *dai,
538 struct s3c_i2sv2_info *i2s,
539 unsigned long base)
540{
541 struct device *dev = &pdev->dev;
542
543 i2s->dev = dev;
544
545 /* record our i2s structure for later use in the callbacks */
546 dai->private_data = i2s;
547
548 i2s->regs = ioremap(base, 0x100);
549 if (i2s->regs == NULL) {
550 dev_err(dev, "cannot ioremap registers\n");
551 return -ENXIO;
552 }
553
554 i2s->iis_pclk = clk_get(dev, "iis");
555 if (i2s->iis_pclk == NULL) {
556 dev_err(dev, "failed to get iis_clock\n");
557 iounmap(i2s->regs);
558 return -ENOENT;
559 }
560
561 clk_enable(i2s->iis_pclk);
562
563 s3c2412_snd_txctrl(i2s, 0);
564 s3c2412_snd_rxctrl(i2s, 0);
565
566 return 0;
567}
568
569EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
570
571#ifdef CONFIG_PM
572static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
573{
574 struct s3c_i2sv2_info *i2s = to_info(dai);
575 u32 iismod;
576
577 if (dai->active) {
578 i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
579 i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
580 i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
581
582 /* some basic suspend checks */
583
584 iismod = readl(i2s->regs + S3C2412_IISMOD);
585
586 if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
587 pr_warning("%s: RXDMA active?\n", __func__);
588
589 if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
590 pr_warning("%s: TXDMA active?\n", __func__);
591
592 if (iismod & S3C2412_IISCON_IIS_ACTIVE)
593 pr_warning("%s: IIS active\n", __func__);
594 }
595
596 return 0;
597}
598
599static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
600{
601 struct s3c_i2sv2_info *i2s = to_info(dai);
602
603 pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n",
604 dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
605
606 if (dai->active) {
607 writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
608 writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
609 writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
610
611 writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
612 i2s->regs + S3C2412_IISFIC);
613
614 ndelay(250);
615 writel(0x0, i2s->regs + S3C2412_IISFIC);
616 }
617
618 return 0;
619}
620#else
621#define s3c2412_i2s_suspend NULL
622#define s3c2412_i2s_resume NULL
623#endif
624
625int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
626{
627 dai->ops.trigger = s3c2412_i2s_trigger;
628 dai->ops.hw_params = s3c2412_i2s_hw_params;
629 dai->ops.set_fmt = s3c2412_i2s_set_fmt;
630 dai->ops.set_clkdiv = s3c2412_i2s_set_clkdiv;
631
632 dai->suspend = s3c2412_i2s_suspend;
633 dai->resume = s3c2412_i2s_resume;
634
635 return snd_soc_register_dai(dai);
636}
637
638EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h
new file mode 100644
index 000000000000..f66854a77fb2
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.h
@@ -0,0 +1,90 @@
1/* sound/soc/s3c24xx/s3c-i2s-v2.h
2 *
3 * ALSA Soc Audio Layer - S3C_I2SV2 I2S driver
4 *
5 * Copyright (c) 2007 Simtec Electronics
6 * http://armlinux.simtec.co.uk/
7 * Ben Dooks <ben@simtec.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13*/
14
15/* This code is the core support for the I2S block found in a number of
16 * Samsung SoC devices which is unofficially named I2S-V2. Currently the
17 * S3C2412 and the S3C64XX series use this block to provide 1 or 2 I2S
18 * channels via configurable GPIO.
19 */
20
21#ifndef __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H
22#define __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H __FILE__
23
24#define S3C_I2SV2_DIV_BCLK (1)
25#define S3C_I2SV2_DIV_RCLK (2)
26#define S3C_I2SV2_DIV_PRESCALER (3)
27
28/**
29 * struct s3c_i2sv2_info - S3C I2S-V2 information
30 * @dev: The parent device passed to use from the probe.
31 * @regs: The pointer to the device registe block.
32 * @master: True if the I2S core is the I2S bit clock master.
33 * @dma_playback: DMA information for playback channel.
34 * @dma_capture: DMA information for capture channel.
35 * @suspend_iismod: PM save for the IISMOD register.
36 * @suspend_iiscon: PM save for the IISCON register.
37 * @suspend_iispsr: PM save for the IISPSR register.
38 *
39 * This is the private codec state for the hardware associated with an
40 * I2S channel such as the register mappings and clock sources.
41 */
42struct s3c_i2sv2_info {
43 struct device *dev;
44 void __iomem *regs;
45
46 struct clk *iis_pclk;
47 struct clk *iis_cclk;
48 struct clk *iis_clk;
49
50 unsigned char master;
51
52 struct s3c24xx_pcm_dma_params *dma_playback;
53 struct s3c24xx_pcm_dma_params *dma_capture;
54
55 u32 suspend_iismod;
56 u32 suspend_iiscon;
57 u32 suspend_iispsr;
58};
59
60struct s3c_i2sv2_rate_calc {
61 unsigned int clk_div; /* for prescaler */
62 unsigned int fs_div; /* for root frame clock */
63};
64
65extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
66 unsigned int *fstab,
67 unsigned int rate, struct clk *clk);
68
69/**
70 * s3c_i2sv2_probe - probe for i2s device helper
71 * @pdev: The platform device supplied to the original probe.
72 * @dai: The ASoC DAI structure supplied to the original probe.
73 * @i2s: Our local i2s structure to fill in.
74 * @base: The base address for the registers.
75 */
76extern int s3c_i2sv2_probe(struct platform_device *pdev,
77 struct snd_soc_dai *dai,
78 struct s3c_i2sv2_info *i2s,
79 unsigned long base);
80
81/**
82 * s3c_i2sv2_register_dai - register dai with soc core
83 * @dai: The snd_soc_dai structure to register
84 *
85 * Fill in any missing fields and then register the given dai with the
86 * soc core.
87 */
88extern int s3c_i2sv2_register_dai(struct snd_soc_dai *dai);
89
90#endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
index 382d7eee53ef..1ca3cdaa8213 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.c
+++ b/sound/soc/s3c24xx/s3c2412-i2s.c
@@ -22,6 +22,7 @@
22#include <linux/delay.h> 22#include <linux/delay.h>
23#include <linux/clk.h> 23#include <linux/clk.h>
24#include <linux/kernel.h> 24#include <linux/kernel.h>
25#include <linux/io.h>
25 26
26#include <sound/core.h> 27#include <sound/core.h>
27#include <sound/pcm.h> 28#include <sound/pcm.h>
@@ -30,26 +31,16 @@
30#include <sound/soc.h> 31#include <sound/soc.h>
31#include <mach/hardware.h> 32#include <mach/hardware.h>
32 33
33#include <linux/io.h> 34#include <plat/regs-s3c2412-iis.h>
34#include <asm/dma.h>
35
36#include <asm/plat-s3c24xx/regs-s3c2412-iis.h>
37 35
38#include <mach/regs-gpio.h> 36#include <plat/regs-gpio.h>
39#include <mach/audio.h> 37#include <plat/audio.h>
40#include <mach/dma.h> 38#include <mach/dma.h>
41 39
42#include "s3c24xx-pcm.h" 40#include "s3c24xx-pcm.h"
43#include "s3c2412-i2s.h" 41#include "s3c2412-i2s.h"
44 42
45#define S3C2412_I2S_DEBUG 0 43#define S3C2412_I2S_DEBUG 0
46#define S3C2412_I2S_DEBUG_CON 0
47
48#if S3C2412_I2S_DEBUG
49#define DBG(x...) printk(KERN_INFO x)
50#else
51#define DBG(x...) do { } while (0)
52#endif
53 44
54static struct s3c2410_dma_client s3c2412_dma_client_out = { 45static struct s3c2410_dma_client s3c2412_dma_client_out = {
55 .name = "I2S PCM Stereo out" 46 .name = "I2S PCM Stereo out"
@@ -73,431 +64,7 @@ static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_in = {
73 .dma_size = 4, 64 .dma_size = 4,
74}; 65};
75 66
76struct s3c2412_i2s_info { 67static struct s3c_i2sv2_info s3c2412_i2s;
77 struct device *dev;
78 void __iomem *regs;
79 struct clk *iis_clk;
80 struct clk *iis_pclk;
81 struct clk *iis_cclk;
82
83 u32 suspend_iismod;
84 u32 suspend_iiscon;
85 u32 suspend_iispsr;
86};
87
88static struct s3c2412_i2s_info s3c2412_i2s;
89
90#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
91
92#if S3C2412_I2S_DEBUG_CON
93static void dbg_showcon(const char *fn, u32 con)
94{
95 printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
96 bit_set(con, S3C2412_IISCON_LRINDEX),
97 bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
98 bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
99 bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
100 bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
101
102 printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
103 fn,
104 bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
105 bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
106 bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
107 bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
108 printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
109 bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
110 bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
111 bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
112}
113#else
114static inline void dbg_showcon(const char *fn, u32 con)
115{
116}
117#endif
118
119/* Turn on or off the transmission path. */
120static void s3c2412_snd_txctrl(int on)
121{
122 struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
123 void __iomem *regs = i2s->regs;
124 u32 fic, con, mod;
125
126 DBG("%s(%d)\n", __func__, on);
127
128 fic = readl(regs + S3C2412_IISFIC);
129 con = readl(regs + S3C2412_IISCON);
130 mod = readl(regs + S3C2412_IISMOD);
131
132 DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
133
134 if (on) {
135 con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
136 con &= ~S3C2412_IISCON_TXDMA_PAUSE;
137 con &= ~S3C2412_IISCON_TXCH_PAUSE;
138
139 switch (mod & S3C2412_IISMOD_MODE_MASK) {
140 case S3C2412_IISMOD_MODE_TXONLY:
141 case S3C2412_IISMOD_MODE_TXRX:
142 /* do nothing, we are in the right mode */
143 break;
144
145 case S3C2412_IISMOD_MODE_RXONLY:
146 mod &= ~S3C2412_IISMOD_MODE_MASK;
147 mod |= S3C2412_IISMOD_MODE_TXRX;
148 break;
149
150 default:
151 dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n");
152 }
153
154 writel(con, regs + S3C2412_IISCON);
155 writel(mod, regs + S3C2412_IISMOD);
156 } else {
157 /* Note, we do not have any indication that the FIFO problems
158 * tha the S3C2410/2440 had apply here, so we should be able
159 * to disable the DMA and TX without resetting the FIFOS.
160 */
161
162 con |= S3C2412_IISCON_TXDMA_PAUSE;
163 con |= S3C2412_IISCON_TXCH_PAUSE;
164 con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
165
166 switch (mod & S3C2412_IISMOD_MODE_MASK) {
167 case S3C2412_IISMOD_MODE_TXRX:
168 mod &= ~S3C2412_IISMOD_MODE_MASK;
169 mod |= S3C2412_IISMOD_MODE_RXONLY;
170 break;
171
172 case S3C2412_IISMOD_MODE_TXONLY:
173 mod &= ~S3C2412_IISMOD_MODE_MASK;
174 con &= ~S3C2412_IISCON_IIS_ACTIVE;
175 break;
176
177 default:
178 dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n");
179 }
180
181 writel(mod, regs + S3C2412_IISMOD);
182 writel(con, regs + S3C2412_IISCON);
183 }
184
185 fic = readl(regs + S3C2412_IISFIC);
186 dbg_showcon(__func__, con);
187 DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
188}
189
190static void s3c2412_snd_rxctrl(int on)
191{
192 struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
193 void __iomem *regs = i2s->regs;
194 u32 fic, con, mod;
195
196 DBG("%s(%d)\n", __func__, on);
197
198 fic = readl(regs + S3C2412_IISFIC);
199 con = readl(regs + S3C2412_IISCON);
200 mod = readl(regs + S3C2412_IISMOD);
201
202 DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
203
204 if (on) {
205 con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
206 con &= ~S3C2412_IISCON_RXDMA_PAUSE;
207 con &= ~S3C2412_IISCON_RXCH_PAUSE;
208
209 switch (mod & S3C2412_IISMOD_MODE_MASK) {
210 case S3C2412_IISMOD_MODE_TXRX:
211 case S3C2412_IISMOD_MODE_RXONLY:
212 /* do nothing, we are in the right mode */
213 break;
214
215 case S3C2412_IISMOD_MODE_TXONLY:
216 mod &= ~S3C2412_IISMOD_MODE_MASK;
217 mod |= S3C2412_IISMOD_MODE_TXRX;
218 break;
219
220 default:
221 dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
222 }
223
224 writel(mod, regs + S3C2412_IISMOD);
225 writel(con, regs + S3C2412_IISCON);
226 } else {
227 /* See txctrl notes on FIFOs. */
228
229 con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
230 con |= S3C2412_IISCON_RXDMA_PAUSE;
231 con |= S3C2412_IISCON_RXCH_PAUSE;
232
233 switch (mod & S3C2412_IISMOD_MODE_MASK) {
234 case S3C2412_IISMOD_MODE_RXONLY:
235 con &= ~S3C2412_IISCON_IIS_ACTIVE;
236 mod &= ~S3C2412_IISMOD_MODE_MASK;
237 break;
238
239 case S3C2412_IISMOD_MODE_TXRX:
240 mod &= ~S3C2412_IISMOD_MODE_MASK;
241 mod |= S3C2412_IISMOD_MODE_TXONLY;
242 break;
243
244 default:
245 dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
246 }
247
248 writel(con, regs + S3C2412_IISCON);
249 writel(mod, regs + S3C2412_IISMOD);
250 }
251
252 fic = readl(regs + S3C2412_IISFIC);
253 DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
254}
255
256
257/*
258 * Wait for the LR signal to allow synchronisation to the L/R clock
259 * from the codec. May only be needed for slave mode.
260 */
261static int s3c2412_snd_lrsync(void)
262{
263 u32 iiscon;
264 unsigned long timeout = jiffies + msecs_to_jiffies(5);
265
266 DBG("Entered %s\n", __func__);
267
268 while (1) {
269 iiscon = readl(s3c2412_i2s.regs + S3C2412_IISCON);
270 if (iiscon & S3C2412_IISCON_LRINDEX)
271 break;
272
273 if (timeout < jiffies) {
274 printk(KERN_ERR "%s: timeout\n", __func__);
275 return -ETIMEDOUT;
276 }
277 }
278
279 return 0;
280}
281
282/*
283 * Check whether CPU is the master or slave
284 */
285static inline int s3c2412_snd_is_clkmaster(void)
286{
287 u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
288
289 DBG("Entered %s\n", __func__);
290
291 iismod &= S3C2412_IISMOD_MASTER_MASK;
292 return !(iismod == S3C2412_IISMOD_SLAVE);
293}
294
295/*
296 * Set S3C2412 I2S DAI format
297 */
298static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
299 unsigned int fmt)
300{
301 u32 iismod;
302
303
304 DBG("Entered %s\n", __func__);
305
306 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
307 DBG("hw_params r: IISMOD: %x \n", iismod);
308
309 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
310 case SND_SOC_DAIFMT_CBM_CFM:
311 iismod &= ~S3C2412_IISMOD_MASTER_MASK;
312 iismod |= S3C2412_IISMOD_SLAVE;
313 break;
314 case SND_SOC_DAIFMT_CBS_CFS:
315 iismod &= ~S3C2412_IISMOD_MASTER_MASK;
316 iismod |= S3C2412_IISMOD_MASTER_INTERNAL;
317 break;
318 default:
319 DBG("unknwon master/slave format\n");
320 return -EINVAL;
321 }
322
323 iismod &= ~S3C2412_IISMOD_SDF_MASK;
324
325 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
326 case SND_SOC_DAIFMT_RIGHT_J:
327 iismod |= S3C2412_IISMOD_SDF_MSB;
328 break;
329 case SND_SOC_DAIFMT_LEFT_J:
330 iismod |= S3C2412_IISMOD_SDF_LSB;
331 break;
332 case SND_SOC_DAIFMT_I2S:
333 iismod |= S3C2412_IISMOD_SDF_IIS;
334 break;
335 default:
336 DBG("Unknown data format\n");
337 return -EINVAL;
338 }
339
340 writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD);
341 DBG("hw_params w: IISMOD: %x \n", iismod);
342 return 0;
343}
344
345static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
346 struct snd_pcm_hw_params *params,
347 struct snd_soc_dai *dai)
348{
349 struct snd_soc_pcm_runtime *rtd = substream->private_data;
350 u32 iismod;
351
352 DBG("Entered %s\n", __func__);
353
354 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
355 rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_out;
356 else
357 rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_in;
358
359 /* Working copies of register */
360 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
361 DBG("%s: r: IISMOD: %x\n", __func__, iismod);
362
363 switch (params_format(params)) {
364 case SNDRV_PCM_FORMAT_S8:
365 iismod |= S3C2412_IISMOD_8BIT;
366 break;
367 case SNDRV_PCM_FORMAT_S16_LE:
368 iismod &= ~S3C2412_IISMOD_8BIT;
369 break;
370 }
371
372 writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD);
373 DBG("%s: w: IISMOD: %x\n", __func__, iismod);
374 return 0;
375}
376
377static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
378 struct snd_soc_dai *dai)
379{
380 int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
381 unsigned long irqs;
382 int ret = 0;
383
384 DBG("Entered %s\n", __func__);
385
386 switch (cmd) {
387 case SNDRV_PCM_TRIGGER_START:
388 /* On start, ensure that the FIFOs are cleared and reset. */
389
390 writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
391 s3c2412_i2s.regs + S3C2412_IISFIC);
392
393 /* clear again, just in case */
394 writel(0x0, s3c2412_i2s.regs + S3C2412_IISFIC);
395
396 case SNDRV_PCM_TRIGGER_RESUME:
397 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
398 if (!s3c2412_snd_is_clkmaster()) {
399 ret = s3c2412_snd_lrsync();
400 if (ret)
401 goto exit_err;
402 }
403
404 local_irq_save(irqs);
405
406 if (capture)
407 s3c2412_snd_rxctrl(1);
408 else
409 s3c2412_snd_txctrl(1);
410
411 local_irq_restore(irqs);
412 break;
413
414 case SNDRV_PCM_TRIGGER_STOP:
415 case SNDRV_PCM_TRIGGER_SUSPEND:
416 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
417 local_irq_save(irqs);
418
419 if (capture)
420 s3c2412_snd_rxctrl(0);
421 else
422 s3c2412_snd_txctrl(0);
423
424 local_irq_restore(irqs);
425 break;
426 default:
427 ret = -EINVAL;
428 break;
429 }
430
431exit_err:
432 return ret;
433}
434
435/* default table of all avaialable root fs divisors */
436static unsigned int s3c2412_iis_fs[] = { 256, 512, 384, 768, 0 };
437
438int s3c2412_iis_calc_rate(struct s3c2412_rate_calc *info,
439 unsigned int *fstab,
440 unsigned int rate, struct clk *clk)
441{
442 unsigned long clkrate = clk_get_rate(clk);
443 unsigned int div;
444 unsigned int fsclk;
445 unsigned int actual;
446 unsigned int fs;
447 unsigned int fsdiv;
448 signed int deviation = 0;
449 unsigned int best_fs = 0;
450 unsigned int best_div = 0;
451 unsigned int best_rate = 0;
452 unsigned int best_deviation = INT_MAX;
453
454
455 if (fstab == NULL)
456 fstab = s3c2412_iis_fs;
457
458 for (fs = 0;; fs++) {
459 fsdiv = s3c2412_iis_fs[fs];
460
461 if (fsdiv == 0)
462 break;
463
464 fsclk = clkrate / fsdiv;
465 div = fsclk / rate;
466
467 if ((fsclk % rate) > (rate / 2))
468 div++;
469
470 if (div <= 1)
471 continue;
472
473 actual = clkrate / (fsdiv * div);
474 deviation = actual - rate;
475
476 printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n",
477 fsdiv, div, actual, deviation);
478
479 deviation = abs(deviation);
480
481 if (deviation < best_deviation) {
482 best_fs = fsdiv;
483 best_div = div;
484 best_rate = actual;
485 best_deviation = deviation;
486 }
487
488 if (deviation == 0)
489 break;
490 }
491
492 printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n",
493 best_fs, best_div, best_rate);
494
495 info->fs_div = best_fs;
496 info->clk_div = best_div;
497
498 return 0;
499}
500EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate);
501 68
502/* 69/*
503 * Set S3C2412 Clock source 70 * Set S3C2412 Clock source
@@ -507,15 +74,17 @@ static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
507{ 74{
508 u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); 75 u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
509 76
510 DBG("%s(%p, %d, %u, %d)\n", __func__, cpu_dai, clk_id, 77 pr_debug("%s(%p, %d, %u, %d)\n", __func__, cpu_dai, clk_id,
511 freq, dir); 78 freq, dir);
512 79
513 switch (clk_id) { 80 switch (clk_id) {
514 case S3C2412_CLKSRC_PCLK: 81 case S3C2412_CLKSRC_PCLK:
82 s3c2412_i2s.master = 1;
515 iismod &= ~S3C2412_IISMOD_MASTER_MASK; 83 iismod &= ~S3C2412_IISMOD_MASTER_MASK;
516 iismod |= S3C2412_IISMOD_MASTER_INTERNAL; 84 iismod |= S3C2412_IISMOD_MASTER_INTERNAL;
517 break; 85 break;
518 case S3C2412_CLKSRC_I2SCLK: 86 case S3C2412_CLKSRC_I2SCLK:
87 s3c2412_i2s.master = 0;
519 iismod &= ~S3C2412_IISMOD_MASTER_MASK; 88 iismod &= ~S3C2412_IISMOD_MASTER_MASK;
520 iismod |= S3C2412_IISMOD_MASTER_EXTERNAL; 89 iismod |= S3C2412_IISMOD_MASTER_EXTERNAL;
521 break; 90 break;
@@ -527,74 +96,6 @@ static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
527 return 0; 96 return 0;
528} 97}
529 98
530/*
531 * Set S3C2412 Clock dividers
532 */
533static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
534 int div_id, int div)
535{
536 struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
537 u32 reg;
538
539 DBG("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
540
541 switch (div_id) {
542 case S3C2412_DIV_BCLK:
543 reg = readl(i2s->regs + S3C2412_IISMOD);
544 reg &= ~S3C2412_IISMOD_BCLK_MASK;
545 writel(reg | div, i2s->regs + S3C2412_IISMOD);
546
547 DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
548 break;
549
550 case S3C2412_DIV_RCLK:
551 if (div > 3) {
552 /* convert value to bit field */
553
554 switch (div) {
555 case 256:
556 div = S3C2412_IISMOD_RCLK_256FS;
557 break;
558
559 case 384:
560 div = S3C2412_IISMOD_RCLK_384FS;
561 break;
562
563 case 512:
564 div = S3C2412_IISMOD_RCLK_512FS;
565 break;
566
567 case 768:
568 div = S3C2412_IISMOD_RCLK_768FS;
569 break;
570
571 default:
572 return -EINVAL;
573 }
574 }
575
576 reg = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
577 reg &= ~S3C2412_IISMOD_RCLK_MASK;
578 writel(reg | div, i2s->regs + S3C2412_IISMOD);
579 DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
580 break;
581
582 case S3C2412_DIV_PRESCALER:
583 if (div >= 0) {
584 writel((div << 8) | S3C2412_IISPSR_PSREN,
585 i2s->regs + S3C2412_IISPSR);
586 } else {
587 writel(0x0, i2s->regs + S3C2412_IISPSR);
588 }
589 DBG("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
590 break;
591
592 default:
593 return -EINVAL;
594 }
595
596 return 0;
597}
598 99
599struct clk *s3c2412_get_iisclk(void) 100struct clk *s3c2412_get_iisclk(void)
600{ 101{
@@ -606,34 +107,30 @@ EXPORT_SYMBOL_GPL(s3c2412_get_iisclk);
606static int s3c2412_i2s_probe(struct platform_device *pdev, 107static int s3c2412_i2s_probe(struct platform_device *pdev,
607 struct snd_soc_dai *dai) 108 struct snd_soc_dai *dai)
608{ 109{
609 DBG("Entered %s\n", __func__); 110 int ret;
610 111
611 s3c2412_i2s.dev = &pdev->dev; 112 pr_debug("Entered %s\n", __func__);
612 113
613 s3c2412_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100); 114 ret = s3c_i2sv2_probe(pdev, dai, &s3c2412_i2s, S3C2410_PA_IIS);
614 if (s3c2412_i2s.regs == NULL) 115 if (ret)
615 return -ENXIO; 116 return ret;
616 117
617 s3c2412_i2s.iis_pclk = clk_get(&pdev->dev, "iis"); 118 s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in;
618 if (s3c2412_i2s.iis_pclk == NULL) { 119 s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out;
619 DBG("failed to get iis_clock\n");
620 iounmap(s3c2412_i2s.regs);
621 return -ENODEV;
622 }
623 120
624 s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk"); 121 s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk");
625 if (s3c2412_i2s.iis_cclk == NULL) { 122 if (s3c2412_i2s.iis_cclk == NULL) {
626 DBG("failed to get i2sclk clock\n"); 123 pr_debug("failed to get i2sclk clock\n");
627 iounmap(s3c2412_i2s.regs); 124 iounmap(s3c2412_i2s.regs);
628 return -ENODEV; 125 return -ENODEV;
629 } 126 }
630 127
631 clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll")); 128 /* Set MPLL as the source for IIS CLK */
632 129
633 clk_enable(s3c2412_i2s.iis_pclk); 130 clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll"));
634 clk_enable(s3c2412_i2s.iis_cclk); 131 clk_enable(s3c2412_i2s.iis_cclk);
635 132
636 s3c2412_i2s.iis_clk = s3c2412_i2s.iis_pclk; 133 s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk;
637 134
638 /* Configure the I2S pins in correct mode */ 135 /* Configure the I2S pins in correct mode */
639 s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK); 136 s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);
@@ -642,66 +139,8 @@ static int s3c2412_i2s_probe(struct platform_device *pdev,
642 s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI); 139 s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
643 s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO); 140 s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
644 141
645 s3c2412_snd_txctrl(0);
646 s3c2412_snd_rxctrl(0);
647
648 return 0;
649}
650
651#ifdef CONFIG_PM
652static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
653{
654 struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
655 u32 iismod;
656
657 if (dai->active) {
658 i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
659 i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
660 i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
661
662 /* some basic suspend checks */
663
664 iismod = readl(i2s->regs + S3C2412_IISMOD);
665
666 if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
667 pr_warning("%s: RXDMA active?\n", __func__);
668
669 if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
670 pr_warning("%s: TXDMA active?\n", __func__);
671
672 if (iismod & S3C2412_IISCON_IIS_ACTIVE)
673 pr_warning("%s: IIS active\n", __func__);
674 }
675
676 return 0;
677}
678
679static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
680{
681 struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
682
683 pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n",
684 dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
685
686 if (dai->active) {
687 writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
688 writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
689 writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
690
691 writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
692 i2s->regs + S3C2412_IISFIC);
693
694 ndelay(250);
695 writel(0x0, i2s->regs + S3C2412_IISFIC);
696
697 }
698
699 return 0; 142 return 0;
700} 143}
701#else
702#define s3c2412_i2s_suspend NULL
703#define s3c2412_i2s_resume NULL
704#endif /* CONFIG_PM */
705 144
706#define S3C2412_I2S_RATES \ 145#define S3C2412_I2S_RATES \
707 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ 146 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
@@ -709,19 +148,13 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
709 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) 148 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
710 149
711static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = { 150static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = {
712 .trigger = s3c2412_i2s_trigger,
713 .hw_params = s3c2412_i2s_hw_params,
714 .set_fmt = s3c2412_i2s_set_fmt,
715 .set_clkdiv = s3c2412_i2s_set_clkdiv,
716 .set_sysclk = s3c2412_i2s_set_sysclk, 151 .set_sysclk = s3c2412_i2s_set_sysclk,
717}; 152};
718 153
719struct snd_soc_dai s3c2412_i2s_dai = { 154struct snd_soc_dai s3c2412_i2s_dai = {
720 .name = "s3c2412-i2s", 155 .name = "s3c2412-i2s",
721 .id = 0, 156 .id = 0,
722 .probe = s3c2412_i2s_probe, 157 .probe = s3c2412_i2s_probe,
723 .suspend = s3c2412_i2s_suspend,
724 .resume = s3c2412_i2s_resume,
725 .playback = { 158 .playback = {
726 .channels_min = 2, 159 .channels_min = 2,
727 .channels_max = 2, 160 .channels_max = 2,
@@ -740,7 +173,7 @@ EXPORT_SYMBOL_GPL(s3c2412_i2s_dai);
740 173
741static int __init s3c2412_i2s_init(void) 174static int __init s3c2412_i2s_init(void)
742{ 175{
743 return snd_soc_register_dai(&s3c2412_i2s_dai); 176 return s3c_i2sv2_register_dai(&s3c2412_i2s_dai);
744} 177}
745module_init(s3c2412_i2s_init); 178module_init(s3c2412_i2s_init);
746 179
@@ -750,7 +183,6 @@ static void __exit s3c2412_i2s_exit(void)
750} 183}
751module_exit(s3c2412_i2s_exit); 184module_exit(s3c2412_i2s_exit);
752 185
753
754/* Module information */ 186/* Module information */
755MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); 187MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
756MODULE_DESCRIPTION("S3C2412 I2S SoC Interface"); 188MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/s3c24xx/s3c2412-i2s.h
index aac08a25e541..92848e54be16 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.h
+++ b/sound/soc/s3c24xx/s3c2412-i2s.h
@@ -15,9 +15,11 @@
15#ifndef __SND_SOC_S3C24XX_S3C2412_I2S_H 15#ifndef __SND_SOC_S3C24XX_S3C2412_I2S_H
16#define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__ 16#define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__
17 17
18#define S3C2412_DIV_BCLK (1) 18#include "s3c-i2s-v2.h"
19#define S3C2412_DIV_RCLK (2) 19
20#define S3C2412_DIV_PRESCALER (3) 20#define S3C2412_DIV_BCLK S3C_I2SV2_DIV_BCLK
21#define S3C2412_DIV_RCLK S3C_I2SV2_DIV_RCLK
22#define S3C2412_DIV_PRESCALER S3C_I2SV2_DIV_PRESCALER
21 23
22#define S3C2412_CLKSRC_PCLK (0) 24#define S3C2412_CLKSRC_PCLK (0)
23#define S3C2412_CLKSRC_I2SCLK (1) 25#define S3C2412_CLKSRC_I2SCLK (1)
@@ -26,13 +28,4 @@ extern struct clk *s3c2412_get_iisclk(void);
26 28
27extern struct snd_soc_dai s3c2412_i2s_dai; 29extern struct snd_soc_dai s3c2412_i2s_dai;
28 30
29struct s3c2412_rate_calc {
30 unsigned int clk_div; /* for prescaler */
31 unsigned int fs_div; /* for root frame clock */
32};
33
34extern int s3c2412_iis_calc_rate(struct s3c2412_rate_calc *info,
35 unsigned int *fstab,
36 unsigned int rate, struct clk *clk);
37
38#endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */ 31#endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c
index 83ea623234e7..3698f707c44d 100644
--- a/sound/soc/s3c24xx/s3c2443-ac97.c
+++ b/sound/soc/s3c24xx/s3c2443-ac97.c
@@ -31,7 +31,7 @@
31#include <plat/regs-ac97.h> 31#include <plat/regs-ac97.h>
32#include <mach/regs-gpio.h> 32#include <mach/regs-gpio.h>
33#include <mach/regs-clock.h> 33#include <mach/regs-clock.h>
34#include <mach/audio.h> 34#include <plat/audio.h>
35#include <asm/dma.h> 35#include <asm/dma.h>
36#include <mach/dma.h> 36#include <mach/dma.h>
37 37
@@ -360,6 +360,11 @@ static struct snd_soc_dai_ops s3c2443_ac97_dai_ops = {
360 .trigger = s3c2443_ac97_trigger, 360 .trigger = s3c2443_ac97_trigger,
361}; 361};
362 362
363static struct snd_soc_dai_ops s3c2443_ac97_mic_dai_ops = {
364 .hw_params = s3c2443_ac97_hw_mic_params,
365 .trigger = s3c2443_ac97_mic_trigger,
366};
367
363struct snd_soc_dai s3c2443_ac97_dai[] = { 368struct snd_soc_dai s3c2443_ac97_dai[] = {
364{ 369{
365 .name = "s3c2443-ac97", 370 .name = "s3c2443-ac97",
@@ -391,7 +396,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = {
391 .channels_max = 1, 396 .channels_max = 1,
392 .rates = s3c2443_AC97_RATES, 397 .rates = s3c2443_AC97_RATES,
393 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 398 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
394 .ops = &s3c2443_ac97_dai_ops, 399 .ops = &s3c2443_ac97_mic_dai_ops,
395}, 400},
396}; 401};
397EXPORT_SYMBOL_GPL(s3c2443_ac97_dai); 402EXPORT_SYMBOL_GPL(s3c2443_ac97_dai);
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
index 4473fb584c4c..cc066964dad6 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.c
@@ -30,22 +30,15 @@
30#include <mach/hardware.h> 30#include <mach/hardware.h>
31#include <mach/regs-gpio.h> 31#include <mach/regs-gpio.h>
32#include <mach/regs-clock.h> 32#include <mach/regs-clock.h>
33#include <mach/audio.h> 33#include <plat/audio.h>
34#include <asm/dma.h> 34#include <asm/dma.h>
35#include <mach/dma.h> 35#include <mach/dma.h>
36 36
37#include <asm/plat-s3c24xx/regs-iis.h> 37#include <plat/regs-iis.h>
38 38
39#include "s3c24xx-pcm.h" 39#include "s3c24xx-pcm.h"
40#include "s3c24xx-i2s.h" 40#include "s3c24xx-i2s.h"
41 41
42#define S3C24XX_I2S_DEBUG 0
43#if S3C24XX_I2S_DEBUG
44#define DBG(x...) printk(KERN_DEBUG "s3c24xx-i2s: " x)
45#else
46#define DBG(x...)
47#endif
48
49static struct s3c2410_dma_client s3c24xx_dma_client_out = { 42static struct s3c2410_dma_client s3c24xx_dma_client_out = {
50 .name = "I2S PCM Stereo out" 43 .name = "I2S PCM Stereo out"
51}; 44};
@@ -84,13 +77,13 @@ static void s3c24xx_snd_txctrl(int on)
84 u32 iiscon; 77 u32 iiscon;
85 u32 iismod; 78 u32 iismod;
86 79
87 DBG("Entered %s\n", __func__); 80 pr_debug("Entered %s\n", __func__);
88 81
89 iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); 82 iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
90 iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); 83 iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
91 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); 84 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
92 85
93 DBG("r: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon); 86 pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
94 87
95 if (on) { 88 if (on) {
96 iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE; 89 iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE;
@@ -120,7 +113,7 @@ static void s3c24xx_snd_txctrl(int on)
120 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); 113 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
121 } 114 }
122 115
123 DBG("w: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon); 116 pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
124} 117}
125 118
126static void s3c24xx_snd_rxctrl(int on) 119static void s3c24xx_snd_rxctrl(int on)
@@ -129,13 +122,13 @@ static void s3c24xx_snd_rxctrl(int on)
129 u32 iiscon; 122 u32 iiscon;
130 u32 iismod; 123 u32 iismod;
131 124
132 DBG("Entered %s\n", __func__); 125 pr_debug("Entered %s\n", __func__);
133 126
134 iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); 127 iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
135 iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); 128 iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
136 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); 129 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
137 130
138 DBG("r: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon); 131 pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
139 132
140 if (on) { 133 if (on) {
141 iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE; 134 iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE;
@@ -165,7 +158,7 @@ static void s3c24xx_snd_rxctrl(int on)
165 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); 158 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
166 } 159 }
167 160
168 DBG("w: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon); 161 pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
169} 162}
170 163
171/* 164/*
@@ -177,7 +170,7 @@ static int s3c24xx_snd_lrsync(void)
177 u32 iiscon; 170 u32 iiscon;
178 int timeout = 50; /* 5ms */ 171 int timeout = 50; /* 5ms */
179 172
180 DBG("Entered %s\n", __func__); 173 pr_debug("Entered %s\n", __func__);
181 174
182 while (1) { 175 while (1) {
183 iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); 176 iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
@@ -197,7 +190,7 @@ static int s3c24xx_snd_lrsync(void)
197 */ 190 */
198static inline int s3c24xx_snd_is_clkmaster(void) 191static inline int s3c24xx_snd_is_clkmaster(void)
199{ 192{
200 DBG("Entered %s\n", __func__); 193 pr_debug("Entered %s\n", __func__);
201 194
202 return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1; 195 return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1;
203} 196}
@@ -210,10 +203,10 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
210{ 203{
211 u32 iismod; 204 u32 iismod;
212 205
213 DBG("Entered %s\n", __func__); 206 pr_debug("Entered %s\n", __func__);
214 207
215 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); 208 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
216 DBG("hw_params r: IISMOD: %lx \n", iismod); 209 pr_debug("hw_params r: IISMOD: %x \n", iismod);
217 210
218 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 211 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
219 case SND_SOC_DAIFMT_CBM_CFM: 212 case SND_SOC_DAIFMT_CBM_CFM:
@@ -238,7 +231,7 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
238 } 231 }
239 232
240 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); 233 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
241 DBG("hw_params w: IISMOD: %lx \n", iismod); 234 pr_debug("hw_params w: IISMOD: %x \n", iismod);
242 return 0; 235 return 0;
243} 236}
244 237
@@ -249,7 +242,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
249 struct snd_soc_pcm_runtime *rtd = substream->private_data; 242 struct snd_soc_pcm_runtime *rtd = substream->private_data;
250 u32 iismod; 243 u32 iismod;
251 244
252 DBG("Entered %s\n", __func__); 245 pr_debug("Entered %s\n", __func__);
253 246
254 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 247 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
255 rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out; 248 rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out;
@@ -258,7 +251,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
258 251
259 /* Working copies of register */ 252 /* Working copies of register */
260 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); 253 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
261 DBG("hw_params r: IISMOD: %lx\n", iismod); 254 pr_debug("hw_params r: IISMOD: %x\n", iismod);
262 255
263 switch (params_format(params)) { 256 switch (params_format(params)) {
264 case SNDRV_PCM_FORMAT_S8: 257 case SNDRV_PCM_FORMAT_S8:
@@ -276,7 +269,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
276 } 269 }
277 270
278 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); 271 writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
279 DBG("hw_params w: IISMOD: %lx\n", iismod); 272 pr_debug("hw_params w: IISMOD: %x\n", iismod);
280 return 0; 273 return 0;
281} 274}
282 275
@@ -285,7 +278,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
285{ 278{
286 int ret = 0; 279 int ret = 0;
287 280
288 DBG("Entered %s\n", __func__); 281 pr_debug("Entered %s\n", __func__);
289 282
290 switch (cmd) { 283 switch (cmd) {
291 case SNDRV_PCM_TRIGGER_START: 284 case SNDRV_PCM_TRIGGER_START:
@@ -327,7 +320,7 @@ static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
327{ 320{
328 u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); 321 u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
329 322
330 DBG("Entered %s\n", __func__); 323 pr_debug("Entered %s\n", __func__);
331 324
332 iismod &= ~S3C2440_IISMOD_MPLL; 325 iismod &= ~S3C2440_IISMOD_MPLL;
333 326
@@ -353,7 +346,7 @@ static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
353{ 346{
354 u32 reg; 347 u32 reg;
355 348
356 DBG("Entered %s\n", __func__); 349 pr_debug("Entered %s\n", __func__);
357 350
358 switch (div_id) { 351 switch (div_id) {
359 case S3C24XX_DIV_BCLK: 352 case S3C24XX_DIV_BCLK:
@@ -389,7 +382,7 @@ EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
389static int s3c24xx_i2s_probe(struct platform_device *pdev, 382static int s3c24xx_i2s_probe(struct platform_device *pdev,
390 struct snd_soc_dai *dai) 383 struct snd_soc_dai *dai)
391{ 384{
392 DBG("Entered %s\n", __func__); 385 pr_debug("Entered %s\n", __func__);
393 386
394 s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100); 387 s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100);
395 if (s3c24xx_i2s.regs == NULL) 388 if (s3c24xx_i2s.regs == NULL)
@@ -397,7 +390,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev,
397 390
398 s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis"); 391 s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis");
399 if (s3c24xx_i2s.iis_clk == NULL) { 392 if (s3c24xx_i2s.iis_clk == NULL) {
400 DBG("failed to get iis_clock\n"); 393 pr_err("failed to get iis_clock\n");
401 iounmap(s3c24xx_i2s.regs); 394 iounmap(s3c24xx_i2s.regs);
402 return -ENODEV; 395 return -ENODEV;
403 } 396 }
@@ -421,7 +414,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev,
421#ifdef CONFIG_PM 414#ifdef CONFIG_PM
422static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) 415static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
423{ 416{
424 DBG("Entered %s\n", __func__); 417 pr_debug("Entered %s\n", __func__);
425 418
426 s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); 419 s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
427 s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); 420 s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
@@ -435,7 +428,7 @@ static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
435 428
436static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) 429static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
437{ 430{
438 DBG("Entered %s\n", __func__); 431 pr_debug("Entered %s\n", __func__);
439 clk_enable(s3c24xx_i2s.iis_clk); 432 clk_enable(s3c24xx_i2s.iis_clk);
440 433
441 writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); 434 writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c
index ba1ae09dfaed..a9d68fa2b34a 100644
--- a/sound/soc/s3c24xx/s3c24xx-pcm.c
+++ b/sound/soc/s3c24xx/s3c24xx-pcm.c
@@ -29,17 +29,10 @@
29#include <asm/dma.h> 29#include <asm/dma.h>
30#include <mach/hardware.h> 30#include <mach/hardware.h>
31#include <mach/dma.h> 31#include <mach/dma.h>
32#include <mach/audio.h> 32#include <plat/audio.h>
33 33
34#include "s3c24xx-pcm.h" 34#include "s3c24xx-pcm.h"
35 35
36#define S3C24XX_PCM_DEBUG 0
37#if S3C24XX_PCM_DEBUG
38#define DBG(x...) printk(KERN_DEBUG "s3c24xx-pcm: " x)
39#else
40#define DBG(x...)
41#endif
42
43static const struct snd_pcm_hardware s3c24xx_pcm_hardware = { 36static const struct snd_pcm_hardware s3c24xx_pcm_hardware = {
44 .info = SNDRV_PCM_INFO_INTERLEAVED | 37 .info = SNDRV_PCM_INFO_INTERLEAVED |
45 SNDRV_PCM_INFO_BLOCK_TRANSFER | 38 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -84,16 +77,16 @@ static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream)
84 dma_addr_t pos = prtd->dma_pos; 77 dma_addr_t pos = prtd->dma_pos;
85 int ret; 78 int ret;
86 79
87 DBG("Entered %s\n", __func__); 80 pr_debug("Entered %s\n", __func__);
88 81
89 while (prtd->dma_loaded < prtd->dma_limit) { 82 while (prtd->dma_loaded < prtd->dma_limit) {
90 unsigned long len = prtd->dma_period; 83 unsigned long len = prtd->dma_period;
91 84
92 DBG("dma_loaded: %d\n", prtd->dma_loaded); 85 pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
93 86
94 if ((pos + len) > prtd->dma_end) { 87 if ((pos + len) > prtd->dma_end) {
95 len = prtd->dma_end - pos; 88 len = prtd->dma_end - pos;
96 DBG(KERN_DEBUG "%s: corrected dma len %ld\n", 89 pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n",
97 __func__, len); 90 __func__, len);
98 } 91 }
99 92
@@ -119,7 +112,7 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel,
119 struct snd_pcm_substream *substream = dev_id; 112 struct snd_pcm_substream *substream = dev_id;
120 struct s3c24xx_runtime_data *prtd; 113 struct s3c24xx_runtime_data *prtd;
121 114
122 DBG("Entered %s\n", __func__); 115 pr_debug("Entered %s\n", __func__);
123 116
124 if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) 117 if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR)
125 return; 118 return;
@@ -148,7 +141,7 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream,
148 unsigned long totbytes = params_buffer_bytes(params); 141 unsigned long totbytes = params_buffer_bytes(params);
149 int ret = 0; 142 int ret = 0;
150 143
151 DBG("Entered %s\n", __func__); 144 pr_debug("Entered %s\n", __func__);
152 145
153 /* return if this is a bufferless transfer e.g. 146 /* return if this is a bufferless transfer e.g.
154 * codec <--> BT codec or GSM modem -- lg FIXME */ 147 * codec <--> BT codec or GSM modem -- lg FIXME */
@@ -161,14 +154,14 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream,
161 /* prepare DMA */ 154 /* prepare DMA */
162 prtd->params = dma; 155 prtd->params = dma;
163 156
164 DBG("params %p, client %p, channel %d\n", prtd->params, 157 pr_debug("params %p, client %p, channel %d\n", prtd->params,
165 prtd->params->client, prtd->params->channel); 158 prtd->params->client, prtd->params->channel);
166 159
167 ret = s3c2410_dma_request(prtd->params->channel, 160 ret = s3c2410_dma_request(prtd->params->channel,
168 prtd->params->client, NULL); 161 prtd->params->client, NULL);
169 162
170 if (ret < 0) { 163 if (ret < 0) {
171 DBG(KERN_ERR "failed to get dma channel\n"); 164 printk(KERN_ERR "failed to get dma channel\n");
172 return ret; 165 return ret;
173 } 166 }
174 } 167 }
@@ -196,7 +189,7 @@ static int s3c24xx_pcm_hw_free(struct snd_pcm_substream *substream)
196{ 189{
197 struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; 190 struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
198 191
199 DBG("Entered %s\n", __func__); 192 pr_debug("Entered %s\n", __func__);
200 193
201 /* TODO - do we need to ensure DMA flushed */ 194 /* TODO - do we need to ensure DMA flushed */
202 snd_pcm_set_runtime_buffer(substream, NULL); 195 snd_pcm_set_runtime_buffer(substream, NULL);
@@ -214,7 +207,7 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream)
214 struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; 207 struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
215 int ret = 0; 208 int ret = 0;
216 209
217 DBG("Entered %s\n", __func__); 210 pr_debug("Entered %s\n", __func__);
218 211
219 /* return if this is a bufferless transfer e.g. 212 /* return if this is a bufferless transfer e.g.
220 * codec <--> BT codec or GSM modem -- lg FIXME */ 213 * codec <--> BT codec or GSM modem -- lg FIXME */
@@ -259,7 +252,7 @@ static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
259 struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; 252 struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
260 int ret = 0; 253 int ret = 0;
261 254
262 DBG("Entered %s\n", __func__); 255 pr_debug("Entered %s\n", __func__);
263 256
264 spin_lock(&prtd->lock); 257 spin_lock(&prtd->lock);
265 258
@@ -297,7 +290,7 @@ s3c24xx_pcm_pointer(struct snd_pcm_substream *substream)
297 unsigned long res; 290 unsigned long res;
298 dma_addr_t src, dst; 291 dma_addr_t src, dst;
299 292
300 DBG("Entered %s\n", __func__); 293 pr_debug("Entered %s\n", __func__);
301 294
302 spin_lock(&prtd->lock); 295 spin_lock(&prtd->lock);
303 s3c2410_dma_getposition(prtd->params->channel, &src, &dst); 296 s3c2410_dma_getposition(prtd->params->channel, &src, &dst);
@@ -309,7 +302,7 @@ s3c24xx_pcm_pointer(struct snd_pcm_substream *substream)
309 302
310 spin_unlock(&prtd->lock); 303 spin_unlock(&prtd->lock);
311 304
312 DBG("Pointer %x %x\n", src, dst); 305 pr_debug("Pointer %x %x\n", src, dst);
313 306
314 /* we seem to be getting the odd error from the pcm library due 307 /* we seem to be getting the odd error from the pcm library due
315 * to out-of-bounds pointers. this is maybe due to the dma engine 308 * to out-of-bounds pointers. this is maybe due to the dma engine
@@ -330,7 +323,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream)
330 struct snd_pcm_runtime *runtime = substream->runtime; 323 struct snd_pcm_runtime *runtime = substream->runtime;
331 struct s3c24xx_runtime_data *prtd; 324 struct s3c24xx_runtime_data *prtd;
332 325
333 DBG("Entered %s\n", __func__); 326 pr_debug("Entered %s\n", __func__);
334 327
335 snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware); 328 snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware);
336 329
@@ -349,10 +342,10 @@ static int s3c24xx_pcm_close(struct snd_pcm_substream *substream)
349 struct snd_pcm_runtime *runtime = substream->runtime; 342 struct snd_pcm_runtime *runtime = substream->runtime;
350 struct s3c24xx_runtime_data *prtd = runtime->private_data; 343 struct s3c24xx_runtime_data *prtd = runtime->private_data;
351 344
352 DBG("Entered %s\n", __func__); 345 pr_debug("Entered %s\n", __func__);
353 346
354 if (!prtd) 347 if (!prtd)
355 DBG("s3c24xx_pcm_close called with prtd == NULL\n"); 348 pr_debug("s3c24xx_pcm_close called with prtd == NULL\n");
356 349
357 kfree(prtd); 350 kfree(prtd);
358 351
@@ -364,7 +357,7 @@ static int s3c24xx_pcm_mmap(struct snd_pcm_substream *substream,
364{ 357{
365 struct snd_pcm_runtime *runtime = substream->runtime; 358 struct snd_pcm_runtime *runtime = substream->runtime;
366 359
367 DBG("Entered %s\n", __func__); 360 pr_debug("Entered %s\n", __func__);
368 361
369 return dma_mmap_writecombine(substream->pcm->card->dev, vma, 362 return dma_mmap_writecombine(substream->pcm->card->dev, vma,
370 runtime->dma_area, 363 runtime->dma_area,
@@ -390,7 +383,7 @@ static int s3c24xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
390 struct snd_dma_buffer *buf = &substream->dma_buffer; 383 struct snd_dma_buffer *buf = &substream->dma_buffer;
391 size_t size = s3c24xx_pcm_hardware.buffer_bytes_max; 384 size_t size = s3c24xx_pcm_hardware.buffer_bytes_max;
392 385
393 DBG("Entered %s\n", __func__); 386 pr_debug("Entered %s\n", __func__);
394 387
395 buf->dev.type = SNDRV_DMA_TYPE_DEV; 388 buf->dev.type = SNDRV_DMA_TYPE_DEV;
396 buf->dev.dev = pcm->card->dev; 389 buf->dev.dev = pcm->card->dev;
@@ -409,7 +402,7 @@ static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
409 struct snd_dma_buffer *buf; 402 struct snd_dma_buffer *buf;
410 int stream; 403 int stream;
411 404
412 DBG("Entered %s\n", __func__); 405 pr_debug("Entered %s\n", __func__);
413 406
414 for (stream = 0; stream < 2; stream++) { 407 for (stream = 0; stream < 2; stream++) {
415 substream = pcm->streams[stream].substream; 408 substream = pcm->streams[stream].substream;
@@ -433,7 +426,7 @@ static int s3c24xx_pcm_new(struct snd_card *card,
433{ 426{
434 int ret = 0; 427 int ret = 0;
435 428
436 DBG("Entered %s\n", __func__); 429 pr_debug("Entered %s\n", __func__);
437 430
438 if (!card->dev->dma_mask) 431 if (!card->dev->dma_mask)
439 card->dev->dma_mask = &s3c24xx_pcm_dmamask; 432 card->dev->dma_mask = &s3c24xx_pcm_dmamask;
diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c
index a0a4d1832a14..8e79a416db57 100644
--- a/sound/soc/s3c24xx/s3c24xx_uda134x.c
+++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c
@@ -22,7 +22,7 @@
22#include <sound/s3c24xx_uda134x.h> 22#include <sound/s3c24xx_uda134x.h>
23#include <sound/uda134x.h> 23#include <sound/uda134x.h>
24 24
25#include <asm/plat-s3c24xx/regs-iis.h> 25#include <plat/regs-iis.h>
26 26
27#include "s3c24xx-pcm.h" 27#include "s3c24xx-pcm.h"
28#include "s3c24xx-i2s.h" 28#include "s3c24xx-i2s.h"
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
new file mode 100644
index 000000000000..6e1e85dc1ff2
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.c
@@ -0,0 +1,220 @@
1/* sound/soc/s3c24xx/s3c64xx-i2s.c
2 *
3 * ALSA SoC Audio Layer - S3C64XX I2S driver
4 *
5 * Copyright 2008 Openmoko, Inc.
6 * Copyright 2008 Simtec Electronics
7 * Ben Dooks <ben@simtec.co.uk>
8 * http://armlinux.simtec.co.uk/
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/device.h>
18#include <linux/delay.h>
19#include <linux/clk.h>
20#include <linux/kernel.h>
21#include <linux/gpio.h>
22#include <linux/io.h>
23
24#include <sound/core.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/initval.h>
28#include <sound/soc.h>
29
30#include <plat/regs-s3c2412-iis.h>
31#include <plat/gpio-bank-d.h>
32#include <plat/gpio-bank-e.h>
33#include <plat/gpio-cfg.h>
34#include <plat/audio.h>
35
36#include <mach/map.h>
37#include <mach/dma.h>
38
39#include "s3c24xx-pcm.h"
40#include "s3c64xx-i2s.h"
41
42static struct s3c2410_dma_client s3c64xx_dma_client_out = {
43 .name = "I2S PCM Stereo out"
44};
45
46static struct s3c2410_dma_client s3c64xx_dma_client_in = {
47 .name = "I2S PCM Stereo in"
48};
49
50static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_out[2] = {
51 [0] = {
52 .channel = DMACH_I2S0_OUT,
53 .client = &s3c64xx_dma_client_out,
54 .dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD,
55 .dma_size = 4,
56 },
57 [1] = {
58 .channel = DMACH_I2S1_OUT,
59 .client = &s3c64xx_dma_client_out,
60 .dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD,
61 .dma_size = 4,
62 },
63};
64
65static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_in[2] = {
66 [0] = {
67 .channel = DMACH_I2S0_IN,
68 .client = &s3c64xx_dma_client_in,
69 .dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD,
70 .dma_size = 4,
71 },
72 [1] = {
73 .channel = DMACH_I2S1_IN,
74 .client = &s3c64xx_dma_client_in,
75 .dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD,
76 .dma_size = 4,
77 },
78};
79
80static struct s3c_i2sv2_info s3c64xx_i2s[2];
81
82static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
83{
84 return cpu_dai->private_data;
85}
86
87static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
88 int clk_id, unsigned int freq, int dir)
89{
90 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
91 u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
92
93 switch (clk_id) {
94 case S3C64XX_CLKSRC_PCLK:
95 iismod &= ~S3C64XX_IISMOD_IMS_SYSMUX;
96 break;
97
98 case S3C64XX_CLKSRC_MUX:
99 iismod |= S3C64XX_IISMOD_IMS_SYSMUX;
100 break;
101
102 default:
103 return -EINVAL;
104 }
105
106 writel(iismod, i2s->regs + S3C2412_IISMOD);
107
108 return 0;
109}
110
111
112unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *dai)
113{
114 struct s3c_i2sv2_info *i2s = to_info(dai);
115
116 return clk_get_rate(i2s->iis_cclk);
117}
118EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clockrate);
119
120static int s3c64xx_i2s_probe(struct platform_device *pdev,
121 struct snd_soc_dai *dai)
122{
123 struct device *dev = &pdev->dev;
124 struct s3c_i2sv2_info *i2s;
125 int ret;
126
127 dev_dbg(dev, "%s: probing dai %d\n", __func__, pdev->id);
128
129 if (pdev->id < 0 || pdev->id > ARRAY_SIZE(s3c64xx_i2s)) {
130 dev_err(dev, "id %d out of range\n", pdev->id);
131 return -EINVAL;
132 }
133
134 i2s = &s3c64xx_i2s[pdev->id];
135
136 ret = s3c_i2sv2_probe(pdev, dai, i2s,
137 pdev->id ? S3C64XX_PA_IIS1 : S3C64XX_PA_IIS0);
138 if (ret)
139 return ret;
140
141 i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
142 i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
143
144 i2s->iis_cclk = clk_get(dev, "audio-bus");
145 if (IS_ERR(i2s->iis_cclk)) {
146 dev_err(dev, "failed to get audio-bus");
147 iounmap(i2s->regs);
148 return -ENODEV;
149 }
150
151 /* configure GPIO for i2s port */
152 switch (pdev->id) {
153 case 0:
154 s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_I2S0_CLK);
155 s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_I2S0_CDCLK);
156 s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_I2S0_LRCLK);
157 s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_I2S0_DI);
158 s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_I2S0_D0);
159 break;
160 case 1:
161 s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_I2S1_CLK);
162 s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_I2S1_CDCLK);
163 s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
164 s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
165 s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
166 }
167
168 return 0;
169}
170
171
172#define S3C64XX_I2S_RATES \
173 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
174 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
175 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
176
177#define S3C64XX_I2S_FMTS \
178 (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE)
179
180struct snd_soc_dai s3c64xx_i2s_dai = {
181 .name = "s3c64xx-i2s",
182 .id = 0,
183 .probe = s3c64xx_i2s_probe,
184 .playback = {
185 .channels_min = 2,
186 .channels_max = 2,
187 .rates = S3C64XX_I2S_RATES,
188 .formats = S3C64XX_I2S_FMTS,
189 },
190 .capture = {
191 .channels_min = 2,
192 .channels_max = 2,
193 .rates = S3C64XX_I2S_RATES,
194 .formats = S3C64XX_I2S_FMTS,
195 },
196 .ops = {
197 .set_sysclk = s3c64xx_i2s_set_sysclk,
198 },
199};
200EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai);
201
202static int __init s3c64xx_i2s_init(void)
203{
204 return s3c_i2sv2_register_dai(&s3c64xx_i2s_dai);
205}
206module_init(s3c64xx_i2s_init);
207
208static void __exit s3c64xx_i2s_exit(void)
209{
210 snd_soc_unregister_dai(&s3c64xx_i2s_dai);
211}
212module_exit(s3c64xx_i2s_exit);
213
214/* Module information */
215MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
216MODULE_DESCRIPTION("S3C64XX I2S SoC Interface");
217MODULE_LICENSE("GPL");
218
219
220
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h
new file mode 100644
index 000000000000..b7ffe3c38b66
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.h
@@ -0,0 +1,31 @@
1/* sound/soc/s3c24xx/s3c64xx-i2s.h
2 *
3 * ALSA SoC Audio Layer - S3C64XX I2S driver
4 *
5 * Copyright 2008 Openmoko, Inc.
6 * Copyright 2008 Simtec Electronics
7 * Ben Dooks <ben@simtec.co.uk>
8 * http://armlinux.simtec.co.uk/
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#ifndef __SND_SOC_S3C24XX_S3C64XX_I2S_H
16#define __SND_SOC_S3C24XX_S3C64XX_I2S_H __FILE__
17
18#include "s3c-i2s-v2.h"
19
20#define S3C64XX_DIV_BCLK S3C_I2SV2_DIV_BCLK
21#define S3C64XX_DIV_RCLK S3C_I2SV2_DIV_RCLK
22#define S3C64XX_DIV_PRESCALER S3C_I2SV2_DIV_PRESCALER
23
24#define S3C64XX_CLKSRC_PCLK (0)
25#define S3C64XX_CLKSRC_MUX (1)
26
27extern struct snd_soc_dai s3c64xx_i2s_dai;
28
29extern unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *cpu_dai);
30
31#endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 4b8dbbfe2efb..735903a74675 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -332,7 +332,7 @@ static int dapm_new_mixer(struct snd_soc_codec *codec,
332 * kcontrol name. 332 * kcontrol name.
333 */ 333 */
334 name_len = strlen(w->kcontrols[i].name) + 1; 334 name_len = strlen(w->kcontrols[i].name) + 1;
335 if (w->id == snd_soc_dapm_mixer) 335 if (w->id != snd_soc_dapm_mixer_named_ctl)
336 name_len += 1 + strlen(w->name); 336 name_len += 1 + strlen(w->name);
337 337
338 path->long_name = kmalloc(name_len, GFP_KERNEL); 338 path->long_name = kmalloc(name_len, GFP_KERNEL);
@@ -341,15 +341,14 @@ static int dapm_new_mixer(struct snd_soc_codec *codec,
341 return -ENOMEM; 341 return -ENOMEM;
342 342
343 switch (w->id) { 343 switch (w->id) {
344 case snd_soc_dapm_mixer:
345 default: 344 default:
346 snprintf(path->long_name, name_len, "%s %s", 345 snprintf(path->long_name, name_len, "%s %s",
347 w->name, w->kcontrols[i].name); 346 w->name, w->kcontrols[i].name);
348 break; 347 break;
349 case snd_soc_dapm_mixer_named_ctl: 348 case snd_soc_dapm_mixer_named_ctl:
350 snprintf(path->long_name, name_len, "%s", 349 snprintf(path->long_name, name_len, "%s",
351 w->kcontrols[i].name); 350 w->kcontrols[i].name);
352 break; 351 break;
353 } 352 }
354 353
355 path->long_name[name_len - 1] = '\0'; 354 path->long_name[name_len - 1] = '\0';
@@ -523,6 +522,137 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
523EXPORT_SYMBOL_GPL(dapm_reg_event); 522EXPORT_SYMBOL_GPL(dapm_reg_event);
524 523
525/* 524/*
525 * Scan a single DAPM widget for a complete audio path and update the
526 * power status appropriately.
527 */
528static int dapm_power_widget(struct snd_soc_codec *codec, int event,
529 struct snd_soc_dapm_widget *w)
530{
531 int in, out, power_change, power, ret;
532
533 /* vmid - no action */
534 if (w->id == snd_soc_dapm_vmid)
535 return 0;
536
537 /* active ADC */
538 if (w->id == snd_soc_dapm_adc && w->active) {
539 in = is_connected_input_ep(w);
540 dapm_clear_walk(w->codec);
541 w->power = (in != 0) ? 1 : 0;
542 dapm_update_bits(w);
543 return 0;
544 }
545
546 /* active DAC */
547 if (w->id == snd_soc_dapm_dac && w->active) {
548 out = is_connected_output_ep(w);
549 dapm_clear_walk(w->codec);
550 w->power = (out != 0) ? 1 : 0;
551 dapm_update_bits(w);
552 return 0;
553 }
554
555 /* pre and post event widgets */
556 if (w->id == snd_soc_dapm_pre) {
557 if (!w->event)
558 return 0;
559
560 if (event == SND_SOC_DAPM_STREAM_START) {
561 ret = w->event(w,
562 NULL, SND_SOC_DAPM_PRE_PMU);
563 if (ret < 0)
564 return ret;
565 } else if (event == SND_SOC_DAPM_STREAM_STOP) {
566 ret = w->event(w,
567 NULL, SND_SOC_DAPM_PRE_PMD);
568 if (ret < 0)
569 return ret;
570 }
571 return 0;
572 }
573 if (w->id == snd_soc_dapm_post) {
574 if (!w->event)
575 return 0;
576
577 if (event == SND_SOC_DAPM_STREAM_START) {
578 ret = w->event(w,
579 NULL, SND_SOC_DAPM_POST_PMU);
580 if (ret < 0)
581 return ret;
582 } else if (event == SND_SOC_DAPM_STREAM_STOP) {
583 ret = w->event(w,
584 NULL, SND_SOC_DAPM_POST_PMD);
585 if (ret < 0)
586 return ret;
587 }
588 return 0;
589 }
590
591 /* all other widgets */
592 in = is_connected_input_ep(w);
593 dapm_clear_walk(w->codec);
594 out = is_connected_output_ep(w);
595 dapm_clear_walk(w->codec);
596 power = (out != 0 && in != 0) ? 1 : 0;
597 power_change = (w->power == power) ? 0 : 1;
598 w->power = power;
599
600 if (!power_change)
601 return 0;
602
603 /* call any power change event handlers */
604 if (w->event)
605 pr_debug("power %s event for %s flags %x\n",
606 w->power ? "on" : "off",
607 w->name, w->event_flags);
608
609 /* power up pre event */
610 if (power && w->event &&
611 (w->event_flags & SND_SOC_DAPM_PRE_PMU)) {
612 ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU);
613 if (ret < 0)
614 return ret;
615 }
616
617 /* power down pre event */
618 if (!power && w->event &&
619 (w->event_flags & SND_SOC_DAPM_PRE_PMD)) {
620 ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD);
621 if (ret < 0)
622 return ret;
623 }
624
625 /* Lower PGA volume to reduce pops */
626 if (w->id == snd_soc_dapm_pga && !power)
627 dapm_set_pga(w, power);
628
629 dapm_update_bits(w);
630
631 /* Raise PGA volume to reduce pops */
632 if (w->id == snd_soc_dapm_pga && power)
633 dapm_set_pga(w, power);
634
635 /* power up post event */
636 if (power && w->event &&
637 (w->event_flags & SND_SOC_DAPM_POST_PMU)) {
638 ret = w->event(w,
639 NULL, SND_SOC_DAPM_POST_PMU);
640 if (ret < 0)
641 return ret;
642 }
643
644 /* power down post event */
645 if (!power && w->event &&
646 (w->event_flags & SND_SOC_DAPM_POST_PMD)) {
647 ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD);
648 if (ret < 0)
649 return ret;
650 }
651
652 return 0;
653}
654
655/*
526 * Scan each dapm widget for complete audio path. 656 * Scan each dapm widget for complete audio path.
527 * A complete path is a route that has valid endpoints i.e.:- 657 * A complete path is a route that has valid endpoints i.e.:-
528 * 658 *
@@ -534,7 +664,7 @@ EXPORT_SYMBOL_GPL(dapm_reg_event);
534static int dapm_power_widgets(struct snd_soc_codec *codec, int event) 664static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
535{ 665{
536 struct snd_soc_dapm_widget *w; 666 struct snd_soc_dapm_widget *w;
537 int in, out, i, c = 1, *seq = NULL, ret = 0, power_change, power; 667 int i, c = 1, *seq = NULL, ret = 0;
538 668
539 /* do we have a sequenced stream event */ 669 /* do we have a sequenced stream event */
540 if (event == SND_SOC_DAPM_STREAM_START) { 670 if (event == SND_SOC_DAPM_STREAM_START) {
@@ -545,135 +675,20 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
545 seq = dapm_down_seq; 675 seq = dapm_down_seq;
546 } 676 }
547 677
548 for(i = 0; i < c; i++) { 678 for (i = 0; i < c; i++) {
549 list_for_each_entry(w, &codec->dapm_widgets, list) { 679 list_for_each_entry(w, &codec->dapm_widgets, list) {
550 680
551 /* is widget in stream order */ 681 /* is widget in stream order */
552 if (seq && seq[i] && w->id != seq[i]) 682 if (seq && seq[i] && w->id != seq[i])
553 continue; 683 continue;
554 684
555 /* vmid - no action */ 685 ret = dapm_power_widget(codec, event, w);
556 if (w->id == snd_soc_dapm_vmid) 686 if (ret != 0)
557 continue; 687 return ret;
558
559 /* active ADC */
560 if (w->id == snd_soc_dapm_adc && w->active) {
561 in = is_connected_input_ep(w);
562 dapm_clear_walk(w->codec);
563 w->power = (in != 0) ? 1 : 0;
564 dapm_update_bits(w);
565 continue;
566 }
567
568 /* active DAC */
569 if (w->id == snd_soc_dapm_dac && w->active) {
570 out = is_connected_output_ep(w);
571 dapm_clear_walk(w->codec);
572 w->power = (out != 0) ? 1 : 0;
573 dapm_update_bits(w);
574 continue;
575 }
576
577 /* pre and post event widgets */
578 if (w->id == snd_soc_dapm_pre) {
579 if (!w->event)
580 continue;
581
582 if (event == SND_SOC_DAPM_STREAM_START) {
583 ret = w->event(w,
584 NULL, SND_SOC_DAPM_PRE_PMU);
585 if (ret < 0)
586 return ret;
587 } else if (event == SND_SOC_DAPM_STREAM_STOP) {
588 ret = w->event(w,
589 NULL, SND_SOC_DAPM_PRE_PMD);
590 if (ret < 0)
591 return ret;
592 }
593 continue;
594 }
595 if (w->id == snd_soc_dapm_post) {
596 if (!w->event)
597 continue;
598
599 if (event == SND_SOC_DAPM_STREAM_START) {
600 ret = w->event(w,
601 NULL, SND_SOC_DAPM_POST_PMU);
602 if (ret < 0)
603 return ret;
604 } else if (event == SND_SOC_DAPM_STREAM_STOP) {
605 ret = w->event(w,
606 NULL, SND_SOC_DAPM_POST_PMD);
607 if (ret < 0)
608 return ret;
609 }
610 continue;
611 }
612
613 /* all other widgets */
614 in = is_connected_input_ep(w);
615 dapm_clear_walk(w->codec);
616 out = is_connected_output_ep(w);
617 dapm_clear_walk(w->codec);
618 power = (out != 0 && in != 0) ? 1 : 0;
619 power_change = (w->power == power) ? 0: 1;
620 w->power = power;
621
622 if (!power_change)
623 continue;
624
625 /* call any power change event handlers */
626 if (w->event)
627 pr_debug("power %s event for %s flags %x\n",
628 w->power ? "on" : "off",
629 w->name, w->event_flags);
630
631 /* power up pre event */
632 if (power && w->event &&
633 (w->event_flags & SND_SOC_DAPM_PRE_PMU)) {
634 ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU);
635 if (ret < 0)
636 return ret;
637 }
638
639 /* power down pre event */
640 if (!power && w->event &&
641 (w->event_flags & SND_SOC_DAPM_PRE_PMD)) {
642 ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD);
643 if (ret < 0)
644 return ret;
645 }
646
647 /* Lower PGA volume to reduce pops */
648 if (w->id == snd_soc_dapm_pga && !power)
649 dapm_set_pga(w, power);
650
651 dapm_update_bits(w);
652
653 /* Raise PGA volume to reduce pops */
654 if (w->id == snd_soc_dapm_pga && power)
655 dapm_set_pga(w, power);
656
657 /* power up post event */
658 if (power && w->event &&
659 (w->event_flags & SND_SOC_DAPM_POST_PMU)) {
660 ret = w->event(w,
661 NULL, SND_SOC_DAPM_POST_PMU);
662 if (ret < 0)
663 return ret;
664 }
665
666 /* power down post event */
667 if (!power && w->event &&
668 (w->event_flags & SND_SOC_DAPM_POST_PMD)) {
669 ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD);
670 if (ret < 0)
671 return ret;
672 }
673 } 688 }
674 } 689 }
675 690
676 return ret; 691 return 0;
677} 692}
678 693
679#ifdef DEBUG 694#ifdef DEBUG
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index ab64a30bedde..28346fb2e70c 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -14,6 +14,10 @@
14#include <sound/jack.h> 14#include <sound/jack.h>
15#include <sound/soc.h> 15#include <sound/soc.h>
16#include <sound/soc-dapm.h> 16#include <sound/soc-dapm.h>
17#include <linux/gpio.h>
18#include <linux/interrupt.h>
19#include <linux/workqueue.h>
20#include <linux/delay.h>
17 21
18/** 22/**
19 * snd_soc_jack_new - Create a new jack 23 * snd_soc_jack_new - Create a new jack
@@ -136,3 +140,128 @@ int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
136 return 0; 140 return 0;
137} 141}
138EXPORT_SYMBOL_GPL(snd_soc_jack_add_pins); 142EXPORT_SYMBOL_GPL(snd_soc_jack_add_pins);
143
144#ifdef CONFIG_GPIOLIB
145/* gpio detect */
146static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
147{
148 struct snd_soc_jack *jack = gpio->jack;
149 int enable;
150 int report;
151
152 if (gpio->debounce_time > 0)
153 mdelay(gpio->debounce_time);
154
155 enable = gpio_get_value(gpio->gpio);
156 if (gpio->invert)
157 enable = !enable;
158
159 if (enable)
160 report = gpio->report;
161 else
162 report = 0;
163
164 snd_soc_jack_report(jack, report, gpio->report);
165}
166
167/* irq handler for gpio pin */
168static irqreturn_t gpio_handler(int irq, void *data)
169{
170 struct snd_soc_jack_gpio *gpio = data;
171
172 schedule_work(&gpio->work);
173
174 return IRQ_HANDLED;
175}
176
177/* gpio work */
178static void gpio_work(struct work_struct *work)
179{
180 struct snd_soc_jack_gpio *gpio;
181
182 gpio = container_of(work, struct snd_soc_jack_gpio, work);
183 snd_soc_jack_gpio_detect(gpio);
184}
185
186/**
187 * snd_soc_jack_add_gpios - Associate GPIO pins with an ASoC jack
188 *
189 * @jack: ASoC jack
190 * @count: number of pins
191 * @gpios: array of gpio pins
192 *
193 * This function will request gpio, set data direction and request irq
194 * for each gpio in the array.
195 */
196int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
197 struct snd_soc_jack_gpio *gpios)
198{
199 int i, ret;
200
201 for (i = 0; i < count; i++) {
202 if (!gpio_is_valid(gpios[i].gpio)) {
203 printk(KERN_ERR "Invalid gpio %d\n",
204 gpios[i].gpio);
205 ret = -EINVAL;
206 goto undo;
207 }
208 if (!gpios[i].name) {
209 printk(KERN_ERR "No name for gpio %d\n",
210 gpios[i].gpio);
211 ret = -EINVAL;
212 goto undo;
213 }
214
215 ret = gpio_request(gpios[i].gpio, gpios[i].name);
216 if (ret)
217 goto undo;
218
219 ret = gpio_direction_input(gpios[i].gpio);
220 if (ret)
221 goto err;
222
223 ret = request_irq(gpio_to_irq(gpios[i].gpio),
224 gpio_handler,
225 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
226 jack->card->dev->driver->name,
227 &gpios[i]);
228 if (ret)
229 goto err;
230
231 INIT_WORK(&gpios[i].work, gpio_work);
232 gpios[i].jack = jack;
233 }
234
235 return 0;
236
237err:
238 gpio_free(gpios[i].gpio);
239undo:
240 snd_soc_jack_free_gpios(jack, i, gpios);
241
242 return ret;
243}
244EXPORT_SYMBOL_GPL(snd_soc_jack_add_gpios);
245
246/**
247 * snd_soc_jack_free_gpios - Release GPIO pins' resources of an ASoC jack
248 *
249 * @jack: ASoC jack
250 * @count: number of pins
251 * @gpios: array of gpio pins
252 *
253 * Release gpio and irq resources for gpio pins associated with an ASoC jack.
254 */
255void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
256 struct snd_soc_jack_gpio *gpios)
257{
258 int i;
259
260 for (i = 0; i < count; i++) {
261 free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]);
262 gpio_free(gpios[i].gpio);
263 gpios[i].jack = NULL;
264 }
265}
266EXPORT_SYMBOL_GPL(snd_soc_jack_free_gpios);
267#endif /* CONFIG_GPIOLIB */