aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/Kconfig1
-rw-r--r--sound/soc/Makefile2
-rw-r--r--sound/soc/at91/at91-pcm.c1
-rw-r--r--sound/soc/at91/at91-ssc.c1
-rw-r--r--sound/soc/at91/eti_b1_wm8731.c1
-rw-r--r--sound/soc/codecs/Kconfig3
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/ac97.c1
-rw-r--r--sound/soc/codecs/cs4270.c262
-rw-r--r--sound/soc/codecs/tlv320aic3x.c1274
-rw-r--r--sound/soc/codecs/tlv320aic3x.h181
-rw-r--r--sound/soc/codecs/wm8731.c9
-rw-r--r--sound/soc/codecs/wm8750.c3
-rw-r--r--sound/soc/codecs/wm8753.c8
-rw-r--r--sound/soc/codecs/wm9712.c10
-rw-r--r--sound/soc/fsl/Kconfig20
-rw-r--r--sound/soc/fsl/Makefile6
-rw-r--r--sound/soc/fsl/fsl_dma.c841
-rw-r--r--sound/soc/fsl/fsl_dma.h149
-rw-r--r--sound/soc/fsl/fsl_ssi.c644
-rw-r--r--sound/soc/fsl/fsl_ssi.h224
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c631
-rw-r--r--sound/soc/pxa/Kconfig9
-rw-r--r--sound/soc/pxa/Makefile2
-rw-r--r--sound/soc/pxa/corgi.c1
-rw-r--r--sound/soc/pxa/e800_wm9712.c89
-rw-r--r--sound/soc/pxa/poodle.c1
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c1
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c1
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.c1
-rw-r--r--sound/soc/pxa/spitz.c1
-rw-r--r--sound/soc/pxa/tosa.c1
-rw-r--r--sound/soc/s3c24xx/Kconfig11
-rw-r--r--sound/soc/s3c24xx/Makefile4
-rw-r--r--sound/soc/s3c24xx/ln2440sbc_alc650.c85
-rw-r--r--sound/soc/s3c24xx/neo1973_wm8753.c5
-rw-r--r--sound/soc/s3c24xx/s3c2412-i2s.c744
-rw-r--r--sound/soc/s3c24xx/s3c2412-i2s.h38
-rw-r--r--sound/soc/s3c24xx/s3c2443-ac97.c5
-rw-r--r--sound/soc/s3c24xx/s3c24xx-ac97.h6
-rw-r--r--sound/soc/s3c24xx/s3c24xx-i2s.c45
-rw-r--r--sound/soc/s3c24xx/s3c24xx-pcm.c49
-rw-r--r--sound/soc/s3c24xx/smdk2443_wm9710.c1
-rw-r--r--sound/soc/sh/dma-sh7760.c1
-rw-r--r--sound/soc/sh/hac.c14
-rw-r--r--sound/soc/sh/sh7760-ac97.c1
-rw-r--r--sound/soc/sh/ssi.c1
-rw-r--r--sound/soc/soc-core.c110
-rw-r--r--sound/soc/soc-dapm.c85
49 files changed, 5313 insertions, 273 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 97b255233175..276585215160 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -28,6 +28,7 @@ source "sound/soc/at91/Kconfig"
28source "sound/soc/pxa/Kconfig" 28source "sound/soc/pxa/Kconfig"
29source "sound/soc/s3c24xx/Kconfig" 29source "sound/soc/s3c24xx/Kconfig"
30source "sound/soc/sh/Kconfig" 30source "sound/soc/sh/Kconfig"
31source "sound/soc/fsl/Kconfig"
31 32
32# Supported codecs 33# Supported codecs
33source "sound/soc/codecs/Kconfig" 34source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 304140377632..4869c9ae7a03 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,4 +1,4 @@
1snd-soc-core-objs := soc-core.o soc-dapm.o 1snd-soc-core-objs := soc-core.o soc-dapm.o
2 2
3obj-$(CONFIG_SND_SOC) += snd-soc-core.o 3obj-$(CONFIG_SND_SOC) += snd-soc-core.o
4obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/ 4obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/ fsl/
diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c
index b39b95a47040..67c88e322fb1 100644
--- a/sound/soc/at91/at91-pcm.c
+++ b/sound/soc/at91/at91-pcm.c
@@ -23,7 +23,6 @@
23#include <linux/dma-mapping.h> 23#include <linux/dma-mapping.h>
24#include <linux/atmel_pdc.h> 24#include <linux/atmel_pdc.h>
25 25
26#include <sound/driver.h>
27#include <sound/core.h> 26#include <sound/core.h>
28#include <sound/pcm.h> 27#include <sound/pcm.h>
29#include <sound/pcm_params.h> 28#include <sound/pcm_params.h>
diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c
index 3d4e32cff75e..f642d2dd4ec3 100644
--- a/sound/soc/at91/at91-ssc.c
+++ b/sound/soc/at91/at91-ssc.c
@@ -22,7 +22,6 @@
22#include <linux/clk.h> 22#include <linux/clk.h>
23#include <linux/atmel_pdc.h> 23#include <linux/atmel_pdc.h>
24 24
25#include <sound/driver.h>
26#include <sound/core.h> 25#include <sound/core.h>
27#include <sound/pcm.h> 26#include <sound/pcm.h>
28#include <sound/pcm_params.h> 27#include <sound/pcm_params.h>
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c
index 820a676c56bf..ad3ad9d662f8 100644
--- a/sound/soc/at91/eti_b1_wm8731.c
+++ b/sound/soc/at91/eti_b1_wm8731.c
@@ -28,7 +28,6 @@
28#include <linux/timer.h> 28#include <linux/timer.h>
29#include <linux/interrupt.h> 29#include <linux/interrupt.h>
30#include <linux/platform_device.h> 30#include <linux/platform_device.h>
31#include <sound/driver.h>
32#include <sound/core.h> 31#include <sound/core.h>
33#include <sound/pcm.h> 32#include <sound/pcm.h>
34#include <sound/soc.h> 33#include <sound/soc.h>
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 78248808a9d8..898a7d363284 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -37,3 +37,6 @@ config SND_SOC_CS4270_VD33_ERRATA
37 bool 37 bool
38 depends on SND_SOC_CS4270 38 depends on SND_SOC_CS4270
39 39
40config SND_SOC_TLV320AIC3X
41 tristate
42 depends on SND_SOC && I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 7ad78e36d506..c6e5338c2666 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -4,6 +4,7 @@ snd-soc-wm8750-objs := wm8750.o
4snd-soc-wm8753-objs := wm8753.o 4snd-soc-wm8753-objs := wm8753.o
5snd-soc-wm9712-objs := wm9712.o 5snd-soc-wm9712-objs := wm9712.o
6snd-soc-cs4270-objs := cs4270.o 6snd-soc-cs4270-objs := cs4270.o
7snd-soc-tlv320aic3x-objs := tlv320aic3x.o
7 8
8obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o 9obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
9obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o 10obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o
@@ -11,3 +12,4 @@ obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
11obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o 12obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
12obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o 13obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
13obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o 14obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
15obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 0b8a6f8b3668..242130cf1abd 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -19,7 +19,6 @@
19#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/kernel.h> 20#include <linux/kernel.h>
21#include <linux/device.h> 21#include <linux/device.h>
22#include <sound/driver.h>
23#include <sound/core.h> 22#include <sound/core.h>
24#include <sound/pcm.h> 23#include <sound/pcm.h>
25#include <sound/ac97_codec.h> 24#include <sound/ac97_codec.h>
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index dab22cc97ead..bf2ab72d49bf 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -28,7 +28,6 @@
28 28
29#include <linux/module.h> 29#include <linux/module.h>
30#include <linux/platform_device.h> 30#include <linux/platform_device.h>
31#include <sound/driver.h>
32#include <sound/core.h> 31#include <sound/core.h>
33#include <sound/soc.h> 32#include <sound/soc.h>
34#include <sound/initval.h> 33#include <sound/initval.h>
@@ -48,12 +47,130 @@ struct cs4270_private {
48 unsigned int mode; /* The mode (I2S or left-justified) */ 47 unsigned int mode; /* The mode (I2S or left-justified) */
49}; 48};
50 49
51/* The number of MCLK/LRCK ratios supported by the CS4270 */ 50/*
52#define NUM_MCLK_RATIOS 9 51 * The codec isn't really big-endian or little-endian, since the I2S
52 * interface requires data to be sent serially with the MSbit first.
53 * However, to support BE and LE I2S devices, we specify both here. That
54 * way, ALSA will always match the bit patterns.
55 */
56#define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
57 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
58 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
59 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
60 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
61 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE)
62
63#ifdef USE_I2C
64
65/* CS4270 registers addresses */
66#define CS4270_CHIPID 0x01 /* Chip ID */
67#define CS4270_PWRCTL 0x02 /* Power Control */
68#define CS4270_MODE 0x03 /* Mode Control */
69#define CS4270_FORMAT 0x04 /* Serial Format, ADC/DAC Control */
70#define CS4270_TRANS 0x05 /* Transition Control */
71#define CS4270_MUTE 0x06 /* Mute Control */
72#define CS4270_VOLA 0x07 /* DAC Channel A Volume Control */
73#define CS4270_VOLB 0x08 /* DAC Channel B Volume Control */
74
75#define CS4270_FIRSTREG 0x01
76#define CS4270_LASTREG 0x08
77#define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1)
53 78
54/* The actual MCLK/LRCK ratios, in increasing numerical order */ 79/* Bit masks for the CS4270 registers */
55static unsigned int mclk_ratios[NUM_MCLK_RATIOS] = 80#define CS4270_CHIPID_ID 0xF0
56 {64, 96, 128, 192, 256, 384, 512, 768, 1024}; 81#define CS4270_CHIPID_REV 0x0F
82#define CS4270_PWRCTL_FREEZE 0x80
83#define CS4270_PWRCTL_PDN_ADC 0x20
84#define CS4270_PWRCTL_PDN_DAC 0x02
85#define CS4270_PWRCTL_PDN 0x01
86#define CS4270_MODE_SPEED_MASK 0x30
87#define CS4270_MODE_1X 0x00
88#define CS4270_MODE_2X 0x10
89#define CS4270_MODE_4X 0x20
90#define CS4270_MODE_SLAVE 0x30
91#define CS4270_MODE_DIV_MASK 0x0E
92#define CS4270_MODE_DIV1 0x00
93#define CS4270_MODE_DIV15 0x02
94#define CS4270_MODE_DIV2 0x04
95#define CS4270_MODE_DIV3 0x06
96#define CS4270_MODE_DIV4 0x08
97#define CS4270_MODE_POPGUARD 0x01
98#define CS4270_FORMAT_FREEZE_A 0x80
99#define CS4270_FORMAT_FREEZE_B 0x40
100#define CS4270_FORMAT_LOOPBACK 0x20
101#define CS4270_FORMAT_DAC_MASK 0x18
102#define CS4270_FORMAT_DAC_LJ 0x00
103#define CS4270_FORMAT_DAC_I2S 0x08
104#define CS4270_FORMAT_DAC_RJ16 0x18
105#define CS4270_FORMAT_DAC_RJ24 0x10
106#define CS4270_FORMAT_ADC_MASK 0x01
107#define CS4270_FORMAT_ADC_LJ 0x00
108#define CS4270_FORMAT_ADC_I2S 0x01
109#define CS4270_TRANS_ONE_VOL 0x80
110#define CS4270_TRANS_SOFT 0x40
111#define CS4270_TRANS_ZERO 0x20
112#define CS4270_TRANS_INV_ADC_A 0x08
113#define CS4270_TRANS_INV_ADC_B 0x10
114#define CS4270_TRANS_INV_DAC_A 0x02
115#define CS4270_TRANS_INV_DAC_B 0x04
116#define CS4270_TRANS_DEEMPH 0x01
117#define CS4270_MUTE_AUTO 0x20
118#define CS4270_MUTE_ADC_A 0x08
119#define CS4270_MUTE_ADC_B 0x10
120#define CS4270_MUTE_POLARITY 0x04
121#define CS4270_MUTE_DAC_A 0x01
122#define CS4270_MUTE_DAC_B 0x02
123
124/*
125 * Clock Ratio Selection for Master Mode with I2C enabled
126 *
127 * The data for this chart is taken from Table 5 of the CS4270 reference
128 * manual.
129 *
130 * This table is used to determine how to program the Mode Control register.
131 * It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling
132 * rates the CS4270 currently supports.
133 *
134 * Each element in this array corresponds to the ratios in mclk_ratios[].
135 * These two arrays need to be in sync.
136 *
137 * 'speed_mode' is the corresponding bit pattern to be written to the
138 * MODE bits of the Mode Control Register
139 *
140 * 'mclk' is the corresponding bit pattern to be wirten to the MCLK bits of
141 * the Mode Control Register.
142 *
143 * In situations where a single ratio is represented by multiple speed
144 * modes, we favor the slowest speed. E.g, for a ratio of 128, we pick
145 * double-speed instead of quad-speed. However, the CS4270 errata states
146 * that Divide-By-1.5 can cause failures, so we avoid that mode where
147 * possible.
148 *
149 * ERRATA: There is an errata for the CS4270 where divide-by-1.5 does not
150 * work if VD = 3.3V. If this effects you, select the
151 * CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will
152 * never select any sample rates that require divide-by-1.5.
153 */
154static struct {
155 unsigned int ratio;
156 u8 speed_mode;
157 u8 mclk;
158} cs4270_mode_ratios[] = {
159 {64, CS4270_MODE_4X, CS4270_MODE_DIV1},
160#ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA
161 {96, CS4270_MODE_4X, CS4270_MODE_DIV15},
162#endif
163 {128, CS4270_MODE_2X, CS4270_MODE_DIV1},
164 {192, CS4270_MODE_4X, CS4270_MODE_DIV3},
165 {256, CS4270_MODE_1X, CS4270_MODE_DIV1},
166 {384, CS4270_MODE_2X, CS4270_MODE_DIV3},
167 {512, CS4270_MODE_1X, CS4270_MODE_DIV2},
168 {768, CS4270_MODE_1X, CS4270_MODE_DIV3},
169 {1024, CS4270_MODE_1X, CS4270_MODE_DIV4}
170};
171
172/* The number of MCLK/LRCK ratios supported by the CS4270 */
173#define NUM_MCLK_RATIOS ARRAY_SIZE(cs4270_mode_ratios)
57 174
58/* 175/*
59 * Determine the CS4270 samples rates. 176 * Determine the CS4270 samples rates.
@@ -97,7 +214,7 @@ static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
97 cs4270->mclk = freq; 214 cs4270->mclk = freq;
98 215
99 for (i = 0; i < NUM_MCLK_RATIOS; i++) { 216 for (i = 0; i < NUM_MCLK_RATIOS; i++) {
100 unsigned int rate = freq / mclk_ratios[i]; 217 unsigned int rate = freq / cs4270_mode_ratios[i].ratio;
101 rates |= snd_pcm_rate_to_rate_bit(rate); 218 rates |= snd_pcm_rate_to_rate_bit(rate);
102 if (rate < rate_min) 219 if (rate < rate_min)
103 rate_min = rate; 220 rate_min = rate;
@@ -155,80 +272,6 @@ static int cs4270_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
155} 272}
156 273
157/* 274/*
158 * The codec isn't really big-endian or little-endian, since the I2S
159 * interface requires data to be sent serially with the MSbit first.
160 * However, to support BE and LE I2S devices, we specify both here. That
161 * way, ALSA will always match the bit patterns.
162 */
163#define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
164 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
165 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
166 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
167 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
168 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE)
169
170#ifdef USE_I2C
171
172/* CS4270 registers addresses */
173#define CS4270_CHIPID 0x01 /* Chip ID */
174#define CS4270_PWRCTL 0x02 /* Power Control */
175#define CS4270_MODE 0x03 /* Mode Control */
176#define CS4270_FORMAT 0x04 /* Serial Format, ADC/DAC Control */
177#define CS4270_TRANS 0x05 /* Transition Control */
178#define CS4270_MUTE 0x06 /* Mute Control */
179#define CS4270_VOLA 0x07 /* DAC Channel A Volume Control */
180#define CS4270_VOLB 0x08 /* DAC Channel B Volume Control */
181
182#define CS4270_FIRSTREG 0x01
183#define CS4270_LASTREG 0x08
184#define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1)
185
186/* Bit masks for the CS4270 registers */
187#define CS4270_CHIPID_ID 0xF0
188#define CS4270_CHIPID_REV 0x0F
189#define CS4270_PWRCTL_FREEZE 0x80
190#define CS4270_PWRCTL_PDN_ADC 0x20
191#define CS4270_PWRCTL_PDN_DAC 0x02
192#define CS4270_PWRCTL_PDN 0x01
193#define CS4270_MODE_SPEED_MASK 0x30
194#define CS4270_MODE_1X 0x00
195#define CS4270_MODE_2X 0x10
196#define CS4270_MODE_4X 0x20
197#define CS4270_MODE_SLAVE 0x30
198#define CS4270_MODE_DIV_MASK 0x0E
199#define CS4270_MODE_DIV1 0x00
200#define CS4270_MODE_DIV15 0x02
201#define CS4270_MODE_DIV2 0x04
202#define CS4270_MODE_DIV3 0x06
203#define CS4270_MODE_DIV4 0x08
204#define CS4270_MODE_POPGUARD 0x01
205#define CS4270_FORMAT_FREEZE_A 0x80
206#define CS4270_FORMAT_FREEZE_B 0x40
207#define CS4270_FORMAT_LOOPBACK 0x20
208#define CS4270_FORMAT_DAC_MASK 0x18
209#define CS4270_FORMAT_DAC_LJ 0x00
210#define CS4270_FORMAT_DAC_I2S 0x08
211#define CS4270_FORMAT_DAC_RJ16 0x18
212#define CS4270_FORMAT_DAC_RJ24 0x10
213#define CS4270_FORMAT_ADC_MASK 0x01
214#define CS4270_FORMAT_ADC_LJ 0x00
215#define CS4270_FORMAT_ADC_I2S 0x01
216#define CS4270_TRANS_ONE_VOL 0x80
217#define CS4270_TRANS_SOFT 0x40
218#define CS4270_TRANS_ZERO 0x20
219#define CS4270_TRANS_INV_ADC_A 0x08
220#define CS4270_TRANS_INV_ADC_B 0x10
221#define CS4270_TRANS_INV_DAC_A 0x02
222#define CS4270_TRANS_INV_DAC_B 0x04
223#define CS4270_TRANS_DEEMPH 0x01
224#define CS4270_MUTE_AUTO 0x20
225#define CS4270_MUTE_ADC_A 0x08
226#define CS4270_MUTE_ADC_B 0x10
227#define CS4270_MUTE_POLARITY 0x04
228#define CS4270_MUTE_DAC_A 0x01
229#define CS4270_MUTE_DAC_B 0x02
230
231/*
232 * A list of addresses on which this CS4270 could use. I2C addresses are 275 * A list of addresses on which this CS4270 could use. I2C addresses are
233 * 7 bits. For the CS4270, the upper four bits are always 1001, and the 276 * 7 bits. For the CS4270, the upper four bits are always 1001, and the
234 * lower three bits are determined via the AD2, AD1, and AD0 pins 277 * lower three bits are determined via the AD2, AD1, and AD0 pins
@@ -315,53 +358,6 @@ static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg,
315} 358}
316 359
317/* 360/*
318 * Clock Ratio Selection for Master Mode with I2C enabled
319 *
320 * The data for this chart is taken from Table 5 of the CS4270 reference
321 * manual.
322 *
323 * This table is used to determine how to program the Mode Control register.
324 * It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling
325 * rates the CS4270 currently supports.
326 *
327 * Each element in this array corresponds to the ratios in mclk_ratios[].
328 * These two arrays need to be in sync.
329 *
330 * 'speed_mode' is the corresponding bit pattern to be written to the
331 * MODE bits of the Mode Control Register
332 *
333 * 'mclk' is the corresponding bit pattern to be wirten to the MCLK bits of
334 * the Mode Control Register.
335 *
336 * In situations where a single ratio is represented by multiple speed
337 * modes, we favor the slowest speed. E.g, for a ratio of 128, we pick
338 * double-speed instead of quad-speed. However, the CS4270 errata states
339 * that Divide-By-1.5 can cause failures, so we avoid that mode where
340 * possible.
341 *
342 * ERRATA: There is an errata for the CS4270 where divide-by-1.5 does not
343 * work if VD = 3.3V. If this effects you, select the
344 * CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will
345 * never select any sample rates that require divide-by-1.5.
346 */
347static struct {
348 u8 speed_mode;
349 u8 mclk;
350} cs4270_mode_ratios[NUM_MCLK_RATIOS] = {
351 {CS4270_MODE_4X, CS4270_MODE_DIV1}, /* 64 */
352#ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA
353 {CS4270_MODE_4X, CS4270_MODE_DIV15}, /* 96 */
354#endif
355 {CS4270_MODE_2X, CS4270_MODE_DIV1}, /* 128 */
356 {CS4270_MODE_4X, CS4270_MODE_DIV3}, /* 192 */
357 {CS4270_MODE_1X, CS4270_MODE_DIV1}, /* 256 */
358 {CS4270_MODE_2X, CS4270_MODE_DIV3}, /* 384 */
359 {CS4270_MODE_1X, CS4270_MODE_DIV2}, /* 512 */
360 {CS4270_MODE_1X, CS4270_MODE_DIV3}, /* 768 */
361 {CS4270_MODE_1X, CS4270_MODE_DIV4} /* 1024 */
362};
363
364/*
365 * Program the CS4270 with the given hardware parameters. 361 * Program the CS4270 with the given hardware parameters.
366 * 362 *
367 * The .dai_ops functions are used to provide board-specific data, like 363 * The .dai_ops functions are used to provide board-specific data, like
@@ -388,7 +384,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
388 ratio = cs4270->mclk / rate; /* MCLK/LRCK ratio */ 384 ratio = cs4270->mclk / rate; /* MCLK/LRCK ratio */
389 385
390 for (i = 0; i < NUM_MCLK_RATIOS; i++) { 386 for (i = 0; i < NUM_MCLK_RATIOS; i++) {
391 if (mclk_ratios[i] == ratio) 387 if (cs4270_mode_ratios[i].ratio == ratio)
392 break; 388 break;
393 } 389 }
394 390
@@ -669,7 +665,7 @@ error:
669 return ret; 665 return ret;
670} 666}
671 667
672#endif 668#endif /* USE_I2C*/
673 669
674struct snd_soc_codec_dai cs4270_dai = { 670struct snd_soc_codec_dai cs4270_dai = {
675 .name = "CS4270", 671 .name = "CS4270",
@@ -687,10 +683,6 @@ struct snd_soc_codec_dai cs4270_dai = {
687 .rates = 0, 683 .rates = 0,
688 .formats = CS4270_FORMATS, 684 .formats = CS4270_FORMATS,
689 }, 685 },
690 .dai_ops = {
691 .set_sysclk = cs4270_set_dai_sysclk,
692 .set_fmt = cs4270_set_dai_fmt,
693 }
694}; 686};
695EXPORT_SYMBOL_GPL(cs4270_dai); 687EXPORT_SYMBOL_GPL(cs4270_dai);
696 688
@@ -752,6 +744,8 @@ static int cs4270_probe(struct platform_device *pdev)
752 if (codec->control_data) { 744 if (codec->control_data) {
753 /* Initialize codec ops */ 745 /* Initialize codec ops */
754 cs4270_dai.ops.hw_params = cs4270_hw_params; 746 cs4270_dai.ops.hw_params = cs4270_hw_params;
747 cs4270_dai.dai_ops.set_sysclk = cs4270_set_dai_sysclk;
748 cs4270_dai.dai_ops.set_fmt = cs4270_set_dai_fmt;
755#ifdef CONFIG_SND_SOC_CS4270_HWMUTE 749#ifdef CONFIG_SND_SOC_CS4270_HWMUTE
756 cs4270_dai.dai_ops.digital_mute = cs4270_mute; 750 cs4270_dai.dai_ops.digital_mute = cs4270_mute;
757#endif 751#endif
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
new file mode 100644
index 000000000000..710e0287ef8c
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -0,0 +1,1274 @@
1/*
2 * ALSA SoC TLV320AIC3X codec driver
3 *
4 * Author: Vladimir Barinov, <vbarinov@ru.mvista.com>
5 * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com>
6 *
7 * Based on sound/soc/codecs/wm8753.c by Liam Girdwood
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 * Notes:
14 * The AIC3X is a driver for a low power stereo audio
15 * codecs aic31, aic32, aic33.
16 *
17 * It supports full aic33 codec functionality.
18 * The compatibility with aic32, aic31 is as follows:
19 * aic32 | aic31
20 * ---------------------------------------
21 * MONO_LOUT -> N/A | MONO_LOUT -> N/A
22 * | IN1L -> LINE1L
23 * | IN1R -> LINE1R
24 * | IN2L -> LINE2L
25 * | IN2R -> LINE2R
26 * | MIC3L/R -> N/A
27 * truncated internal functionality in
28 * accordance with documentation
29 * ---------------------------------------
30 *
31 * Hence the machine layer should disable unsupported inputs/outputs by
32 * snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0), etc.
33 */
34
35#include <linux/module.h>
36#include <linux/moduleparam.h>
37#include <linux/init.h>
38#include <linux/delay.h>
39#include <linux/pm.h>
40#include <linux/i2c.h>
41#include <linux/platform_device.h>
42#include <sound/core.h>
43#include <sound/pcm.h>
44#include <sound/pcm_params.h>
45#include <sound/soc.h>
46#include <sound/soc-dapm.h>
47#include <sound/initval.h>
48
49#include "tlv320aic3x.h"
50
51#define AUDIO_NAME "aic3x"
52#define AIC3X_VERSION "0.1"
53
54/* codec private data */
55struct aic3x_priv {
56 unsigned int sysclk;
57 int master;
58};
59
60/*
61 * AIC3X register cache
62 * We can't read the AIC3X register space when we are
63 * using 2 wire for device control, so we cache them instead.
64 * There is no point in caching the reset register
65 */
66static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = {
67 0x00, 0x00, 0x00, 0x10, /* 0 */
68 0x04, 0x00, 0x00, 0x00, /* 4 */
69 0x00, 0x00, 0x00, 0x01, /* 8 */
70 0x00, 0x00, 0x00, 0x80, /* 12 */
71 0x80, 0xff, 0xff, 0x78, /* 16 */
72 0x78, 0x78, 0x78, 0x78, /* 20 */
73 0x78, 0x00, 0x00, 0xfe, /* 24 */
74 0x00, 0x00, 0xfe, 0x00, /* 28 */
75 0x18, 0x18, 0x00, 0x00, /* 32 */
76 0x00, 0x00, 0x00, 0x00, /* 36 */
77 0x00, 0x00, 0x00, 0x80, /* 40 */
78 0x80, 0x00, 0x00, 0x00, /* 44 */
79 0x00, 0x00, 0x00, 0x04, /* 48 */
80 0x00, 0x00, 0x00, 0x00, /* 52 */
81 0x00, 0x00, 0x04, 0x00, /* 56 */
82 0x00, 0x00, 0x00, 0x00, /* 60 */
83 0x00, 0x04, 0x00, 0x00, /* 64 */
84 0x00, 0x00, 0x00, 0x00, /* 68 */
85 0x04, 0x00, 0x00, 0x00, /* 72 */
86 0x00, 0x00, 0x00, 0x00, /* 76 */
87 0x00, 0x00, 0x00, 0x00, /* 80 */
88 0x00, 0x00, 0x00, 0x00, /* 84 */
89 0x00, 0x00, 0x00, 0x00, /* 88 */
90 0x00, 0x00, 0x00, 0x00, /* 92 */
91 0x00, 0x00, 0x00, 0x00, /* 96 */
92 0x00, 0x00, 0x02, /* 100 */
93};
94
95/*
96 * read aic3x register cache
97 */
98static inline unsigned int aic3x_read_reg_cache(struct snd_soc_codec *codec,
99 unsigned int reg)
100{
101 u8 *cache = codec->reg_cache;
102 if (reg >= AIC3X_CACHEREGNUM)
103 return -1;
104 return cache[reg];
105}
106
107/*
108 * write aic3x register cache
109 */
110static inline void aic3x_write_reg_cache(struct snd_soc_codec *codec,
111 u8 reg, u8 value)
112{
113 u8 *cache = codec->reg_cache;
114 if (reg >= AIC3X_CACHEREGNUM)
115 return;
116 cache[reg] = value;
117}
118
119/*
120 * write to the aic3x register space
121 */
122static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg,
123 unsigned int value)
124{
125 u8 data[2];
126
127 /* data is
128 * D15..D8 aic3x register offset
129 * D7...D0 register data
130 */
131 data[0] = reg & 0xff;
132 data[1] = value & 0xff;
133
134 aic3x_write_reg_cache(codec, data[0], data[1]);
135 if (codec->hw_write(codec->control_data, data, 2) == 2)
136 return 0;
137 else
138 return -EIO;
139}
140
141#define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \
142{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
143 .info = snd_soc_info_volsw, \
144 .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw_aic3x, \
145 .private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) }
146
147/*
148 * All input lines are connected when !0xf and disconnected with 0xf bit field,
149 * so we have to use specific dapm_put call for input mixer
150 */
151static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
152 struct snd_ctl_elem_value *ucontrol)
153{
154 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
155 int reg = kcontrol->private_value & 0xff;
156 int shift = (kcontrol->private_value >> 8) & 0x0f;
157 int mask = (kcontrol->private_value >> 16) & 0xff;
158 int invert = (kcontrol->private_value >> 24) & 0x01;
159 unsigned short val, val_mask;
160 int ret;
161 struct snd_soc_dapm_path *path;
162 int found = 0;
163
164 val = (ucontrol->value.integer.value[0] & mask);
165
166 mask = 0xf;
167 if (val)
168 val = mask;
169
170 if (invert)
171 val = mask - val;
172 val_mask = mask << shift;
173 val = val << shift;
174
175 mutex_lock(&widget->codec->mutex);
176
177 if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) {
178 /* find dapm widget path assoc with kcontrol */
179 list_for_each_entry(path, &widget->codec->dapm_paths, list) {
180 if (path->kcontrol != kcontrol)
181 continue;
182
183 /* found, now check type */
184 found = 1;
185 if (val)
186 /* new connection */
187 path->connect = invert ? 0 : 1;
188 else
189 /* old connection must be powered down */
190 path->connect = invert ? 1 : 0;
191 break;
192 }
193
194 if (found)
195 snd_soc_dapm_sync_endpoints(widget->codec);
196 }
197
198 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
199
200 mutex_unlock(&widget->codec->mutex);
201 return ret;
202}
203
204static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" };
205static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" };
206static const char *aic3x_left_hpcom_mux[] =
207 { "differential of HPLOUT", "constant VCM", "single-ended" };
208static const char *aic3x_right_hpcom_mux[] =
209 { "differential of HPROUT", "constant VCM", "single-ended",
210 "differential of HPLCOM", "external feedback" };
211static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" };
212
213#define LDAC_ENUM 0
214#define RDAC_ENUM 1
215#define LHPCOM_ENUM 2
216#define RHPCOM_ENUM 3
217#define LINE1L_ENUM 4
218#define LINE1R_ENUM 5
219#define LINE2L_ENUM 6
220#define LINE2R_ENUM 7
221
222static const struct soc_enum aic3x_enum[] = {
223 SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux),
224 SOC_ENUM_SINGLE(DAC_LINE_MUX, 4, 3, aic3x_right_dac_mux),
225 SOC_ENUM_SINGLE(HPLCOM_CFG, 4, 3, aic3x_left_hpcom_mux),
226 SOC_ENUM_SINGLE(HPRCOM_CFG, 3, 5, aic3x_right_hpcom_mux),
227 SOC_ENUM_SINGLE(LINE1L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux),
228 SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux),
229 SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux),
230 SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux),
231};
232
233static const struct snd_kcontrol_new aic3x_snd_controls[] = {
234 /* Output */
235 SOC_DOUBLE_R("PCM Playback Volume", LDAC_VOL, RDAC_VOL, 0, 0x7f, 1),
236
237 SOC_DOUBLE_R("Line DAC Playback Volume", DACL1_2_LLOPM_VOL,
238 DACR1_2_RLOPM_VOL, 0, 0x7f, 1),
239 SOC_DOUBLE_R("Line DAC Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3,
240 0x01, 0),
241 SOC_DOUBLE_R("Line PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL,
242 PGAR_2_RLOPM_VOL, 0, 0x7f, 1),
243 SOC_DOUBLE_R("Line Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL,
244 LINE2R_2_RLOPM_VOL, 0, 0x7f, 1),
245
246 SOC_DOUBLE_R("Mono DAC Playback Volume", DACL1_2_MONOLOPM_VOL,
247 DACR1_2_MONOLOPM_VOL, 0, 0x7f, 1),
248 SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
249 SOC_DOUBLE_R("Mono PGA Bypass Playback Volume", PGAL_2_MONOLOPM_VOL,
250 PGAR_2_MONOLOPM_VOL, 0, 0x7f, 1),
251 SOC_DOUBLE_R("Mono Line2 Bypass Playback Volume", LINE2L_2_MONOLOPM_VOL,
252 LINE2R_2_MONOLOPM_VOL, 0, 0x7f, 1),
253
254 SOC_DOUBLE_R("HP DAC Playback Volume", DACL1_2_HPLOUT_VOL,
255 DACR1_2_HPROUT_VOL, 0, 0x7f, 1),
256 SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
257 0x01, 0),
258 SOC_DOUBLE_R("HP PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL,
259 PGAR_2_HPROUT_VOL, 0, 0x7f, 1),
260 SOC_DOUBLE_R("HP Line2 Bypass Playback Volume", LINE2L_2_HPLOUT_VOL,
261 LINE2R_2_HPROUT_VOL, 0, 0x7f, 1),
262
263 SOC_DOUBLE_R("HPCOM DAC Playback Volume", DACL1_2_HPLCOM_VOL,
264 DACR1_2_HPRCOM_VOL, 0, 0x7f, 1),
265 SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
266 0x01, 0),
267 SOC_DOUBLE_R("HPCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL,
268 PGAR_2_HPRCOM_VOL, 0, 0x7f, 1),
269 SOC_DOUBLE_R("HPCOM Line2 Bypass Playback Volume", LINE2L_2_HPLCOM_VOL,
270 LINE2R_2_HPRCOM_VOL, 0, 0x7f, 1),
271
272 /*
273 * Note: enable Automatic input Gain Controller with care. It can
274 * adjust PGA to max value when ADC is on and will never go back.
275 */
276 SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0),
277
278 /* Input */
279 SOC_DOUBLE_R("PGA Capture Volume", LADC_VOL, RADC_VOL, 0, 0x7f, 0),
280 SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1),
281};
282
283/* add non dapm controls */
284static int aic3x_add_controls(struct snd_soc_codec *codec)
285{
286 int err, i;
287
288 for (i = 0; i < ARRAY_SIZE(aic3x_snd_controls); i++) {
289 err = snd_ctl_add(codec->card,
290 snd_soc_cnew(&aic3x_snd_controls[i],
291 codec, NULL));
292 if (err < 0)
293 return err;
294 }
295
296 return 0;
297}
298
299/* Left DAC Mux */
300static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
301SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]);
302
303/* Right DAC Mux */
304static const struct snd_kcontrol_new aic3x_right_dac_mux_controls =
305SOC_DAPM_ENUM("Route", aic3x_enum[RDAC_ENUM]);
306
307/* Left HPCOM Mux */
308static const struct snd_kcontrol_new aic3x_left_hpcom_mux_controls =
309SOC_DAPM_ENUM("Route", aic3x_enum[LHPCOM_ENUM]);
310
311/* Right HPCOM Mux */
312static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls =
313SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]);
314
315/* Left DAC_L1 Mixer */
316static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = {
317 SOC_DAPM_SINGLE("Line Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
318 SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0),
319 SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
320 SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
321};
322
323/* Right DAC_R1 Mixer */
324static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = {
325 SOC_DAPM_SINGLE("Line Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
326 SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0),
327 SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
328 SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
329};
330
331/* Left PGA Mixer */
332static const struct snd_kcontrol_new aic3x_left_pga_mixer_controls[] = {
333 SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1),
334 SOC_DAPM_SINGLE_AIC3X("Line2L Switch", LINE2L_2_LADC_CTRL, 3, 1, 1),
335 SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1),
336};
337
338/* Right PGA Mixer */
339static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = {
340 SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1),
341 SOC_DAPM_SINGLE_AIC3X("Line2R Switch", LINE2R_2_RADC_CTRL, 3, 1, 1),
342 SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1),
343};
344
345/* Left Line1 Mux */
346static const struct snd_kcontrol_new aic3x_left_line1_mux_controls =
347SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_ENUM]);
348
349/* Right Line1 Mux */
350static const struct snd_kcontrol_new aic3x_right_line1_mux_controls =
351SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_ENUM]);
352
353/* Left Line2 Mux */
354static const struct snd_kcontrol_new aic3x_left_line2_mux_controls =
355SOC_DAPM_ENUM("Route", aic3x_enum[LINE2L_ENUM]);
356
357/* Right Line2 Mux */
358static const struct snd_kcontrol_new aic3x_right_line2_mux_controls =
359SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]);
360
361/* Left PGA Bypass Mixer */
362static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = {
363 SOC_DAPM_SINGLE("Line Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
364 SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0),
365 SOC_DAPM_SINGLE("HP Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
366 SOC_DAPM_SINGLE("HPCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
367};
368
369/* Right PGA Bypass Mixer */
370static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = {
371 SOC_DAPM_SINGLE("Line Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
372 SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0),
373 SOC_DAPM_SINGLE("HP Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
374 SOC_DAPM_SINGLE("HPCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
375};
376
377/* Left Line2 Bypass Mixer */
378static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = {
379 SOC_DAPM_SINGLE("Line Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
380 SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0),
381 SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
382 SOC_DAPM_SINGLE("HPCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
383};
384
385/* Right Line2 Bypass Mixer */
386static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = {
387 SOC_DAPM_SINGLE("Line Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
388 SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0),
389 SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
390 SOC_DAPM_SINGLE("HPCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
391};
392
393static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
394 /* Left DAC to Left Outputs */
395 SND_SOC_DAPM_DAC("Left DAC", "Left Playback", DAC_PWR, 7, 0),
396 SND_SOC_DAPM_MUX("Left DAC Mux", SND_SOC_NOPM, 0, 0,
397 &aic3x_left_dac_mux_controls),
398 SND_SOC_DAPM_MIXER("Left DAC_L1 Mixer", SND_SOC_NOPM, 0, 0,
399 &aic3x_left_dac_mixer_controls[0],
400 ARRAY_SIZE(aic3x_left_dac_mixer_controls)),
401 SND_SOC_DAPM_MUX("Left HPCOM Mux", SND_SOC_NOPM, 0, 0,
402 &aic3x_left_hpcom_mux_controls),
403 SND_SOC_DAPM_PGA("Left Line Out", LLOPM_CTRL, 0, 0, NULL, 0),
404 SND_SOC_DAPM_PGA("Left HP Out", HPLOUT_CTRL, 0, 0, NULL, 0),
405 SND_SOC_DAPM_PGA("Left HP Com", HPLCOM_CTRL, 0, 0, NULL, 0),
406
407 /* Right DAC to Right Outputs */
408 SND_SOC_DAPM_DAC("Right DAC", "Right Playback", DAC_PWR, 6, 0),
409 SND_SOC_DAPM_MUX("Right DAC Mux", SND_SOC_NOPM, 0, 0,
410 &aic3x_right_dac_mux_controls),
411 SND_SOC_DAPM_MIXER("Right DAC_R1 Mixer", SND_SOC_NOPM, 0, 0,
412 &aic3x_right_dac_mixer_controls[0],
413 ARRAY_SIZE(aic3x_right_dac_mixer_controls)),
414 SND_SOC_DAPM_MUX("Right HPCOM Mux", SND_SOC_NOPM, 0, 0,
415 &aic3x_right_hpcom_mux_controls),
416 SND_SOC_DAPM_PGA("Right Line Out", RLOPM_CTRL, 0, 0, NULL, 0),
417 SND_SOC_DAPM_PGA("Right HP Out", HPROUT_CTRL, 0, 0, NULL, 0),
418 SND_SOC_DAPM_PGA("Right HP Com", HPRCOM_CTRL, 0, 0, NULL, 0),
419
420 /* Mono Output */
421 SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0),
422
423 /* Left Inputs to Left ADC */
424 SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0),
425 SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
426 &aic3x_left_pga_mixer_controls[0],
427 ARRAY_SIZE(aic3x_left_pga_mixer_controls)),
428 SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0,
429 &aic3x_left_line1_mux_controls),
430 SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0,
431 &aic3x_left_line2_mux_controls),
432
433 /* Right Inputs to Right ADC */
434 SND_SOC_DAPM_ADC("Right ADC", "Right Capture",
435 LINE1R_2_RADC_CTRL, 2, 0),
436 SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
437 &aic3x_right_pga_mixer_controls[0],
438 ARRAY_SIZE(aic3x_right_pga_mixer_controls)),
439 SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0,
440 &aic3x_right_line1_mux_controls),
441 SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0,
442 &aic3x_right_line2_mux_controls),
443
444 /* Mic Bias */
445 SND_SOC_DAPM_MICBIAS("Mic Bias 2V", MICBIAS_CTRL, 6, 0),
446 SND_SOC_DAPM_MICBIAS("Mic Bias 2.5V", MICBIAS_CTRL, 7, 0),
447 SND_SOC_DAPM_MICBIAS("Mic Bias AVDD", MICBIAS_CTRL, 6, 0),
448 SND_SOC_DAPM_MICBIAS("Mic Bias AVDD", MICBIAS_CTRL, 7, 0),
449
450 /* Left PGA to Left Output bypass */
451 SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0,
452 &aic3x_left_pga_bp_mixer_controls[0],
453 ARRAY_SIZE(aic3x_left_pga_bp_mixer_controls)),
454
455 /* Right PGA to Right Output bypass */
456 SND_SOC_DAPM_MIXER("Right PGA Bypass Mixer", SND_SOC_NOPM, 0, 0,
457 &aic3x_right_pga_bp_mixer_controls[0],
458 ARRAY_SIZE(aic3x_right_pga_bp_mixer_controls)),
459
460 /* Left Line2 to Left Output bypass */
461 SND_SOC_DAPM_MIXER("Left Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0,
462 &aic3x_left_line2_bp_mixer_controls[0],
463 ARRAY_SIZE(aic3x_left_line2_bp_mixer_controls)),
464
465 /* Right Line2 to Right Output bypass */
466 SND_SOC_DAPM_MIXER("Right Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0,
467 &aic3x_right_line2_bp_mixer_controls[0],
468 ARRAY_SIZE(aic3x_right_line2_bp_mixer_controls)),
469
470 SND_SOC_DAPM_OUTPUT("LLOUT"),
471 SND_SOC_DAPM_OUTPUT("RLOUT"),
472 SND_SOC_DAPM_OUTPUT("MONO_LOUT"),
473 SND_SOC_DAPM_OUTPUT("HPLOUT"),
474 SND_SOC_DAPM_OUTPUT("HPROUT"),
475 SND_SOC_DAPM_OUTPUT("HPLCOM"),
476 SND_SOC_DAPM_OUTPUT("HPRCOM"),
477
478 SND_SOC_DAPM_INPUT("MIC3L"),
479 SND_SOC_DAPM_INPUT("MIC3R"),
480 SND_SOC_DAPM_INPUT("LINE1L"),
481 SND_SOC_DAPM_INPUT("LINE1R"),
482 SND_SOC_DAPM_INPUT("LINE2L"),
483 SND_SOC_DAPM_INPUT("LINE2R"),
484};
485
486static const char *intercon[][3] = {
487 /* Left Output */
488 {"Left DAC Mux", "DAC_L1", "Left DAC"},
489 {"Left DAC Mux", "DAC_L2", "Left DAC"},
490 {"Left DAC Mux", "DAC_L3", "Left DAC"},
491
492 {"Left DAC_L1 Mixer", "Line Switch", "Left DAC Mux"},
493 {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"},
494 {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"},
495 {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"},
496 {"Left Line Out", NULL, "Left DAC Mux"},
497 {"Left HP Out", NULL, "Left DAC Mux"},
498
499 {"Left HPCOM Mux", "differential of HPLOUT", "Left DAC_L1 Mixer"},
500 {"Left HPCOM Mux", "constant VCM", "Left DAC_L1 Mixer"},
501 {"Left HPCOM Mux", "single-ended", "Left DAC_L1 Mixer"},
502
503 {"Left Line Out", NULL, "Left DAC_L1 Mixer"},
504 {"Mono Out", NULL, "Left DAC_L1 Mixer"},
505 {"Left HP Out", NULL, "Left DAC_L1 Mixer"},
506 {"Left HP Com", NULL, "Left HPCOM Mux"},
507
508 {"LLOUT", NULL, "Left Line Out"},
509 {"LLOUT", NULL, "Left Line Out"},
510 {"HPLOUT", NULL, "Left HP Out"},
511 {"HPLCOM", NULL, "Left HP Com"},
512
513 /* Right Output */
514 {"Right DAC Mux", "DAC_R1", "Right DAC"},
515 {"Right DAC Mux", "DAC_R2", "Right DAC"},
516 {"Right DAC Mux", "DAC_R3", "Right DAC"},
517
518 {"Right DAC_R1 Mixer", "Line Switch", "Right DAC Mux"},
519 {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"},
520 {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"},
521 {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"},
522 {"Right Line Out", NULL, "Right DAC Mux"},
523 {"Right HP Out", NULL, "Right DAC Mux"},
524
525 {"Right HPCOM Mux", "differential of HPROUT", "Right DAC_R1 Mixer"},
526 {"Right HPCOM Mux", "constant VCM", "Right DAC_R1 Mixer"},
527 {"Right HPCOM Mux", "single-ended", "Right DAC_R1 Mixer"},
528 {"Right HPCOM Mux", "differential of HPLCOM", "Right DAC_R1 Mixer"},
529 {"Right HPCOM Mux", "external feedback", "Right DAC_R1 Mixer"},
530
531 {"Right Line Out", NULL, "Right DAC_R1 Mixer"},
532 {"Mono Out", NULL, "Right DAC_R1 Mixer"},
533 {"Right HP Out", NULL, "Right DAC_R1 Mixer"},
534 {"Right HP Com", NULL, "Right HPCOM Mux"},
535
536 {"RLOUT", NULL, "Right Line Out"},
537 {"RLOUT", NULL, "Right Line Out"},
538 {"HPROUT", NULL, "Right HP Out"},
539 {"HPRCOM", NULL, "Right HP Com"},
540
541 /* Mono Output */
542 {"MONOLOUT", NULL, "Mono Out"},
543 {"MONOLOUT", NULL, "Mono Out"},
544
545 /* Left Input */
546 {"Left Line1L Mux", "single-ended", "LINE1L"},
547 {"Left Line1L Mux", "differential", "LINE1L"},
548
549 {"Left Line2L Mux", "single-ended", "LINE2L"},
550 {"Left Line2L Mux", "differential", "LINE2L"},
551
552 {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"},
553 {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"},
554 {"Left PGA Mixer", "Mic3L Switch", "MIC3L"},
555
556 {"Left ADC", NULL, "Left PGA Mixer"},
557
558 /* Right Input */
559 {"Right Line1R Mux", "single-ended", "LINE1R"},
560 {"Right Line1R Mux", "differential", "LINE1R"},
561
562 {"Right Line2R Mux", "single-ended", "LINE2R"},
563 {"Right Line2R Mux", "differential", "LINE2R"},
564
565 {"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"},
566 {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"},
567 {"Right PGA Mixer", "Mic3R Switch", "MIC3R"},
568
569 {"Right ADC", NULL, "Right PGA Mixer"},
570
571 /* Left PGA Bypass */
572 {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"},
573 {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"},
574 {"Left PGA Bypass Mixer", "HP Switch", "Left PGA Mixer"},
575 {"Left PGA Bypass Mixer", "HPCOM Switch", "Left PGA Mixer"},
576
577 {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"},
578 {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"},
579 {"Left HPCOM Mux", "single-ended", "Left PGA Bypass Mixer"},
580
581 {"Left Line Out", NULL, "Left PGA Bypass Mixer"},
582 {"Mono Out", NULL, "Left PGA Bypass Mixer"},
583 {"Left HP Out", NULL, "Left PGA Bypass Mixer"},
584
585 /* Right PGA Bypass */
586 {"Right PGA Bypass Mixer", "Line Switch", "Right PGA Mixer"},
587 {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"},
588 {"Right PGA Bypass Mixer", "HP Switch", "Right PGA Mixer"},
589 {"Right PGA Bypass Mixer", "HPCOM Switch", "Right PGA Mixer"},
590
591 {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"},
592 {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"},
593 {"Right HPCOM Mux", "single-ended", "Right PGA Bypass Mixer"},
594 {"Right HPCOM Mux", "differential of HPLCOM", "Right PGA Bypass Mixer"},
595 {"Right HPCOM Mux", "external feedback", "Right PGA Bypass Mixer"},
596
597 {"Right Line Out", NULL, "Right PGA Bypass Mixer"},
598 {"Mono Out", NULL, "Right PGA Bypass Mixer"},
599 {"Right HP Out", NULL, "Right PGA Bypass Mixer"},
600
601 /* Left Line2 Bypass */
602 {"Left Line2 Bypass Mixer", "Line Switch", "Left Line2L Mux"},
603 {"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"},
604 {"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"},
605 {"Left Line2 Bypass Mixer", "HPCOM Switch", "Left Line2L Mux"},
606
607 {"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"},
608 {"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"},
609 {"Left HPCOM Mux", "single-ended", "Left Line2 Bypass Mixer"},
610
611 {"Left Line Out", NULL, "Left Line2 Bypass Mixer"},
612 {"Mono Out", NULL, "Left Line2 Bypass Mixer"},
613 {"Left HP Out", NULL, "Left Line2 Bypass Mixer"},
614
615 /* Right Line2 Bypass */
616 {"Right Line2 Bypass Mixer", "Line Switch", "Right Line2R Mux"},
617 {"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"},
618 {"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"},
619 {"Right Line2 Bypass Mixer", "HPCOM Switch", "Right Line2R Mux"},
620
621 {"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"},
622 {"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"},
623 {"Right HPCOM Mux", "single-ended", "Right Line2 Bypass Mixer"},
624 {"Right HPCOM Mux", "differential of HPLCOM", "Right Line2 Bypass Mixer"},
625 {"Right HPCOM Mux", "external feedback", "Right Line2 Bypass Mixer"},
626
627 {"Right Line Out", NULL, "Right Line2 Bypass Mixer"},
628 {"Mono Out", NULL, "Right Line2 Bypass Mixer"},
629 {"Right HP Out", NULL, "Right Line2 Bypass Mixer"},
630
631 /* terminator */
632 {NULL, NULL, NULL},
633};
634
635static int aic3x_add_widgets(struct snd_soc_codec *codec)
636{
637 int i;
638
639 for (i = 0; i < ARRAY_SIZE(aic3x_dapm_widgets); i++)
640 snd_soc_dapm_new_control(codec, &aic3x_dapm_widgets[i]);
641
642 /* set up audio path interconnects */
643 for (i = 0; intercon[i][0] != NULL; i++)
644 snd_soc_dapm_connect_input(codec, intercon[i][0],
645 intercon[i][1], intercon[i][2]);
646
647 snd_soc_dapm_new_widgets(codec);
648 return 0;
649}
650
651struct aic3x_rate_divs {
652 u32 mclk;
653 u32 rate;
654 u32 fsref_reg;
655 u8 sr_reg:4;
656 u8 pllj_reg;
657 u16 plld_reg;
658};
659
660/* AIC3X codec mclk clock divider coefficients */
661static const struct aic3x_rate_divs aic3x_divs[] = {
662 /* 8k */
663 {22579200, 8000, 48000, 0xa, 8, 7075},
664 {33868800, 8000, 48000, 0xa, 5, 8049},
665 /* 11.025k */
666 {22579200, 11025, 44100, 0x6, 8, 0},
667 {33868800, 11025, 44100, 0x6, 5, 3333},
668 /* 16k */
669 {22579200, 16000, 48000, 0x4, 8, 7075},
670 {33868800, 16000, 48000, 0x4, 5, 8049},
671 /* 22.05k */
672 {22579200, 22050, 44100, 0x2, 8, 0},
673 {33868800, 22050, 44100, 0x2, 5, 3333},
674 /* 32k */
675 {22579200, 32000, 48000, 0x1, 8, 7075},
676 {33868800, 32000, 48000, 0x1, 5, 8049},
677 /* 44.1k */
678 {22579200, 44100, 44100, 0x0, 8, 0},
679 {33868800, 44100, 44100, 0x0, 5, 3333},
680 /* 48k */
681 {22579200, 48000, 48000, 0x0, 8, 7075},
682 {33868800, 48000, 48000, 0x0, 5, 8049},
683 /* 64k */
684 {22579200, 96000, 96000, 0x1, 8, 7075},
685 {33868800, 96000, 96000, 0x1, 5, 8049},
686 /* 88.2k */
687 {22579200, 88200, 88200, 0x0, 8, 0},
688 {33868800, 88200, 88200, 0x0, 5, 3333},
689 /* 96k */
690 {22579200, 96000, 96000, 0x0, 8, 7075},
691 {33868800, 96000, 96000, 0x0, 5, 8049},
692};
693
694static inline int aic3x_get_divs(int mclk, int rate)
695{
696 int i;
697
698 for (i = 0; i < ARRAY_SIZE(aic3x_divs); i++) {
699 if (aic3x_divs[i].rate == rate && aic3x_divs[i].mclk == mclk)
700 return i;
701 }
702
703 return 0;
704}
705
706static int aic3x_hw_params(struct snd_pcm_substream *substream,
707 struct snd_pcm_hw_params *params)
708{
709 struct snd_soc_pcm_runtime *rtd = substream->private_data;
710 struct snd_soc_device *socdev = rtd->socdev;
711 struct snd_soc_codec *codec = socdev->codec;
712 struct aic3x_priv *aic3x = codec->private_data;
713 int i;
714 u8 data, pll_p, pll_r, pll_j;
715 u16 pll_d;
716
717 i = aic3x_get_divs(aic3x->sysclk, params_rate(params));
718
719 /* Route Left DAC to left channel input and
720 * right DAC to right channel input */
721 data = (LDAC2LCH | RDAC2RCH);
722 switch (aic3x_divs[i].fsref_reg) {
723 case 44100:
724 data |= FSREF_44100;
725 break;
726 case 48000:
727 data |= FSREF_48000;
728 break;
729 case 88200:
730 data |= FSREF_44100 | DUAL_RATE_MODE;
731 break;
732 case 96000:
733 data |= FSREF_48000 | DUAL_RATE_MODE;
734 break;
735 }
736 aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data);
737
738 /* codec sample rate select */
739 data = aic3x_divs[i].sr_reg;
740 data |= (data << 4);
741 aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data);
742
743 /* Use PLL for generation Fsref by equation:
744 * Fsref = (MCLK * K * R)/(2048 * P);
745 * Fix P = 2 and R = 1 and calculate K, if
746 * K = J.D, i.e. J - an interger portion of K and D is the fractional
747 * one with 4 digits of precision;
748 * Example:
749 * For MCLK = 22.5792 MHz and Fsref = 48kHz:
750 * Select P = 2, R= 1, K = 8.7074, which results in J = 8, D = 7074
751 */
752 pll_p = 2;
753 pll_r = 1;
754 pll_j = aic3x_divs[i].pllj_reg;
755 pll_d = aic3x_divs[i].plld_reg;
756
757 data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
758 aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT));
759 aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT);
760 aic3x_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
761 aic3x_write(codec, AIC3X_PLL_PROGC_REG, (pll_d >> 6) << PLLD_MSB_SHIFT);
762 aic3x_write(codec, AIC3X_PLL_PROGD_REG,
763 (pll_d & 0x3F) << PLLD_LSB_SHIFT);
764
765 /* select data word length */
766 data =
767 aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
768 switch (params_format(params)) {
769 case SNDRV_PCM_FORMAT_S16_LE:
770 break;
771 case SNDRV_PCM_FORMAT_S20_3LE:
772 data |= (0x01 << 4);
773 break;
774 case SNDRV_PCM_FORMAT_S24_LE:
775 data |= (0x02 << 4);
776 break;
777 case SNDRV_PCM_FORMAT_S32_LE:
778 data |= (0x03 << 4);
779 break;
780 }
781 aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data);
782
783 return 0;
784}
785
786static int aic3x_mute(struct snd_soc_codec_dai *dai, int mute)
787{
788 struct snd_soc_codec *codec = dai->codec;
789 u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON;
790 u8 rdac_reg = aic3x_read_reg_cache(codec, RDAC_VOL) & ~MUTE_ON;
791
792 if (mute) {
793 aic3x_write(codec, LDAC_VOL, ldac_reg | MUTE_ON);
794 aic3x_write(codec, RDAC_VOL, rdac_reg | MUTE_ON);
795 } else {
796 aic3x_write(codec, LDAC_VOL, ldac_reg);
797 aic3x_write(codec, RDAC_VOL, rdac_reg);
798 }
799
800 return 0;
801}
802
803static int aic3x_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
804 int clk_id, unsigned int freq, int dir)
805{
806 struct snd_soc_codec *codec = codec_dai->codec;
807 struct aic3x_priv *aic3x = codec->private_data;
808
809 switch (freq) {
810 case 22579200:
811 case 33868800:
812 aic3x->sysclk = freq;
813 return 0;
814 }
815
816 return -EINVAL;
817}
818
819static int aic3x_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
820 unsigned int fmt)
821{
822 struct snd_soc_codec *codec = codec_dai->codec;
823 struct aic3x_priv *aic3x = codec->private_data;
824 u8 iface_areg = 0;
825 u8 iface_breg = 0;
826
827 /* set master/slave audio interface */
828 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
829 case SND_SOC_DAIFMT_CBM_CFM:
830 aic3x->master = 1;
831 iface_areg |= BIT_CLK_MASTER | WORD_CLK_MASTER;
832 break;
833 case SND_SOC_DAIFMT_CBS_CFS:
834 aic3x->master = 0;
835 break;
836 default:
837 return -EINVAL;
838 }
839
840 /* interface format */
841 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
842 case SND_SOC_DAIFMT_I2S:
843 break;
844 case SND_SOC_DAIFMT_DSP_A:
845 iface_breg |= (0x01 << 6);
846 break;
847 case SND_SOC_DAIFMT_RIGHT_J:
848 iface_breg |= (0x02 << 6);
849 break;
850 case SND_SOC_DAIFMT_LEFT_J:
851 iface_breg |= (0x03 << 6);
852 break;
853 default:
854 return -EINVAL;
855 }
856
857 /* set iface */
858 aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg);
859 aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg);
860
861 return 0;
862}
863
864static int aic3x_dapm_event(struct snd_soc_codec *codec, int event)
865{
866 struct aic3x_priv *aic3x = codec->private_data;
867 u8 reg;
868
869 switch (event) {
870 case SNDRV_CTL_POWER_D0:
871 /* all power is driven by DAPM system */
872 if (aic3x->master) {
873 /* enable pll */
874 reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
875 aic3x_write(codec, AIC3X_PLL_PROGA_REG,
876 reg | PLL_ENABLE);
877 }
878 break;
879 case SNDRV_CTL_POWER_D1:
880 case SNDRV_CTL_POWER_D2:
881 break;
882 case SNDRV_CTL_POWER_D3hot:
883 /*
884 * all power is driven by DAPM system,
885 * so output power is safe if bypass was set
886 */
887 if (aic3x->master) {
888 /* disable pll */
889 reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
890 aic3x_write(codec, AIC3X_PLL_PROGA_REG,
891 reg & ~PLL_ENABLE);
892 }
893 break;
894 case SNDRV_CTL_POWER_D3cold:
895 /* force all power off */
896 reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL);
897 aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON);
898 reg = aic3x_read_reg_cache(codec, LINE1R_2_RADC_CTRL);
899 aic3x_write(codec, LINE1R_2_RADC_CTRL, reg & ~RADC_PWR_ON);
900
901 reg = aic3x_read_reg_cache(codec, DAC_PWR);
902 aic3x_write(codec, DAC_PWR, reg & ~(LDAC_PWR_ON | RDAC_PWR_ON));
903
904 reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL);
905 aic3x_write(codec, HPLOUT_CTRL, reg & ~HPLOUT_PWR_ON);
906 reg = aic3x_read_reg_cache(codec, HPROUT_CTRL);
907 aic3x_write(codec, HPROUT_CTRL, reg & ~HPROUT_PWR_ON);
908
909 reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL);
910 aic3x_write(codec, HPLCOM_CTRL, reg & ~HPLCOM_PWR_ON);
911 reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL);
912 aic3x_write(codec, HPRCOM_CTRL, reg & ~HPRCOM_PWR_ON);
913
914 reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL);
915 aic3x_write(codec, MONOLOPM_CTRL, reg & ~MONOLOPM_PWR_ON);
916
917 reg = aic3x_read_reg_cache(codec, LLOPM_CTRL);
918 aic3x_write(codec, LLOPM_CTRL, reg & ~LLOPM_PWR_ON);
919 reg = aic3x_read_reg_cache(codec, RLOPM_CTRL);
920 aic3x_write(codec, RLOPM_CTRL, reg & ~RLOPM_PWR_ON);
921
922 if (aic3x->master) {
923 /* disable pll */
924 reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
925 aic3x_write(codec, AIC3X_PLL_PROGA_REG,
926 reg & ~PLL_ENABLE);
927 }
928 break;
929 }
930 codec->dapm_state = event;
931
932 return 0;
933}
934
935#define AIC3X_RATES SNDRV_PCM_RATE_8000_96000
936#define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
937 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
938
939struct snd_soc_codec_dai aic3x_dai = {
940 .name = "aic3x",
941 .playback = {
942 .stream_name = "Playback",
943 .channels_min = 1,
944 .channels_max = 2,
945 .rates = AIC3X_RATES,
946 .formats = AIC3X_FORMATS,},
947 .capture = {
948 .stream_name = "Capture",
949 .channels_min = 1,
950 .channels_max = 2,
951 .rates = AIC3X_RATES,
952 .formats = AIC3X_FORMATS,},
953 .ops = {
954 .hw_params = aic3x_hw_params,
955 },
956 .dai_ops = {
957 .digital_mute = aic3x_mute,
958 .set_sysclk = aic3x_set_dai_sysclk,
959 .set_fmt = aic3x_set_dai_fmt,
960 }
961};
962EXPORT_SYMBOL_GPL(aic3x_dai);
963
964static int aic3x_suspend(struct platform_device *pdev, pm_message_t state)
965{
966 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
967 struct snd_soc_codec *codec = socdev->codec;
968
969 aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
970
971 return 0;
972}
973
974static int aic3x_resume(struct platform_device *pdev)
975{
976 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
977 struct snd_soc_codec *codec = socdev->codec;
978 int i;
979 u8 data[2];
980 u8 *cache = codec->reg_cache;
981
982 /* Sync reg_cache with the hardware */
983 for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) {
984 data[0] = i;
985 data[1] = cache[i];
986 codec->hw_write(codec->control_data, data, 2);
987 }
988
989 aic3x_dapm_event(codec, codec->suspend_dapm_state);
990
991 return 0;
992}
993
994/*
995 * initialise the AIC3X driver
996 * register the mixer and dsp interfaces with the kernel
997 */
998static int aic3x_init(struct snd_soc_device *socdev)
999{
1000 struct snd_soc_codec *codec = socdev->codec;
1001 int reg, ret = 0;
1002
1003 codec->name = "aic3x";
1004 codec->owner = THIS_MODULE;
1005 codec->read = aic3x_read_reg_cache;
1006 codec->write = aic3x_write;
1007 codec->dapm_event = aic3x_dapm_event;
1008 codec->dai = &aic3x_dai;
1009 codec->num_dai = 1;
1010 codec->reg_cache_size = sizeof(aic3x_reg);
1011 codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL);
1012 if (codec->reg_cache == NULL)
1013 return -ENOMEM;
1014
1015 aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
1016 aic3x_write(codec, AIC3X_RESET, SOFT_RESET);
1017
1018 /* register pcms */
1019 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
1020 if (ret < 0) {
1021 printk(KERN_ERR "aic3x: failed to create pcms\n");
1022 goto pcm_err;
1023 }
1024
1025 /* DAC default volume and mute */
1026 aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON);
1027 aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON);
1028
1029 /* DAC to HP default volume and route to Output mixer */
1030 aic3x_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON);
1031 aic3x_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON);
1032 aic3x_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON);
1033 aic3x_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON);
1034 /* DAC to Line Out default volume and route to Output mixer */
1035 aic3x_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
1036 aic3x_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
1037 /* DAC to Mono Line Out default volume and route to Output mixer */
1038 aic3x_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
1039 aic3x_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
1040
1041 /* unmute all outputs */
1042 reg = aic3x_read_reg_cache(codec, LLOPM_CTRL);
1043 aic3x_write(codec, LLOPM_CTRL, reg | UNMUTE);
1044 reg = aic3x_read_reg_cache(codec, RLOPM_CTRL);
1045 aic3x_write(codec, RLOPM_CTRL, reg | UNMUTE);
1046 reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL);
1047 aic3x_write(codec, MONOLOPM_CTRL, reg | UNMUTE);
1048 reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL);
1049 aic3x_write(codec, HPLOUT_CTRL, reg | UNMUTE);
1050 reg = aic3x_read_reg_cache(codec, HPROUT_CTRL);
1051 aic3x_write(codec, HPROUT_CTRL, reg | UNMUTE);
1052 reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL);
1053 aic3x_write(codec, HPLCOM_CTRL, reg | UNMUTE);
1054 reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL);
1055 aic3x_write(codec, HPRCOM_CTRL, reg | UNMUTE);
1056
1057 /* ADC default volume and unmute */
1058 aic3x_write(codec, LADC_VOL, DEFAULT_GAIN);
1059 aic3x_write(codec, RADC_VOL, DEFAULT_GAIN);
1060 /* By default route Line1 to ADC PGA mixer */
1061 aic3x_write(codec, LINE1L_2_LADC_CTRL, 0x0);
1062 aic3x_write(codec, LINE1R_2_RADC_CTRL, 0x0);
1063
1064 /* PGA to HP Bypass default volume, disconnect from Output Mixer */
1065 aic3x_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL);
1066 aic3x_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL);
1067 aic3x_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL);
1068 aic3x_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL);
1069 /* PGA to Line Out default volume, disconnect from Output Mixer */
1070 aic3x_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
1071 aic3x_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
1072 /* PGA to Mono Line Out default volume, disconnect from Output Mixer */
1073 aic3x_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
1074 aic3x_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
1075
1076 /* Line2 to HP Bypass default volume, disconnect from Output Mixer */
1077 aic3x_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
1078 aic3x_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL);
1079 aic3x_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL);
1080 aic3x_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL);
1081 /* Line2 Line Out default volume, disconnect from Output Mixer */
1082 aic3x_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
1083 aic3x_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
1084 /* Line2 to Mono Out default volume, disconnect from Output Mixer */
1085 aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
1086 aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
1087
1088 /* off, with power on */
1089 aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
1090
1091 aic3x_add_controls(codec);
1092 aic3x_add_widgets(codec);
1093 ret = snd_soc_register_card(socdev);
1094 if (ret < 0) {
1095 printk(KERN_ERR "aic3x: failed to register card\n");
1096 goto card_err;
1097 }
1098
1099 return ret;
1100
1101card_err:
1102 snd_soc_free_pcms(socdev);
1103 snd_soc_dapm_free(socdev);
1104pcm_err:
1105 kfree(codec->reg_cache);
1106 return ret;
1107}
1108
1109static struct snd_soc_device *aic3x_socdev;
1110
1111#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1112/*
1113 * AIC3X 2 wire address can be up to 4 devices with device addresses
1114 * 0x18, 0x19, 0x1A, 0x1B
1115 */
1116static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
1117
1118/* Magic definition of all other variables and things */
1119I2C_CLIENT_INSMOD;
1120
1121static struct i2c_driver aic3x_i2c_driver;
1122static struct i2c_client client_template;
1123
1124/*
1125 * If the i2c layer weren't so broken, we could pass this kind of data
1126 * around
1127 */
1128static int aic3x_codec_probe(struct i2c_adapter *adap, int addr, int kind)
1129{
1130 struct snd_soc_device *socdev = aic3x_socdev;
1131 struct aic3x_setup_data *setup = socdev->codec_data;
1132 struct snd_soc_codec *codec = socdev->codec;
1133 struct i2c_client *i2c;
1134 int ret;
1135
1136 if (addr != setup->i2c_address)
1137 return -ENODEV;
1138
1139 client_template.adapter = adap;
1140 client_template.addr = addr;
1141
1142 i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
1143 if (i2c == NULL) {
1144 kfree(codec);
1145 return -ENOMEM;
1146 }
1147 i2c_set_clientdata(i2c, codec);
1148 codec->control_data = i2c;
1149
1150 ret = i2c_attach_client(i2c);
1151 if (ret < 0) {
1152 printk(KERN_ERR "aic3x: failed to attach codec at addr %x\n",
1153 addr);
1154 goto err;
1155 }
1156
1157 ret = aic3x_init(socdev);
1158 if (ret < 0) {
1159 printk(KERN_ERR "aic3x: failed to initialise AIC3X\n");
1160 goto err;
1161 }
1162 return ret;
1163
1164err:
1165 kfree(codec);
1166 kfree(i2c);
1167 return ret;
1168}
1169
1170static int aic3x_i2c_detach(struct i2c_client *client)
1171{
1172 struct snd_soc_codec *codec = i2c_get_clientdata(client);
1173 i2c_detach_client(client);
1174 kfree(codec->reg_cache);
1175 kfree(client);
1176 return 0;
1177}
1178
1179static int aic3x_i2c_attach(struct i2c_adapter *adap)
1180{
1181 return i2c_probe(adap, &addr_data, aic3x_codec_probe);
1182}
1183
1184/* machine i2c codec control layer */
1185static struct i2c_driver aic3x_i2c_driver = {
1186 .driver = {
1187 .name = "aic3x I2C Codec",
1188 .owner = THIS_MODULE,
1189 },
1190 .id = I2C_DRIVERID_I2CDEV,
1191 .attach_adapter = aic3x_i2c_attach,
1192 .detach_client = aic3x_i2c_detach,
1193 .command = NULL,
1194};
1195
1196static struct i2c_client client_template = {
1197 .name = "AIC3X",
1198 .driver = &aic3x_i2c_driver,
1199};
1200#endif
1201
1202static int aic3x_probe(struct platform_device *pdev)
1203{
1204 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1205 struct aic3x_setup_data *setup;
1206 struct snd_soc_codec *codec;
1207 struct aic3x_priv *aic3x;
1208 int ret = 0;
1209
1210 printk(KERN_INFO "AIC3X Audio Codec %s\n", AIC3X_VERSION);
1211
1212 setup = socdev->codec_data;
1213 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
1214 if (codec == NULL)
1215 return -ENOMEM;
1216
1217 aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
1218 if (aic3x == NULL) {
1219 kfree(codec);
1220 return -ENOMEM;
1221 }
1222
1223 codec->private_data = aic3x;
1224 socdev->codec = codec;
1225 mutex_init(&codec->mutex);
1226 INIT_LIST_HEAD(&codec->dapm_widgets);
1227 INIT_LIST_HEAD(&codec->dapm_paths);
1228
1229 aic3x_socdev = socdev;
1230#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1231 if (setup->i2c_address) {
1232 normal_i2c[0] = setup->i2c_address;
1233 codec->hw_write = (hw_write_t) i2c_master_send;
1234 ret = i2c_add_driver(&aic3x_i2c_driver);
1235 if (ret != 0)
1236 printk(KERN_ERR "can't add i2c driver");
1237 }
1238#else
1239 /* Add other interfaces here */
1240#endif
1241 return ret;
1242}
1243
1244static int aic3x_remove(struct platform_device *pdev)
1245{
1246 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1247 struct snd_soc_codec *codec = socdev->codec;
1248
1249 /* power down chip */
1250 if (codec->control_data)
1251 aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3);
1252
1253 snd_soc_free_pcms(socdev);
1254 snd_soc_dapm_free(socdev);
1255#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1256 i2c_del_driver(&aic3x_i2c_driver);
1257#endif
1258 kfree(codec->private_data);
1259 kfree(codec);
1260
1261 return 0;
1262}
1263
1264struct snd_soc_codec_device soc_codec_dev_aic3x = {
1265 .probe = aic3x_probe,
1266 .remove = aic3x_remove,
1267 .suspend = aic3x_suspend,
1268 .resume = aic3x_resume,
1269};
1270EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x);
1271
1272MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver");
1273MODULE_AUTHOR("Vladimir Barinov");
1274MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
new file mode 100644
index 000000000000..d0cdeeb629de
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -0,0 +1,181 @@
1/*
2 * ALSA SoC TLV320AIC3X codec driver
3 *
4 * Author: Vladimir Barinov, <vbarinov@ru.mvista.com>
5 * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#ifndef _AIC3X_H
13#define _AIC3X_H
14
15/* AIC3X register space */
16#define AIC3X_CACHEREGNUM 103
17
18/* Page select register */
19#define AIC3X_PAGE_SELECT 0
20/* Software reset register */
21#define AIC3X_RESET 1
22/* Codec Sample rate select register */
23#define AIC3X_SAMPLE_RATE_SEL_REG 2
24/* PLL progrramming register A */
25#define AIC3X_PLL_PROGA_REG 3
26/* PLL progrramming register B */
27#define AIC3X_PLL_PROGB_REG 4
28/* PLL progrramming register C */
29#define AIC3X_PLL_PROGC_REG 5
30/* PLL progrramming register D */
31#define AIC3X_PLL_PROGD_REG 6
32/* Codec datapath setup register */
33#define AIC3X_CODEC_DATAPATH_REG 7
34/* Audio serial data interface control register A */
35#define AIC3X_ASD_INTF_CTRLA 8
36/* Audio serial data interface control register B */
37#define AIC3X_ASD_INTF_CTRLB 9
38/* Audio overflow status and PLL R value programming register */
39#define AIC3X_OVRF_STATUS_AND_PLLR_REG 11
40
41/* ADC PGA Gain control registers */
42#define LADC_VOL 15
43#define RADC_VOL 16
44/* MIC3 control registers */
45#define MIC3LR_2_LADC_CTRL 17
46#define MIC3LR_2_RADC_CTRL 18
47/* Line1 Input control registers */
48#define LINE1L_2_LADC_CTRL 19
49#define LINE1R_2_RADC_CTRL 22
50/* Line2 Input control registers */
51#define LINE2L_2_LADC_CTRL 20
52#define LINE2R_2_RADC_CTRL 23
53/* MICBIAS Control Register */
54#define MICBIAS_CTRL 25
55
56/* AGC Control Registers A, B, C */
57#define LAGC_CTRL_A 26
58#define LAGC_CTRL_B 27
59#define LAGC_CTRL_C 28
60#define RAGC_CTRL_A 29
61#define RAGC_CTRL_B 30
62#define RAGC_CTRL_C 31
63
64/* DAC Power and Left High Power Output control registers */
65#define DAC_PWR 37
66#define HPLCOM_CFG 37
67/* Right High Power Output control registers */
68#define HPRCOM_CFG 38
69/* DAC Output Switching control registers */
70#define DAC_LINE_MUX 41
71/* High Power Output Driver Pop Reduction registers */
72#define HPOUT_POP_REDUCTION 42
73/* DAC Digital control registers */
74#define LDAC_VOL 43
75#define RDAC_VOL 44
76/* High Power Output control registers */
77#define LINE2L_2_HPLOUT_VOL 45
78#define LINE2R_2_HPROUT_VOL 62
79#define PGAL_2_HPLOUT_VOL 46
80#define PGAR_2_HPROUT_VOL 63
81#define DACL1_2_HPLOUT_VOL 47
82#define DACR1_2_HPROUT_VOL 64
83#define HPLOUT_CTRL 51
84#define HPROUT_CTRL 65
85/* High Power COM control registers */
86#define LINE2L_2_HPLCOM_VOL 52
87#define LINE2R_2_HPRCOM_VOL 69
88#define PGAL_2_HPLCOM_VOL 53
89#define PGAR_2_HPRCOM_VOL 70
90#define DACL1_2_HPLCOM_VOL 54
91#define DACR1_2_HPRCOM_VOL 71
92#define HPLCOM_CTRL 58
93#define HPRCOM_CTRL 72
94/* Mono Line Output Plus/Minus control registers */
95#define LINE2L_2_MONOLOPM_VOL 73
96#define LINE2R_2_MONOLOPM_VOL 76
97#define PGAL_2_MONOLOPM_VOL 74
98#define PGAR_2_MONOLOPM_VOL 77
99#define DACL1_2_MONOLOPM_VOL 75
100#define DACR1_2_MONOLOPM_VOL 78
101#define MONOLOPM_CTRL 79
102/* Line Output Plus/Minus control registers */
103#define LINE2L_2_LLOPM_VOL 80
104#define LINE2R_2_RLOPM_VOL 90
105#define PGAL_2_LLOPM_VOL 81
106#define PGAR_2_RLOPM_VOL 91
107#define DACL1_2_LLOPM_VOL 82
108#define DACR1_2_RLOPM_VOL 92
109#define LLOPM_CTRL 86
110#define RLOPM_CTRL 93
111/* Clock generation control register */
112#define AIC3X_CLKGEN_CTRL_REG 102
113
114/* Page select register bits */
115#define PAGE0_SELECT 0
116#define PAGE1_SELECT 1
117
118/* Audio serial data interface control register A bits */
119#define BIT_CLK_MASTER 0x80
120#define WORD_CLK_MASTER 0x40
121
122/* Codec Datapath setup register 7 */
123#define FSREF_44100 (1 << 7)
124#define FSREF_48000 (0 << 7)
125#define DUAL_RATE_MODE ((1 << 5) | (1 << 6))
126#define LDAC2LCH (0x1 << 3)
127#define RDAC2RCH (0x1 << 1)
128
129/* PLL registers bitfields */
130#define PLLP_SHIFT 0
131#define PLLR_SHIFT 0
132#define PLLJ_SHIFT 2
133#define PLLD_MSB_SHIFT 0
134#define PLLD_LSB_SHIFT 2
135
136/* Clock generation register bits */
137#define PLL_CLKIN_SHIFT 4
138#define MCLK_SOURCE 0x0
139#define PLL_CLKDIV_SHIFT 0
140
141/* Software reset register bits */
142#define SOFT_RESET 0x80
143
144/* PLL progrramming register A bits */
145#define PLL_ENABLE 0x80
146
147/* Route bits */
148#define ROUTE_ON 0x80
149
150/* Mute bits */
151#define UNMUTE 0x08
152#define MUTE_ON 0x80
153
154/* Power bits */
155#define LADC_PWR_ON 0x04
156#define RADC_PWR_ON 0x04
157#define LDAC_PWR_ON 0x80
158#define RDAC_PWR_ON 0x40
159#define HPLOUT_PWR_ON 0x01
160#define HPROUT_PWR_ON 0x01
161#define HPLCOM_PWR_ON 0x01
162#define HPRCOM_PWR_ON 0x01
163#define MONOLOPM_PWR_ON 0x01
164#define LLOPM_PWR_ON 0x01
165#define RLOPM_PWR_ON 0x01
166
167#define INVERT_VOL(val) (0x7f - val)
168
169/* Default output volume (inverted) */
170#define DEFAULT_VOL INVERT_VOL(0x50)
171/* Default input volume */
172#define DEFAULT_GAIN 0x20
173
174struct aic3x_setup_data {
175 unsigned short i2c_address;
176};
177
178extern struct snd_soc_codec_dai aic3x_dai;
179extern struct snd_soc_codec_device soc_codec_dev_aic3x;
180
181#endif /* _AIC3X_H */
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 7ca0b5268289..9c33fe874928 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -19,7 +19,6 @@
19#include <linux/pm.h> 19#include <linux/pm.h>
20#include <linux/i2c.h> 20#include <linux/i2c.h>
21#include <linux/platform_device.h> 21#include <linux/platform_device.h>
22#include <sound/driver.h>
23#include <sound/core.h> 22#include <sound/core.h>
24#include <sound/pcm.h> 23#include <sound/pcm.h>
25#include <sound/pcm_params.h> 24#include <sound/pcm_params.h>
@@ -562,13 +561,13 @@ static int wm8731_init(struct snd_soc_device *socdev)
562 561
563 /* set the update bits */ 562 /* set the update bits */
564 reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); 563 reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V);
565 wm8731_write(codec, WM8731_LOUT1V, reg | 0x0100); 564 wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100);
566 reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V); 565 reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V);
567 wm8731_write(codec, WM8731_ROUT1V, reg | 0x0100); 566 wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100);
568 reg = wm8731_read_reg_cache(codec, WM8731_LINVOL); 567 reg = wm8731_read_reg_cache(codec, WM8731_LINVOL);
569 wm8731_write(codec, WM8731_LINVOL, reg | 0x0100); 568 wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100);
570 reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); 569 reg = wm8731_read_reg_cache(codec, WM8731_RINVOL);
571 wm8731_write(codec, WM8731_RINVOL, reg | 0x0100); 570 wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100);
572 571
573 wm8731_add_controls(codec); 572 wm8731_add_controls(codec);
574 wm8731_add_widgets(codec); 573 wm8731_add_widgets(codec);
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 28684eeda738..77a857b997a2 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -19,7 +19,6 @@
19#include <linux/pm.h> 19#include <linux/pm.h>
20#include <linux/i2c.h> 20#include <linux/i2c.h>
21#include <linux/platform_device.h> 21#include <linux/platform_device.h>
22#include <sound/driver.h>
23#include <sound/core.h> 22#include <sound/core.h>
24#include <sound/pcm.h> 23#include <sound/pcm.h>
25#include <sound/pcm_params.h> 24#include <sound/pcm_params.h>
@@ -189,7 +188,7 @@ SOC_ENUM("Bass Boost", wm8750_enum[0]),
189SOC_ENUM("Bass Filter", wm8750_enum[1]), 188SOC_ENUM("Bass Filter", wm8750_enum[1]),
190SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1), 189SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1),
191 190
192SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 0), 191SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 1),
193SOC_ENUM("Treble Cut-off", wm8750_enum[2]), 192SOC_ENUM("Treble Cut-off", wm8750_enum[2]),
194 193
195SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0), 194SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0),
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index efced934566d..ddd9c71b3fde 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -41,13 +41,13 @@
41#include <linux/pm.h> 41#include <linux/pm.h>
42#include <linux/i2c.h> 42#include <linux/i2c.h>
43#include <linux/platform_device.h> 43#include <linux/platform_device.h>
44#include <sound/driver.h>
45#include <sound/core.h> 44#include <sound/core.h>
46#include <sound/pcm.h> 45#include <sound/pcm.h>
47#include <sound/pcm_params.h> 46#include <sound/pcm_params.h>
48#include <sound/soc.h> 47#include <sound/soc.h>
49#include <sound/soc-dapm.h> 48#include <sound/soc-dapm.h>
50#include <sound/initval.h> 49#include <sound/initval.h>
50#include <sound/tlv.h>
51#include <asm/div64.h> 51#include <asm/div64.h>
52 52
53#include "wm8753.h" 53#include "wm8753.h"
@@ -258,6 +258,8 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
258 return 1; 258 return 1;
259} 259}
260 260
261static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600);
262
261static const struct snd_kcontrol_new wm8753_snd_controls[] = { 263static const struct snd_kcontrol_new wm8753_snd_controls[] = {
262SOC_DOUBLE_R("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0), 264SOC_DOUBLE_R("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0),
263 265
@@ -287,8 +289,8 @@ SOC_SINGLE("Bass Volume", WM8753_BASS, 0, 15, 1),
287SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1), 289SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1),
288SOC_ENUM("Treble Cut-off", wm8753_enum[2]), 290SOC_ENUM("Treble Cut-off", wm8753_enum[2]),
289 291
290SOC_DOUBLE("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1), 292SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1, rec_mix_tlv),
291SOC_SINGLE("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1), 293SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1, rec_mix_tlv),
292 294
293SOC_DOUBLE_R("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0), 295SOC_DOUBLE_R("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0),
294SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0), 296SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0),
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 986b5d59cefa..590baea3c4c3 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -19,7 +19,6 @@
19#include <linux/version.h> 19#include <linux/version.h>
20#include <linux/kernel.h> 20#include <linux/kernel.h>
21#include <linux/device.h> 21#include <linux/device.h>
22#include <sound/driver.h>
23#include <sound/core.h> 22#include <sound/core.h>
24#include <sound/pcm.h> 23#include <sound/pcm.h>
25#include <sound/ac97_codec.h> 24#include <sound/ac97_codec.h>
@@ -102,7 +101,8 @@ SOC_SINGLE("Speaker Playback ZC Switch", AC97_MASTER, 7, 1, 0),
102SOC_SINGLE("Speaker Playback Invert Switch", AC97_MASTER, 6, 1, 0), 101SOC_SINGLE("Speaker Playback Invert Switch", AC97_MASTER, 6, 1, 0),
103SOC_SINGLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 7, 1, 0), 102SOC_SINGLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 7, 1, 0),
104SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_MONO, 7, 1, 0), 103SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_MONO, 7, 1, 0),
105SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 0), 104SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1),
105SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
106 106
107SOC_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0), 107SOC_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
108SOC_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0), 108SOC_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
@@ -131,7 +131,7 @@ SOC_SINGLE("Aux Playback Headphone Volume", AC97_CD, 12, 7, 1),
131SOC_SINGLE("Aux Playback Speaker Volume", AC97_CD, 8, 7, 1), 131SOC_SINGLE("Aux Playback Speaker Volume", AC97_CD, 8, 7, 1),
132SOC_SINGLE("Aux Playback Phone Volume", AC97_CD, 4, 7, 1), 132SOC_SINGLE("Aux Playback Phone Volume", AC97_CD, 4, 7, 1),
133 133
134SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 0), 134SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 1),
135SOC_DOUBLE("Line Capture Volume", AC97_LINE, 8, 0, 31, 1), 135SOC_DOUBLE("Line Capture Volume", AC97_LINE, 8, 0, 31, 1),
136 136
137SOC_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0), 137SOC_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0),
@@ -145,8 +145,8 @@ SOC_ENUM("Bass Control", wm9712_enum[5]),
145SOC_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1), 145SOC_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1),
146SOC_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1), 146SOC_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1),
147SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0), 147SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0),
148SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 0), 148SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 1),
149SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 0), 149SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 1),
150 150
151SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1), 151SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1),
152SOC_ENUM("Capture Volume Steps", wm9712_enum[6]), 152SOC_ENUM("Capture Volume Steps", wm9712_enum[6]),
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
new file mode 100644
index 000000000000..257101f44e9e
--- /dev/null
+++ b/sound/soc/fsl/Kconfig
@@ -0,0 +1,20 @@
1menu "ALSA SoC audio for Freescale SOCs"
2
3config SND_SOC_MPC8610
4 bool "ALSA SoC support for the MPC8610 SOC"
5 depends on SND_SOC && MPC8610_HPCD
6 default y if MPC8610
7 help
8 Say Y if you want to add support for codecs attached to the SSI
9 device on an MPC8610.
10
11config SND_SOC_MPC8610_HPCD
12 bool "ALSA SoC support for the Freescale MPC8610 HPCD board"
13 depends on SND_SOC_MPC8610
14 select SND_SOC_CS4270
15 select SND_SOC_CS4270_VD33_ERRATA
16 default y if MPC8610_HPCD
17 help
18 Say Y if you want to enable audio on the Freescale MPC8610 HPCD.
19
20endmenu
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
new file mode 100644
index 000000000000..62f680a4a776
--- /dev/null
+++ b/sound/soc/fsl/Makefile
@@ -0,0 +1,6 @@
1# MPC8610 HPCD Machine Support
2obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += mpc8610_hpcd.o
3
4# MPC8610 Platform Support
5obj-$(CONFIG_SND_SOC_MPC8610) += fsl_ssi.o fsl_dma.o
6
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
new file mode 100644
index 000000000000..652514fc8142
--- /dev/null
+++ b/sound/soc/fsl/fsl_dma.c
@@ -0,0 +1,841 @@
1/*
2 * Freescale DMA ALSA SoC PCM driver
3 *
4 * Author: Timur Tabi <timur@freescale.com>
5 *
6 * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed
7 * under the terms of the GNU General Public License version 2. This
8 * program is licensed "as is" without any warranty of any kind, whether
9 * express or implied.
10 *
11 * This driver implements ASoC support for the Elo DMA controller, which is
12 * the DMA controller on Freescale 83xx, 85xx, and 86xx SOCs. In ALSA terms,
13 * the PCM driver is what handles the DMA buffer.
14 */
15
16#include <linux/module.h>
17#include <linux/init.h>
18#include <linux/platform_device.h>
19#include <linux/dma-mapping.h>
20#include <linux/interrupt.h>
21#include <linux/delay.h>
22
23#include <sound/driver.h>
24#include <sound/core.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/soc.h>
28
29#include <asm/io.h>
30
31#include "fsl_dma.h"
32
33/*
34 * The formats that the DMA controller supports, which is anything
35 * that is 8, 16, or 32 bits.
36 */
37#define FSLDMA_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
38 SNDRV_PCM_FMTBIT_U8 | \
39 SNDRV_PCM_FMTBIT_S16_LE | \
40 SNDRV_PCM_FMTBIT_S16_BE | \
41 SNDRV_PCM_FMTBIT_U16_LE | \
42 SNDRV_PCM_FMTBIT_U16_BE | \
43 SNDRV_PCM_FMTBIT_S24_LE | \
44 SNDRV_PCM_FMTBIT_S24_BE | \
45 SNDRV_PCM_FMTBIT_U24_LE | \
46 SNDRV_PCM_FMTBIT_U24_BE | \
47 SNDRV_PCM_FMTBIT_S32_LE | \
48 SNDRV_PCM_FMTBIT_S32_BE | \
49 SNDRV_PCM_FMTBIT_U32_LE | \
50 SNDRV_PCM_FMTBIT_U32_BE)
51
52#define FSLDMA_PCM_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
53 SNDRV_PCM_RATE_CONTINUOUS)
54
55/* DMA global data. This structure is used by fsl_dma_open() to determine
56 * which DMA channels to assign to a substream. Unfortunately, ASoC V1 does
57 * not allow the machine driver to provide this information to the PCM
58 * driver in advance, and there's no way to differentiate between the two
59 * DMA controllers. So for now, this driver only supports one SSI device
60 * using two DMA channels. We cannot support multiple DMA devices.
61 *
62 * ssi_stx_phys: bus address of SSI STX register
63 * ssi_srx_phys: bus address of SSI SRX register
64 * dma_channel: pointer to the DMA channel's registers
65 * irq: IRQ for this DMA channel
66 * assigned: set to 1 if that DMA channel is assigned to a substream
67 */
68static struct {
69 dma_addr_t ssi_stx_phys;
70 dma_addr_t ssi_srx_phys;
71 struct ccsr_dma_channel __iomem *dma_channel[2];
72 unsigned int irq[2];
73 unsigned int assigned[2];
74} dma_global_data;
75
76/*
77 * The number of DMA links to use. Two is the bare minimum, but if you
78 * have really small links you might need more.
79 */
80#define NUM_DMA_LINKS 2
81
82/** fsl_dma_private: p-substream DMA data
83 *
84 * Each substream has a 1-to-1 association with a DMA channel.
85 *
86 * The link[] array is first because it needs to be aligned on a 32-byte
87 * boundary, so putting it first will ensure alignment without padding the
88 * structure.
89 *
90 * @link[]: array of link descriptors
91 * @controller_id: which DMA controller (0, 1, ...)
92 * @channel_id: which DMA channel on the controller (0, 1, 2, ...)
93 * @dma_channel: pointer to the DMA channel's registers
94 * @irq: IRQ for this DMA channel
95 * @substream: pointer to the substream object, needed by the ISR
96 * @ssi_sxx_phys: bus address of the STX or SRX register to use
97 * @ld_buf_phys: physical address of the LD buffer
98 * @current_link: index into link[] of the link currently being processed
99 * @dma_buf_phys: physical address of the DMA buffer
100 * @dma_buf_next: physical address of the next period to process
101 * @dma_buf_end: physical address of the byte after the end of the DMA
102 * @buffer period_size: the size of a single period
103 * @num_periods: the number of periods in the DMA buffer
104 */
105struct fsl_dma_private {
106 struct fsl_dma_link_descriptor link[NUM_DMA_LINKS];
107 unsigned int controller_id;
108 unsigned int channel_id;
109 struct ccsr_dma_channel __iomem *dma_channel;
110 unsigned int irq;
111 struct snd_pcm_substream *substream;
112 dma_addr_t ssi_sxx_phys;
113 dma_addr_t ld_buf_phys;
114 unsigned int current_link;
115 dma_addr_t dma_buf_phys;
116 dma_addr_t dma_buf_next;
117 dma_addr_t dma_buf_end;
118 size_t period_size;
119 unsigned int num_periods;
120};
121
122/**
123 * fsl_dma_hardare: define characteristics of the PCM hardware.
124 *
125 * The PCM hardware is the Freescale DMA controller. This structure defines
126 * the capabilities of that hardware.
127 *
128 * Since the sampling rate and data format are not controlled by the DMA
129 * controller, we specify no limits for those values. The only exception is
130 * period_bytes_min, which is set to a reasonably low value to prevent the
131 * DMA controller from generating too many interrupts per second.
132 *
133 * Since each link descriptor has a 32-bit byte count field, we set
134 * period_bytes_max to the largest 32-bit number. We also have no maximum
135 * number of periods.
136 */
137static const struct snd_pcm_hardware fsl_dma_hardware = {
138
139 .info = SNDRV_PCM_INFO_INTERLEAVED |
140 SNDRV_PCM_INFO_MMAP |
141 SNDRV_PCM_INFO_MMAP_VALID,
142 .formats = FSLDMA_PCM_FORMATS,
143 .rates = FSLDMA_PCM_RATES,
144 .rate_min = 5512,
145 .rate_max = 192000,
146 .period_bytes_min = 512, /* A reasonable limit */
147 .period_bytes_max = (u32) -1,
148 .periods_min = NUM_DMA_LINKS,
149 .periods_max = (unsigned int) -1,
150 .buffer_bytes_max = 128 * 1024, /* A reasonable limit */
151};
152
153/**
154 * fsl_dma_abort_stream: tell ALSA that the DMA transfer has aborted
155 *
156 * This function should be called by the ISR whenever the DMA controller
157 * halts data transfer.
158 */
159static void fsl_dma_abort_stream(struct snd_pcm_substream *substream)
160{
161 unsigned long flags;
162
163 snd_pcm_stream_lock_irqsave(substream, flags);
164
165 if (snd_pcm_running(substream))
166 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
167
168 snd_pcm_stream_unlock_irqrestore(substream, flags);
169}
170
171/**
172 * fsl_dma_update_pointers - update LD pointers to point to the next period
173 *
174 * As each period is completed, this function changes the the link
175 * descriptor pointers for that period to point to the next period.
176 */
177static void fsl_dma_update_pointers(struct fsl_dma_private *dma_private)
178{
179 struct fsl_dma_link_descriptor *link =
180 &dma_private->link[dma_private->current_link];
181
182 /* Update our link descriptors to point to the next period */
183 if (dma_private->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
184 link->source_addr =
185 cpu_to_be32(dma_private->dma_buf_next);
186 else
187 link->dest_addr =
188 cpu_to_be32(dma_private->dma_buf_next);
189
190 /* Update our variables for next time */
191 dma_private->dma_buf_next += dma_private->period_size;
192
193 if (dma_private->dma_buf_next >= dma_private->dma_buf_end)
194 dma_private->dma_buf_next = dma_private->dma_buf_phys;
195
196 if (++dma_private->current_link >= NUM_DMA_LINKS)
197 dma_private->current_link = 0;
198}
199
200/**
201 * fsl_dma_isr: interrupt handler for the DMA controller
202 *
203 * @irq: IRQ of the DMA channel
204 * @dev_id: pointer to the dma_private structure for this DMA channel
205 */
206static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
207{
208 struct fsl_dma_private *dma_private = dev_id;
209 struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
210 irqreturn_t ret = IRQ_NONE;
211 u32 sr, sr2 = 0;
212
213 /* We got an interrupt, so read the status register to see what we
214 were interrupted for.
215 */
216 sr = in_be32(&dma_channel->sr);
217
218 if (sr & CCSR_DMA_SR_TE) {
219 dev_err(dma_private->substream->pcm->card->dev,
220 "DMA transmit error (controller=%u channel=%u irq=%u\n",
221 dma_private->controller_id,
222 dma_private->channel_id, irq);
223 fsl_dma_abort_stream(dma_private->substream);
224 sr2 |= CCSR_DMA_SR_TE;
225 ret = IRQ_HANDLED;
226 }
227
228 if (sr & CCSR_DMA_SR_CH)
229 ret = IRQ_HANDLED;
230
231 if (sr & CCSR_DMA_SR_PE) {
232 dev_err(dma_private->substream->pcm->card->dev,
233 "DMA%u programming error (channel=%u irq=%u)\n",
234 dma_private->controller_id,
235 dma_private->channel_id, irq);
236 fsl_dma_abort_stream(dma_private->substream);
237 sr2 |= CCSR_DMA_SR_PE;
238 ret = IRQ_HANDLED;
239 }
240
241 if (sr & CCSR_DMA_SR_EOLNI) {
242 sr2 |= CCSR_DMA_SR_EOLNI;
243 ret = IRQ_HANDLED;
244 }
245
246 if (sr & CCSR_DMA_SR_CB)
247 ret = IRQ_HANDLED;
248
249 if (sr & CCSR_DMA_SR_EOSI) {
250 struct snd_pcm_substream *substream = dma_private->substream;
251
252 /* Tell ALSA we completed a period. */
253 snd_pcm_period_elapsed(substream);
254
255 /*
256 * Update our link descriptors to point to the next period. We
257 * only need to do this if the number of periods is not equal to
258 * the number of links.
259 */
260 if (dma_private->num_periods != NUM_DMA_LINKS)
261 fsl_dma_update_pointers(dma_private);
262
263 sr2 |= CCSR_DMA_SR_EOSI;
264 ret = IRQ_HANDLED;
265 }
266
267 if (sr & CCSR_DMA_SR_EOLSI) {
268 sr2 |= CCSR_DMA_SR_EOLSI;
269 ret = IRQ_HANDLED;
270 }
271
272 /* Clear the bits that we set */
273 if (sr2)
274 out_be32(&dma_channel->sr, sr2);
275
276 return ret;
277}
278
279/**
280 * fsl_dma_new: initialize this PCM driver.
281 *
282 * This function is called when the codec driver calls snd_soc_new_pcms(),
283 * once for each .dai_link in the machine driver's snd_soc_machine
284 * structure.
285 */
286static int fsl_dma_new(struct snd_card *card, struct snd_soc_codec_dai *dai,
287 struct snd_pcm *pcm)
288{
289 static u64 fsl_dma_dmamask = DMA_BIT_MASK(32);
290 int ret;
291
292 if (!card->dev->dma_mask)
293 card->dev->dma_mask = &fsl_dma_dmamask;
294
295 if (!card->dev->coherent_dma_mask)
296 card->dev->coherent_dma_mask = fsl_dma_dmamask;
297
298 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev,
299 fsl_dma_hardware.buffer_bytes_max,
300 &pcm->streams[0].substream->dma_buffer);
301 if (ret) {
302 dev_err(card->dev,
303 "Can't allocate playback DMA buffer (size=%u)\n",
304 fsl_dma_hardware.buffer_bytes_max);
305 return -ENOMEM;
306 }
307
308 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev,
309 fsl_dma_hardware.buffer_bytes_max,
310 &pcm->streams[1].substream->dma_buffer);
311 if (ret) {
312 snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
313 dev_err(card->dev,
314 "Can't allocate capture DMA buffer (size=%u)\n",
315 fsl_dma_hardware.buffer_bytes_max);
316 return -ENOMEM;
317 }
318
319 return 0;
320}
321
322/**
323 * fsl_dma_open: open a new substream.
324 *
325 * Each substream has its own DMA buffer.
326 */
327static int fsl_dma_open(struct snd_pcm_substream *substream)
328{
329 struct snd_pcm_runtime *runtime = substream->runtime;
330 struct fsl_dma_private *dma_private;
331 dma_addr_t ld_buf_phys;
332 unsigned int channel;
333 int ret = 0;
334
335 /*
336 * Reject any DMA buffer whose size is not a multiple of the period
337 * size. We need to make sure that the DMA buffer can be evenly divided
338 * into periods.
339 */
340 ret = snd_pcm_hw_constraint_integer(runtime,
341 SNDRV_PCM_HW_PARAM_PERIODS);
342 if (ret < 0) {
343 dev_err(substream->pcm->card->dev, "invalid buffer size\n");
344 return ret;
345 }
346
347 channel = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
348
349 if (dma_global_data.assigned[channel]) {
350 dev_err(substream->pcm->card->dev,
351 "DMA channel already assigned\n");
352 return -EBUSY;
353 }
354
355 dma_private = dma_alloc_coherent(substream->pcm->dev,
356 sizeof(struct fsl_dma_private), &ld_buf_phys, GFP_KERNEL);
357 if (!dma_private) {
358 dev_err(substream->pcm->card->dev,
359 "can't allocate DMA private data\n");
360 return -ENOMEM;
361 }
362 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
363 dma_private->ssi_sxx_phys = dma_global_data.ssi_stx_phys;
364 else
365 dma_private->ssi_sxx_phys = dma_global_data.ssi_srx_phys;
366
367 dma_private->dma_channel = dma_global_data.dma_channel[channel];
368 dma_private->irq = dma_global_data.irq[channel];
369 dma_private->substream = substream;
370 dma_private->ld_buf_phys = ld_buf_phys;
371 dma_private->dma_buf_phys = substream->dma_buffer.addr;
372
373 /* We only support one DMA controller for now */
374 dma_private->controller_id = 0;
375 dma_private->channel_id = channel;
376
377 ret = request_irq(dma_private->irq, fsl_dma_isr, 0, "DMA", dma_private);
378 if (ret) {
379 dev_err(substream->pcm->card->dev,
380 "can't register ISR for IRQ %u (ret=%i)\n",
381 dma_private->irq, ret);
382 dma_free_coherent(substream->pcm->dev,
383 sizeof(struct fsl_dma_private),
384 dma_private, dma_private->ld_buf_phys);
385 return ret;
386 }
387
388 dma_global_data.assigned[channel] = 1;
389
390 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
391 snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware);
392 runtime->private_data = dma_private;
393
394 return 0;
395}
396
397/**
398 * fsl_dma_hw_params: allocate the DMA buffer and the DMA link descriptors.
399 *
400 * ALSA divides the DMA buffer into N periods. We create NUM_DMA_LINKS link
401 * descriptors that ping-pong from one period to the next. For example, if
402 * there are six periods and two link descriptors, this is how they look
403 * before playback starts:
404 *
405 * The last link descriptor
406 * ____________ points back to the first
407 * | |
408 * V |
409 * ___ ___ |
410 * | |->| |->|
411 * |___| |___|
412 * | |
413 * | |
414 * V V
415 * _________________________________________
416 * | | | | | | | The DMA buffer is
417 * | | | | | | | divided into 6 parts
418 * |______|______|______|______|______|______|
419 *
420 * and here's how they look after the first period is finished playing:
421 *
422 * ____________
423 * | |
424 * V |
425 * ___ ___ |
426 * | |->| |->|
427 * |___| |___|
428 * | |
429 * |______________
430 * | |
431 * V V
432 * _________________________________________
433 * | | | | | | |
434 * | | | | | | |
435 * |______|______|______|______|______|______|
436 *
437 * The first link descriptor now points to the third period. The DMA
438 * controller is currently playing the second period. When it finishes, it
439 * will jump back to the first descriptor and play the third period.
440 *
441 * There are four reasons we do this:
442 *
443 * 1. The only way to get the DMA controller to automatically restart the
444 * transfer when it gets to the end of the buffer is to use chaining
445 * mode. Basic direct mode doesn't offer that feature.
446 * 2. We need to receive an interrupt at the end of every period. The DMA
447 * controller can generate an interrupt at the end of every link transfer
448 * (aka segment). Making each period into a DMA segment will give us the
449 * interrupts we need.
450 * 3. By creating only two link descriptors, regardless of the number of
451 * periods, we do not need to reallocate the link descriptors if the
452 * number of periods changes.
453 * 4. All of the audio data is still stored in a single, contiguous DMA
454 * buffer, which is what ALSA expects. We're just dividing it into
455 * contiguous parts, and creating a link descriptor for each one.
456 *
457 * Note that due to a quirk of the SSI's STX register, the target address
458 * for the DMA operations depends on the sample size. So we don't program
459 * the dest_addr (for playback -- source_addr for capture) fields in the
460 * link descriptors here. We do that in fsl_dma_prepare()
461 */
462static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
463 struct snd_pcm_hw_params *hw_params)
464{
465 struct snd_pcm_runtime *runtime = substream->runtime;
466 struct fsl_dma_private *dma_private = runtime->private_data;
467 struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
468
469 dma_addr_t temp_addr; /* Pointer to next period */
470 u64 temp_link; /* Pointer to next link descriptor */
471 u32 mr; /* Temporary variable for MR register */
472
473 unsigned int i;
474
475 /* Get all the parameters we need */
476 size_t buffer_size = params_buffer_bytes(hw_params);
477 size_t period_size = params_period_bytes(hw_params);
478
479 /* Initialize our DMA tracking variables */
480 dma_private->period_size = period_size;
481 dma_private->num_periods = params_periods(hw_params);
482 dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size;
483 dma_private->dma_buf_next = dma_private->dma_buf_phys +
484 (NUM_DMA_LINKS * period_size);
485 if (dma_private->dma_buf_next >= dma_private->dma_buf_end)
486 dma_private->dma_buf_next = dma_private->dma_buf_phys;
487
488 /*
489 * Initialize each link descriptor.
490 *
491 * The actual address in STX0 (destination for playback, source for
492 * capture) is based on the sample size, but we don't know the sample
493 * size in this function, so we'll have to adjust that later. See
494 * comments in fsl_dma_prepare().
495 *
496 * The DMA controller does not have a cache, so the CPU does not
497 * need to tell it to flush its cache. However, the DMA
498 * controller does need to tell the CPU to flush its cache.
499 * That's what the SNOOP bit does.
500 *
501 * Also, even though the DMA controller supports 36-bit addressing, for
502 * simplicity we currently support only 32-bit addresses for the audio
503 * buffer itself.
504 */
505 temp_addr = substream->dma_buffer.addr;
506 temp_link = dma_private->ld_buf_phys +
507 sizeof(struct fsl_dma_link_descriptor);
508
509 for (i = 0; i < NUM_DMA_LINKS; i++) {
510 struct fsl_dma_link_descriptor *link = &dma_private->link[i];
511
512 link->count = cpu_to_be32(period_size);
513 link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
514 link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
515 link->next = cpu_to_be64(temp_link);
516
517 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
518 link->source_addr = cpu_to_be32(temp_addr);
519 else
520 link->dest_addr = cpu_to_be32(temp_addr);
521
522 temp_addr += period_size;
523 temp_link += sizeof(struct fsl_dma_link_descriptor);
524 }
525 /* The last link descriptor points to the first */
526 dma_private->link[i - 1].next = cpu_to_be64(dma_private->ld_buf_phys);
527
528 /* Tell the DMA controller where the first link descriptor is */
529 out_be32(&dma_channel->clndar,
530 CCSR_DMA_CLNDAR_ADDR(dma_private->ld_buf_phys));
531 out_be32(&dma_channel->eclndar,
532 CCSR_DMA_ECLNDAR_ADDR(dma_private->ld_buf_phys));
533
534 /* The manual says the BCR must be clear before enabling EMP */
535 out_be32(&dma_channel->bcr, 0);
536
537 /*
538 * Program the mode register for interrupts, external master control,
539 * and source/destination hold. Also clear the Channel Abort bit.
540 */
541 mr = in_be32(&dma_channel->mr) &
542 ~(CCSR_DMA_MR_CA | CCSR_DMA_MR_DAHE | CCSR_DMA_MR_SAHE);
543
544 /*
545 * We want External Master Start and External Master Pause enabled,
546 * because the SSI is controlling the DMA controller. We want the DMA
547 * controller to be set up in advance, and then we signal only the SSI
548 * to start transfering.
549 *
550 * We want End-Of-Segment Interrupts enabled, because this will generate
551 * an interrupt at the end of each segment (each link descriptor
552 * represents one segment). Each DMA segment is the same thing as an
553 * ALSA period, so this is how we get an interrupt at the end of every
554 * period.
555 *
556 * We want Error Interrupt enabled, so that we can get an error if
557 * the DMA controller is mis-programmed somehow.
558 */
559 mr |= CCSR_DMA_MR_EOSIE | CCSR_DMA_MR_EIE | CCSR_DMA_MR_EMP_EN |
560 CCSR_DMA_MR_EMS_EN;
561
562 /* For playback, we want the destination address to be held. For
563 capture, set the source address to be held. */
564 mr |= (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
565 CCSR_DMA_MR_DAHE : CCSR_DMA_MR_SAHE;
566
567 out_be32(&dma_channel->mr, mr);
568
569 return 0;
570}
571
572/**
573 * fsl_dma_prepare - prepare the DMA registers for playback.
574 *
575 * This function is called after the specifics of the audio data are known,
576 * i.e. snd_pcm_runtime is initialized.
577 *
578 * In this function, we finish programming the registers of the DMA
579 * controller that are dependent on the sample size.
580 *
581 * One of the drawbacks with big-endian is that when copying integers of
582 * different sizes to a fixed-sized register, the address to which the
583 * integer must be copied is dependent on the size of the integer.
584 *
585 * For example, if P is the address of a 32-bit register, and X is a 32-bit
586 * integer, then X should be copied to address P. However, if X is a 16-bit
587 * integer, then it should be copied to P+2. If X is an 8-bit register,
588 * then it should be copied to P+3.
589 *
590 * So for playback of 8-bit samples, the DMA controller must transfer single
591 * bytes from the DMA buffer to the last byte of the STX0 register, i.e.
592 * offset by 3 bytes. For 16-bit samples, the offset is two bytes.
593 *
594 * For 24-bit samples, the offset is 1 byte. However, the DMA controller
595 * does not support 3-byte copies (the DAHTS register supports only 1, 2, 4,
596 * and 8 bytes at a time). So we do not support packed 24-bit samples.
597 * 24-bit data must be padded to 32 bits.
598 */
599static int fsl_dma_prepare(struct snd_pcm_substream *substream)
600{
601 struct snd_pcm_runtime *runtime = substream->runtime;
602 struct fsl_dma_private *dma_private = runtime->private_data;
603 struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
604 u32 mr;
605 unsigned int i;
606 dma_addr_t ssi_sxx_phys; /* Bus address of SSI STX register */
607 unsigned int frame_size; /* Number of bytes per frame */
608
609 ssi_sxx_phys = dma_private->ssi_sxx_phys;
610
611 mr = in_be32(&dma_channel->mr) & ~(CCSR_DMA_MR_BWC_MASK |
612 CCSR_DMA_MR_SAHTS_MASK | CCSR_DMA_MR_DAHTS_MASK);
613
614 switch (runtime->sample_bits) {
615 case 8:
616 mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1;
617 ssi_sxx_phys += 3;
618 break;
619 case 16:
620 mr |= CCSR_DMA_MR_DAHTS_2 | CCSR_DMA_MR_SAHTS_2;
621 ssi_sxx_phys += 2;
622 break;
623 case 32:
624 mr |= CCSR_DMA_MR_DAHTS_4 | CCSR_DMA_MR_SAHTS_4;
625 break;
626 default:
627 dev_err(substream->pcm->card->dev,
628 "unsupported sample size %u\n", runtime->sample_bits);
629 return -EINVAL;
630 }
631
632 frame_size = runtime->frame_bits / 8;
633 /*
634 * BWC should always be a multiple of the frame size. BWC determines
635 * how many bytes are sent/received before the DMA controller checks the
636 * SSI to see if it needs to stop. For playback, the transmit FIFO can
637 * hold three frames, so we want to send two frames at a time. For
638 * capture, the receive FIFO is triggered when it contains one frame, so
639 * we want to receive one frame at a time.
640 */
641
642 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
643 mr |= CCSR_DMA_MR_BWC(2 * frame_size);
644 else
645 mr |= CCSR_DMA_MR_BWC(frame_size);
646
647 out_be32(&dma_channel->mr, mr);
648
649 /*
650 * Program the address of the DMA transfer to/from the SSI.
651 */
652 for (i = 0; i < NUM_DMA_LINKS; i++) {
653 struct fsl_dma_link_descriptor *link = &dma_private->link[i];
654
655 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
656 link->dest_addr = cpu_to_be32(ssi_sxx_phys);
657 else
658 link->source_addr = cpu_to_be32(ssi_sxx_phys);
659 }
660
661 return 0;
662}
663
664/**
665 * fsl_dma_pointer: determine the current position of the DMA transfer
666 *
667 * This function is called by ALSA when ALSA wants to know where in the
668 * stream buffer the hardware currently is.
669 *
670 * For playback, the SAR register contains the physical address of the most
671 * recent DMA transfer. For capture, the value is in the DAR register.
672 *
673 * The base address of the buffer is stored in the source_addr field of the
674 * first link descriptor.
675 */
676static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream)
677{
678 struct snd_pcm_runtime *runtime = substream->runtime;
679 struct fsl_dma_private *dma_private = runtime->private_data;
680 struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
681 dma_addr_t position;
682 snd_pcm_uframes_t frames;
683
684 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
685 position = in_be32(&dma_channel->sar);
686 else
687 position = in_be32(&dma_channel->dar);
688
689 frames = bytes_to_frames(runtime, position - dma_private->dma_buf_phys);
690
691 /*
692 * If the current address is just past the end of the buffer, wrap it
693 * around.
694 */
695 if (frames == runtime->buffer_size)
696 frames = 0;
697
698 return frames;
699}
700
701/**
702 * fsl_dma_hw_free: release resources allocated in fsl_dma_hw_params()
703 *
704 * Release the resources allocated in fsl_dma_hw_params() and de-program the
705 * registers.
706 *
707 * This function can be called multiple times.
708 */
709static int fsl_dma_hw_free(struct snd_pcm_substream *substream)
710{
711 struct snd_pcm_runtime *runtime = substream->runtime;
712 struct fsl_dma_private *dma_private = runtime->private_data;
713
714 if (dma_private) {
715 struct ccsr_dma_channel __iomem *dma_channel;
716
717 dma_channel = dma_private->dma_channel;
718
719 /* Stop the DMA */
720 out_be32(&dma_channel->mr, CCSR_DMA_MR_CA);
721 out_be32(&dma_channel->mr, 0);
722
723 /* Reset all the other registers */
724 out_be32(&dma_channel->sr, -1);
725 out_be32(&dma_channel->clndar, 0);
726 out_be32(&dma_channel->eclndar, 0);
727 out_be32(&dma_channel->satr, 0);
728 out_be32(&dma_channel->sar, 0);
729 out_be32(&dma_channel->datr, 0);
730 out_be32(&dma_channel->dar, 0);
731 out_be32(&dma_channel->bcr, 0);
732 out_be32(&dma_channel->nlndar, 0);
733 out_be32(&dma_channel->enlndar, 0);
734 }
735
736 return 0;
737}
738
739/**
740 * fsl_dma_close: close the stream.
741 */
742static int fsl_dma_close(struct snd_pcm_substream *substream)
743{
744 struct snd_pcm_runtime *runtime = substream->runtime;
745 struct fsl_dma_private *dma_private = runtime->private_data;
746 int dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
747
748 if (dma_private) {
749 if (dma_private->irq)
750 free_irq(dma_private->irq, dma_private);
751
752 if (dma_private->ld_buf_phys) {
753 dma_unmap_single(substream->pcm->dev,
754 dma_private->ld_buf_phys,
755 sizeof(dma_private->link), DMA_TO_DEVICE);
756 }
757
758 /* Deallocate the fsl_dma_private structure */
759 dma_free_coherent(substream->pcm->dev,
760 sizeof(struct fsl_dma_private),
761 dma_private, dma_private->ld_buf_phys);
762 substream->runtime->private_data = NULL;
763 }
764
765 dma_global_data.assigned[dir] = 0;
766
767 return 0;
768}
769
770/*
771 * Remove this PCM driver.
772 */
773static void fsl_dma_free_dma_buffers(struct snd_pcm *pcm)
774{
775 struct snd_pcm_substream *substream;
776 unsigned int i;
777
778 for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) {
779 substream = pcm->streams[i].substream;
780 if (substream) {
781 snd_dma_free_pages(&substream->dma_buffer);
782 substream->dma_buffer.area = NULL;
783 substream->dma_buffer.addr = 0;
784 }
785 }
786}
787
788static struct snd_pcm_ops fsl_dma_ops = {
789 .open = fsl_dma_open,
790 .close = fsl_dma_close,
791 .ioctl = snd_pcm_lib_ioctl,
792 .hw_params = fsl_dma_hw_params,
793 .hw_free = fsl_dma_hw_free,
794 .prepare = fsl_dma_prepare,
795 .pointer = fsl_dma_pointer,
796};
797
798struct snd_soc_platform fsl_soc_platform = {
799 .name = "fsl-dma",
800 .pcm_ops = &fsl_dma_ops,
801 .pcm_new = fsl_dma_new,
802 .pcm_free = fsl_dma_free_dma_buffers,
803};
804EXPORT_SYMBOL_GPL(fsl_soc_platform);
805
806/**
807 * fsl_dma_configure: store the DMA parameters from the fabric driver.
808 *
809 * This function is called by the ASoC fabric driver to give us the DMA and
810 * SSI channel information.
811 *
812 * Unfortunately, ASoC V1 does make it possible to determine the DMA/SSI
813 * data when a substream is created, so for now we need to store this data
814 * into a global variable. This means that we can only support one DMA
815 * controller, and hence only one SSI.
816 */
817int fsl_dma_configure(struct fsl_dma_info *dma_info)
818{
819 static int initialized;
820
821 /* We only support one DMA controller for now */
822 if (initialized)
823 return 0;
824
825 dma_global_data.ssi_stx_phys = dma_info->ssi_stx_phys;
826 dma_global_data.ssi_srx_phys = dma_info->ssi_srx_phys;
827 dma_global_data.dma_channel[0] = dma_info->dma_channel[0];
828 dma_global_data.dma_channel[1] = dma_info->dma_channel[1];
829 dma_global_data.irq[0] = dma_info->dma_irq[0];
830 dma_global_data.irq[1] = dma_info->dma_irq[1];
831 dma_global_data.assigned[0] = 0;
832 dma_global_data.assigned[1] = 0;
833
834 initialized = 1;
835 return 1;
836}
837EXPORT_SYMBOL_GPL(fsl_dma_configure);
838
839MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
840MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM module");
841MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/fsl_dma.h b/sound/soc/fsl/fsl_dma.h
new file mode 100644
index 000000000000..430a6ce8b0d0
--- /dev/null
+++ b/sound/soc/fsl/fsl_dma.h
@@ -0,0 +1,149 @@
1/*
2 * mpc8610-pcm.h - ALSA PCM interface for the Freescale MPC8610 SoC
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef _MPC8610_PCM_H
10#define _MPC8610_PCM_H
11
12struct ccsr_dma {
13 u8 res0[0x100];
14 struct ccsr_dma_channel {
15 __be32 mr; /* Mode register */
16 __be32 sr; /* Status register */
17 __be32 eclndar; /* Current link descriptor extended addr reg */
18 __be32 clndar; /* Current link descriptor address register */
19 __be32 satr; /* Source attributes register */
20 __be32 sar; /* Source address register */
21 __be32 datr; /* Destination attributes register */
22 __be32 dar; /* Destination address register */
23 __be32 bcr; /* Byte count register */
24 __be32 enlndar; /* Next link descriptor extended address reg */
25 __be32 nlndar; /* Next link descriptor address register */
26 u8 res1[4];
27 __be32 eclsdar; /* Current list descriptor extended addr reg */
28 __be32 clsdar; /* Current list descriptor address register */
29 __be32 enlsdar; /* Next list descriptor extended address reg */
30 __be32 nlsdar; /* Next list descriptor address register */
31 __be32 ssr; /* Source stride register */
32 __be32 dsr; /* Destination stride register */
33 u8 res2[0x38];
34 } channel[4];
35 __be32 dgsr;
36};
37
38#define CCSR_DMA_MR_BWC_DISABLED 0x0F000000
39#define CCSR_DMA_MR_BWC_SHIFT 24
40#define CCSR_DMA_MR_BWC_MASK 0x0F000000
41#define CCSR_DMA_MR_BWC(x) \
42 ((ilog2(x) << CCSR_DMA_MR_BWC_SHIFT) & CCSR_DMA_MR_BWC_MASK)
43#define CCSR_DMA_MR_EMP_EN 0x00200000
44#define CCSR_DMA_MR_EMS_EN 0x00040000
45#define CCSR_DMA_MR_DAHTS_MASK 0x00030000
46#define CCSR_DMA_MR_DAHTS_1 0x00000000
47#define CCSR_DMA_MR_DAHTS_2 0x00010000
48#define CCSR_DMA_MR_DAHTS_4 0x00020000
49#define CCSR_DMA_MR_DAHTS_8 0x00030000
50#define CCSR_DMA_MR_SAHTS_MASK 0x0000C000
51#define CCSR_DMA_MR_SAHTS_1 0x00000000
52#define CCSR_DMA_MR_SAHTS_2 0x00004000
53#define CCSR_DMA_MR_SAHTS_4 0x00008000
54#define CCSR_DMA_MR_SAHTS_8 0x0000C000
55#define CCSR_DMA_MR_DAHE 0x00002000
56#define CCSR_DMA_MR_SAHE 0x00001000
57#define CCSR_DMA_MR_SRW 0x00000400
58#define CCSR_DMA_MR_EOSIE 0x00000200
59#define CCSR_DMA_MR_EOLNIE 0x00000100
60#define CCSR_DMA_MR_EOLSIE 0x00000080
61#define CCSR_DMA_MR_EIE 0x00000040
62#define CCSR_DMA_MR_XFE 0x00000020
63#define CCSR_DMA_MR_CDSM_SWSM 0x00000010
64#define CCSR_DMA_MR_CA 0x00000008
65#define CCSR_DMA_MR_CTM 0x00000004
66#define CCSR_DMA_MR_CC 0x00000002
67#define CCSR_DMA_MR_CS 0x00000001
68
69#define CCSR_DMA_SR_TE 0x00000080
70#define CCSR_DMA_SR_CH 0x00000020
71#define CCSR_DMA_SR_PE 0x00000010
72#define CCSR_DMA_SR_EOLNI 0x00000008
73#define CCSR_DMA_SR_CB 0x00000004
74#define CCSR_DMA_SR_EOSI 0x00000002
75#define CCSR_DMA_SR_EOLSI 0x00000001
76
77/* ECLNDAR takes bits 32-36 of the CLNDAR register */
78static inline u32 CCSR_DMA_ECLNDAR_ADDR(u64 x)
79{
80 return (x >> 32) & 0xf;
81}
82
83#define CCSR_DMA_CLNDAR_ADDR(x) ((x) & 0xFFFFFFFE)
84#define CCSR_DMA_CLNDAR_EOSIE 0x00000008
85
86/* SATR and DATR, combined */
87#define CCSR_DMA_ATR_PBATMU 0x20000000
88#define CCSR_DMA_ATR_TFLOWLVL_0 0x00000000
89#define CCSR_DMA_ATR_TFLOWLVL_1 0x06000000
90#define CCSR_DMA_ATR_TFLOWLVL_2 0x08000000
91#define CCSR_DMA_ATR_TFLOWLVL_3 0x0C000000
92#define CCSR_DMA_ATR_PCIORDER 0x02000000
93#define CCSR_DMA_ATR_SME 0x01000000
94#define CCSR_DMA_ATR_NOSNOOP 0x00040000
95#define CCSR_DMA_ATR_SNOOP 0x00050000
96#define CCSR_DMA_ATR_ESAD_MASK 0x0000000F
97
98/**
99 * List Descriptor for extended chaining mode DMA operations.
100 *
101 * The CLSDAR register points to the first (in a linked-list) List
102 * Descriptor. Each object must be aligned on a 32-byte boundary. Each
103 * list descriptor points to a linked-list of link Descriptors.
104 */
105struct fsl_dma_list_descriptor {
106 __be64 next; /* Address of next list descriptor */
107 __be64 first_link; /* Address of first link descriptor */
108 __be32 source; /* Source stride */
109 __be32 dest; /* Destination stride */
110 u8 res[8]; /* Reserved */
111} __attribute__ ((aligned(32), packed));
112
113/**
114 * Link Descriptor for basic and extended chaining mode DMA operations.
115 *
116 * A Link Descriptor points to a single DMA buffer. Each link descriptor
117 * must be aligned on a 32-byte boundary.
118 */
119struct fsl_dma_link_descriptor {
120 __be32 source_attr; /* Programmed into SATR register */
121 __be32 source_addr; /* Programmed into SAR register */
122 __be32 dest_attr; /* Programmed into DATR register */
123 __be32 dest_addr; /* Programmed into DAR register */
124 __be64 next; /* Address of next link descriptor */
125 __be32 count; /* Byte count */
126 u8 res[4]; /* Reserved */
127} __attribute__ ((aligned(32), packed));
128
129/* DMA information needed to create a snd_soc_cpu_dai object
130 *
131 * ssi_stx_phys: bus address of SSI STX register to use
132 * ssi_srx_phys: bus address of SSI SRX register to use
133 * dma[0]: points to the DMA channel to use for playback
134 * dma[1]: points to the DMA channel to use for capture
135 * dma_irq[0]: IRQ of the DMA channel to use for playback
136 * dma_irq[1]: IRQ of the DMA channel to use for capture
137 */
138struct fsl_dma_info {
139 dma_addr_t ssi_stx_phys;
140 dma_addr_t ssi_srx_phys;
141 struct ccsr_dma_channel __iomem *dma_channel[2];
142 unsigned int dma_irq[2];
143};
144
145extern struct snd_soc_platform fsl_soc_platform;
146
147int fsl_dma_configure(struct fsl_dma_info *dma_info);
148
149#endif
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
new file mode 100644
index 000000000000..145ad13d52d1
--- /dev/null
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -0,0 +1,644 @@
1/*
2 * Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver
3 *
4 * Author: Timur Tabi <timur@freescale.com>
5 *
6 * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed
7 * under the terms of the GNU General Public License version 2. This
8 * program is licensed "as is" without any warranty of any kind, whether
9 * express or implied.
10 */
11
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/interrupt.h>
15#include <linux/device.h>
16#include <linux/delay.h>
17
18#include <sound/driver.h>
19#include <sound/core.h>
20#include <sound/pcm.h>
21#include <sound/pcm_params.h>
22#include <sound/initval.h>
23#include <sound/soc.h>
24
25#include <asm/immap_86xx.h>
26
27#include "fsl_ssi.h"
28
29/**
30 * FSLSSI_I2S_RATES: sample rates supported by the I2S
31 *
32 * This driver currently only supports the SSI running in I2S slave mode,
33 * which means the codec determines the sample rate. Therefore, we tell
34 * ALSA that we support all rates and let the codec driver decide what rates
35 * are really supported.
36 */
37#define FSLSSI_I2S_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
38 SNDRV_PCM_RATE_CONTINUOUS)
39
40/**
41 * FSLSSI_I2S_FORMATS: audio formats supported by the SSI
42 *
43 * This driver currently only supports the SSI running in I2S slave mode.
44 *
45 * The SSI has a limitation in that the samples must be in the same byte
46 * order as the host CPU. This is because when multiple bytes are written
47 * to the STX register, the bytes and bits must be written in the same
48 * order. The STX is a shift register, so all the bits need to be aligned
49 * (bit-endianness must match byte-endianness). Processors typically write
50 * the bits within a byte in the same order that the bytes of a word are
51 * written in. So if the host CPU is big-endian, then only big-endian
52 * samples will be written to STX properly.
53 */
54#ifdef __BIG_ENDIAN
55#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
56 SNDRV_PCM_FMTBIT_S18_3BE | SNDRV_PCM_FMTBIT_S20_3BE | \
57 SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_S24_BE)
58#else
59#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
60 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | \
61 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE)
62#endif
63
64/**
65 * fsl_ssi_private: per-SSI private data
66 *
67 * @name: short name for this device ("SSI0", "SSI1", etc)
68 * @ssi: pointer to the SSI's registers
69 * @ssi_phys: physical address of the SSI registers
70 * @irq: IRQ of this SSI
71 * @dev: struct device pointer
72 * @playback: the number of playback streams opened
73 * @capture: the number of capture streams opened
74 * @cpu_dai: the CPU DAI for this device
75 * @dev_attr: the sysfs device attribute structure
76 * @stats: SSI statistics
77 */
78struct fsl_ssi_private {
79 char name[8];
80 struct ccsr_ssi __iomem *ssi;
81 dma_addr_t ssi_phys;
82 unsigned int irq;
83 struct device *dev;
84 unsigned int playback;
85 unsigned int capture;
86 struct snd_soc_cpu_dai cpu_dai;
87 struct device_attribute dev_attr;
88
89 struct {
90 unsigned int rfrc;
91 unsigned int tfrc;
92 unsigned int cmdau;
93 unsigned int cmddu;
94 unsigned int rxt;
95 unsigned int rdr1;
96 unsigned int rdr0;
97 unsigned int tde1;
98 unsigned int tde0;
99 unsigned int roe1;
100 unsigned int roe0;
101 unsigned int tue1;
102 unsigned int tue0;
103 unsigned int tfs;
104 unsigned int rfs;
105 unsigned int tls;
106 unsigned int rls;
107 unsigned int rff1;
108 unsigned int rff0;
109 unsigned int tfe1;
110 unsigned int tfe0;
111 } stats;
112};
113
114/**
115 * fsl_ssi_isr: SSI interrupt handler
116 *
117 * Although it's possible to use the interrupt handler to send and receive
118 * data to/from the SSI, we use the DMA instead. Programming is more
119 * complicated, but the performance is much better.
120 *
121 * This interrupt handler is used only to gather statistics.
122 *
123 * @irq: IRQ of the SSI device
124 * @dev_id: pointer to the ssi_private structure for this SSI device
125 */
126static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
127{
128 struct fsl_ssi_private *ssi_private = dev_id;
129 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
130 irqreturn_t ret = IRQ_NONE;
131 __be32 sisr;
132 __be32 sisr2 = 0;
133
134 /* We got an interrupt, so read the status register to see what we
135 were interrupted for. We mask it with the Interrupt Enable register
136 so that we only check for events that we're interested in.
137 */
138 sisr = in_be32(&ssi->sisr) & in_be32(&ssi->sier);
139
140 if (sisr & CCSR_SSI_SISR_RFRC) {
141 ssi_private->stats.rfrc++;
142 sisr2 |= CCSR_SSI_SISR_RFRC;
143 ret = IRQ_HANDLED;
144 }
145
146 if (sisr & CCSR_SSI_SISR_TFRC) {
147 ssi_private->stats.tfrc++;
148 sisr2 |= CCSR_SSI_SISR_TFRC;
149 ret = IRQ_HANDLED;
150 }
151
152 if (sisr & CCSR_SSI_SISR_CMDAU) {
153 ssi_private->stats.cmdau++;
154 ret = IRQ_HANDLED;
155 }
156
157 if (sisr & CCSR_SSI_SISR_CMDDU) {
158 ssi_private->stats.cmddu++;
159 ret = IRQ_HANDLED;
160 }
161
162 if (sisr & CCSR_SSI_SISR_RXT) {
163 ssi_private->stats.rxt++;
164 ret = IRQ_HANDLED;
165 }
166
167 if (sisr & CCSR_SSI_SISR_RDR1) {
168 ssi_private->stats.rdr1++;
169 ret = IRQ_HANDLED;
170 }
171
172 if (sisr & CCSR_SSI_SISR_RDR0) {
173 ssi_private->stats.rdr0++;
174 ret = IRQ_HANDLED;
175 }
176
177 if (sisr & CCSR_SSI_SISR_TDE1) {
178 ssi_private->stats.tde1++;
179 ret = IRQ_HANDLED;
180 }
181
182 if (sisr & CCSR_SSI_SISR_TDE0) {
183 ssi_private->stats.tde0++;
184 ret = IRQ_HANDLED;
185 }
186
187 if (sisr & CCSR_SSI_SISR_ROE1) {
188 ssi_private->stats.roe1++;
189 sisr2 |= CCSR_SSI_SISR_ROE1;
190 ret = IRQ_HANDLED;
191 }
192
193 if (sisr & CCSR_SSI_SISR_ROE0) {
194 ssi_private->stats.roe0++;
195 sisr2 |= CCSR_SSI_SISR_ROE0;
196 ret = IRQ_HANDLED;
197 }
198
199 if (sisr & CCSR_SSI_SISR_TUE1) {
200 ssi_private->stats.tue1++;
201 sisr2 |= CCSR_SSI_SISR_TUE1;
202 ret = IRQ_HANDLED;
203 }
204
205 if (sisr & CCSR_SSI_SISR_TUE0) {
206 ssi_private->stats.tue0++;
207 sisr2 |= CCSR_SSI_SISR_TUE0;
208 ret = IRQ_HANDLED;
209 }
210
211 if (sisr & CCSR_SSI_SISR_TFS) {
212 ssi_private->stats.tfs++;
213 ret = IRQ_HANDLED;
214 }
215
216 if (sisr & CCSR_SSI_SISR_RFS) {
217 ssi_private->stats.rfs++;
218 ret = IRQ_HANDLED;
219 }
220
221 if (sisr & CCSR_SSI_SISR_TLS) {
222 ssi_private->stats.tls++;
223 ret = IRQ_HANDLED;
224 }
225
226 if (sisr & CCSR_SSI_SISR_RLS) {
227 ssi_private->stats.rls++;
228 ret = IRQ_HANDLED;
229 }
230
231 if (sisr & CCSR_SSI_SISR_RFF1) {
232 ssi_private->stats.rff1++;
233 ret = IRQ_HANDLED;
234 }
235
236 if (sisr & CCSR_SSI_SISR_RFF0) {
237 ssi_private->stats.rff0++;
238 ret = IRQ_HANDLED;
239 }
240
241 if (sisr & CCSR_SSI_SISR_TFE1) {
242 ssi_private->stats.tfe1++;
243 ret = IRQ_HANDLED;
244 }
245
246 if (sisr & CCSR_SSI_SISR_TFE0) {
247 ssi_private->stats.tfe0++;
248 ret = IRQ_HANDLED;
249 }
250
251 /* Clear the bits that we set */
252 if (sisr2)
253 out_be32(&ssi->sisr, sisr2);
254
255 return ret;
256}
257
258/**
259 * fsl_ssi_startup: create a new substream
260 *
261 * This is the first function called when a stream is opened.
262 *
263 * If this is the first stream open, then grab the IRQ and program most of
264 * the SSI registers.
265 */
266static int fsl_ssi_startup(struct snd_pcm_substream *substream)
267{
268 struct snd_soc_pcm_runtime *rtd = substream->private_data;
269 struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
270
271 /*
272 * If this is the first stream opened, then request the IRQ
273 * and initialize the SSI registers.
274 */
275 if (!ssi_private->playback && !ssi_private->capture) {
276 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
277 int ret;
278
279 ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0,
280 ssi_private->name, ssi_private);
281 if (ret < 0) {
282 dev_err(substream->pcm->card->dev,
283 "could not claim irq %u\n", ssi_private->irq);
284 return ret;
285 }
286
287 /*
288 * Section 16.5 of the MPC8610 reference manual says that the
289 * SSI needs to be disabled before updating the registers we set
290 * here.
291 */
292 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
293
294 /*
295 * Program the SSI into I2S Slave Non-Network Synchronous mode.
296 * Also enable the transmit and receive FIFO.
297 *
298 * FIXME: Little-endian samples require a different shift dir
299 */
300 clrsetbits_be32(&ssi->scr, CCSR_SSI_SCR_I2S_MODE_MASK,
301 CCSR_SSI_SCR_TFR_CLK_DIS |
302 CCSR_SSI_SCR_I2S_MODE_SLAVE | CCSR_SSI_SCR_SYN);
303
304 out_be32(&ssi->stcr,
305 CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
306 CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS |
307 CCSR_SSI_STCR_TSCKP);
308
309 out_be32(&ssi->srcr,
310 CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
311 CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS |
312 CCSR_SSI_SRCR_RSCKP);
313
314 /*
315 * The DC and PM bits are only used if the SSI is the clock
316 * master.
317 */
318
319 /* 4. Enable the interrupts and DMA requests */
320 out_be32(&ssi->sier,
321 CCSR_SSI_SIER_TFRC_EN | CCSR_SSI_SIER_TDMAE |
322 CCSR_SSI_SIER_TIE | CCSR_SSI_SIER_TUE0_EN |
323 CCSR_SSI_SIER_TUE1_EN | CCSR_SSI_SIER_RFRC_EN |
324 CCSR_SSI_SIER_RDMAE | CCSR_SSI_SIER_RIE |
325 CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_ROE1_EN);
326
327 /*
328 * Set the watermark for transmit FIFI 0 and receive FIFO 0. We
329 * don't use FIFO 1. Since the SSI only supports stereo, the
330 * watermark should never be an odd number.
331 */
332 out_be32(&ssi->sfcsr,
333 CCSR_SSI_SFCSR_TFWM0(6) | CCSR_SSI_SFCSR_RFWM0(2));
334
335 /*
336 * We keep the SSI disabled because if we enable it, then the
337 * DMA controller will start. It's not supposed to start until
338 * the SCR.TE (or SCR.RE) bit is set, but it does anyway. The
339 * DMA controller will transfer one "BWC" of data (i.e. the
340 * amount of data that the MR.BWC bits are set to). The reason
341 * this is bad is because at this point, the PCM driver has not
342 * finished initializing the DMA controller.
343 */
344 }
345
346 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
347 ssi_private->playback++;
348
349 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
350 ssi_private->capture++;
351
352 return 0;
353}
354
355/**
356 * fsl_ssi_prepare: prepare the SSI.
357 *
358 * Most of the SSI registers have been programmed in the startup function,
359 * but the word length must be programmed here. Unfortunately, programming
360 * the SxCCR.WL bits requires the SSI to be temporarily disabled. This can
361 * cause a problem with supporting simultaneous playback and capture. If
362 * the SSI is already playing a stream, then that stream may be temporarily
363 * stopped when you start capture.
364 *
365 * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the
366 * clock master.
367 */
368static int fsl_ssi_prepare(struct snd_pcm_substream *substream)
369{
370 struct snd_pcm_runtime *runtime = substream->runtime;
371 struct snd_soc_pcm_runtime *rtd = substream->private_data;
372 struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
373
374 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
375 u32 wl;
376
377 wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format));
378
379 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
380
381 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
382 clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
383 else
384 clrsetbits_be32(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
385
386 setbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
387
388 return 0;
389}
390
391/**
392 * fsl_ssi_trigger: start and stop the DMA transfer.
393 *
394 * This function is called by ALSA to start, stop, pause, and resume the DMA
395 * transfer of data.
396 *
397 * The DMA channel is in external master start and pause mode, which
398 * means the SSI completely controls the flow of data.
399 */
400static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd)
401{
402 struct snd_soc_pcm_runtime *rtd = substream->private_data;
403 struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
404 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
405
406 switch (cmd) {
407 case SNDRV_PCM_TRIGGER_START:
408 case SNDRV_PCM_TRIGGER_RESUME:
409 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
410 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
411 setbits32(&ssi->scr, CCSR_SSI_SCR_TE);
412 } else {
413 setbits32(&ssi->scr, CCSR_SSI_SCR_RE);
414
415 /*
416 * I think we need this delay to allow time for the SSI
417 * to put data into its FIFO. Without it, ALSA starts
418 * to complain about overruns.
419 */
420 msleep(1);
421 }
422 break;
423
424 case SNDRV_PCM_TRIGGER_STOP:
425 case SNDRV_PCM_TRIGGER_SUSPEND:
426 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
427 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
428 clrbits32(&ssi->scr, CCSR_SSI_SCR_TE);
429 else
430 clrbits32(&ssi->scr, CCSR_SSI_SCR_RE);
431 break;
432
433 default:
434 return -EINVAL;
435 }
436
437 return 0;
438}
439
440/**
441 * fsl_ssi_shutdown: shutdown the SSI
442 *
443 * Shutdown the SSI if there are no other substreams open.
444 */
445static void fsl_ssi_shutdown(struct snd_pcm_substream *substream)
446{
447 struct snd_soc_pcm_runtime *rtd = substream->private_data;
448 struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
449
450 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
451 ssi_private->playback--;
452
453 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
454 ssi_private->capture--;
455
456 /*
457 * If this is the last active substream, disable the SSI and release
458 * the IRQ.
459 */
460 if (!ssi_private->playback && !ssi_private->capture) {
461 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
462
463 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
464
465 free_irq(ssi_private->irq, ssi_private);
466 }
467}
468
469/**
470 * fsl_ssi_set_sysclk: set the clock frequency and direction
471 *
472 * This function is called by the machine driver to tell us what the clock
473 * frequency and direction are.
474 *
475 * Currently, we only support operating as a clock slave (SND_SOC_CLOCK_IN),
476 * and we don't care about the frequency. Return an error if the direction
477 * is not SND_SOC_CLOCK_IN.
478 *
479 * @clk_id: reserved, should be zero
480 * @freq: the frequency of the given clock ID, currently ignored
481 * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master)
482 */
483static int fsl_ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai,
484 int clk_id, unsigned int freq, int dir)
485{
486
487 return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
488}
489
490/**
491 * fsl_ssi_set_fmt: set the serial format.
492 *
493 * This function is called by the machine driver to tell us what serial
494 * format to use.
495 *
496 * Currently, we only support I2S mode. Return an error if the format is
497 * not SND_SOC_DAIFMT_I2S.
498 *
499 * @format: one of SND_SOC_DAIFMT_xxx
500 */
501static int fsl_ssi_set_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int format)
502{
503 return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
504}
505
506/**
507 * fsl_ssi_dai_template: template CPU DAI for the SSI
508 */
509static struct snd_soc_cpu_dai fsl_ssi_dai_template = {
510 .playback = {
511 /* The SSI does not support monaural audio. */
512 .channels_min = 2,
513 .channels_max = 2,
514 .rates = FSLSSI_I2S_RATES,
515 .formats = FSLSSI_I2S_FORMATS,
516 },
517 .capture = {
518 .channels_min = 2,
519 .channels_max = 2,
520 .rates = FSLSSI_I2S_RATES,
521 .formats = FSLSSI_I2S_FORMATS,
522 },
523 .ops = {
524 .startup = fsl_ssi_startup,
525 .prepare = fsl_ssi_prepare,
526 .shutdown = fsl_ssi_shutdown,
527 .trigger = fsl_ssi_trigger,
528 },
529 .dai_ops = {
530 .set_sysclk = fsl_ssi_set_sysclk,
531 .set_fmt = fsl_ssi_set_fmt,
532 },
533};
534
535/**
536 * fsl_sysfs_ssi_show: display SSI statistics
537 *
538 * Display the statistics for the current SSI device.
539 */
540static ssize_t fsl_sysfs_ssi_show(struct device *dev,
541 struct device_attribute *attr, char *buf)
542{
543 struct fsl_ssi_private *ssi_private =
544 container_of(attr, struct fsl_ssi_private, dev_attr);
545 ssize_t length;
546
547 length = sprintf(buf, "rfrc=%u", ssi_private->stats.rfrc);
548 length += sprintf(buf + length, "\ttfrc=%u", ssi_private->stats.tfrc);
549 length += sprintf(buf + length, "\tcmdau=%u", ssi_private->stats.cmdau);
550 length += sprintf(buf + length, "\tcmddu=%u", ssi_private->stats.cmddu);
551 length += sprintf(buf + length, "\trxt=%u", ssi_private->stats.rxt);
552 length += sprintf(buf + length, "\trdr1=%u", ssi_private->stats.rdr1);
553 length += sprintf(buf + length, "\trdr0=%u", ssi_private->stats.rdr0);
554 length += sprintf(buf + length, "\ttde1=%u", ssi_private->stats.tde1);
555 length += sprintf(buf + length, "\ttde0=%u", ssi_private->stats.tde0);
556 length += sprintf(buf + length, "\troe1=%u", ssi_private->stats.roe1);
557 length += sprintf(buf + length, "\troe0=%u", ssi_private->stats.roe0);
558 length += sprintf(buf + length, "\ttue1=%u", ssi_private->stats.tue1);
559 length += sprintf(buf + length, "\ttue0=%u", ssi_private->stats.tue0);
560 length += sprintf(buf + length, "\ttfs=%u", ssi_private->stats.tfs);
561 length += sprintf(buf + length, "\trfs=%u", ssi_private->stats.rfs);
562 length += sprintf(buf + length, "\ttls=%u", ssi_private->stats.tls);
563 length += sprintf(buf + length, "\trls=%u", ssi_private->stats.rls);
564 length += sprintf(buf + length, "\trff1=%u", ssi_private->stats.rff1);
565 length += sprintf(buf + length, "\trff0=%u", ssi_private->stats.rff0);
566 length += sprintf(buf + length, "\ttfe1=%u", ssi_private->stats.tfe1);
567 length += sprintf(buf + length, "\ttfe0=%u\n", ssi_private->stats.tfe0);
568
569 return length;
570}
571
572/**
573 * fsl_ssi_create_dai: create a snd_soc_cpu_dai structure
574 *
575 * This function is called by the machine driver to create a snd_soc_cpu_dai
576 * structure. The function creates an ssi_private object, which contains
577 * the snd_soc_cpu_dai. It also creates the sysfs statistics device.
578 */
579struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
580{
581 struct snd_soc_cpu_dai *fsl_ssi_dai;
582 struct fsl_ssi_private *ssi_private;
583 int ret = 0;
584 struct device_attribute *dev_attr;
585
586 ssi_private = kzalloc(sizeof(struct fsl_ssi_private), GFP_KERNEL);
587 if (!ssi_private) {
588 dev_err(ssi_info->dev, "could not allocate DAI object\n");
589 return NULL;
590 }
591 memcpy(&ssi_private->cpu_dai, &fsl_ssi_dai_template,
592 sizeof(struct snd_soc_cpu_dai));
593
594 fsl_ssi_dai = &ssi_private->cpu_dai;
595 dev_attr = &ssi_private->dev_attr;
596
597 sprintf(ssi_private->name, "ssi%u", (u8) ssi_info->id);
598 ssi_private->ssi = ssi_info->ssi;
599 ssi_private->ssi_phys = ssi_info->ssi_phys;
600 ssi_private->irq = ssi_info->irq;
601 ssi_private->dev = ssi_info->dev;
602
603 ssi_private->dev->driver_data = fsl_ssi_dai;
604
605 /* Initialize the the device_attribute structure */
606 dev_attr->attr.name = "ssi-stats";
607 dev_attr->attr.mode = S_IRUGO;
608 dev_attr->show = fsl_sysfs_ssi_show;
609
610 ret = device_create_file(ssi_private->dev, dev_attr);
611 if (ret) {
612 dev_err(ssi_info->dev, "could not create sysfs %s file\n",
613 ssi_private->dev_attr.attr.name);
614 kfree(fsl_ssi_dai);
615 return NULL;
616 }
617
618 fsl_ssi_dai->private_data = ssi_private;
619 fsl_ssi_dai->name = ssi_private->name;
620 fsl_ssi_dai->id = ssi_info->id;
621
622 return fsl_ssi_dai;
623}
624EXPORT_SYMBOL_GPL(fsl_ssi_create_dai);
625
626/**
627 * fsl_ssi_destroy_dai: destroy the snd_soc_cpu_dai object
628 *
629 * This function undoes the operations of fsl_ssi_create_dai()
630 */
631void fsl_ssi_destroy_dai(struct snd_soc_cpu_dai *fsl_ssi_dai)
632{
633 struct fsl_ssi_private *ssi_private =
634 container_of(fsl_ssi_dai, struct fsl_ssi_private, cpu_dai);
635
636 device_remove_file(ssi_private->dev, &ssi_private->dev_attr);
637
638 kfree(ssi_private);
639}
640EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai);
641
642MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
643MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
644MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
new file mode 100644
index 000000000000..c5ce88e15651
--- /dev/null
+++ b/sound/soc/fsl/fsl_ssi.h
@@ -0,0 +1,224 @@
1/*
2 * fsl_ssi.h - ALSA SSI interface for the Freescale MPC8610 SoC
3 *
4 * Author: Timur Tabi <timur@freescale.com>
5 *
6 * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed
7 * under the terms of the GNU General Public License version 2. This
8 * program is licensed "as is" without any warranty of any kind, whether
9 * express or implied.
10 */
11
12#ifndef _MPC8610_I2S_H
13#define _MPC8610_I2S_H
14
15/* SSI Register Map */
16struct ccsr_ssi {
17 __be32 stx0; /* 0x.0000 - SSI Transmit Data Register 0 */
18 __be32 stx1; /* 0x.0004 - SSI Transmit Data Register 1 */
19 __be32 srx0; /* 0x.0008 - SSI Receive Data Register 0 */
20 __be32 srx1; /* 0x.000C - SSI Receive Data Register 1 */
21 __be32 scr; /* 0x.0010 - SSI Control Register */
22 __be32 sisr; /* 0x.0014 - SSI Interrupt Status Register Mixed */
23 __be32 sier; /* 0x.0018 - SSI Interrupt Enable Register */
24 __be32 stcr; /* 0x.001C - SSI Transmit Configuration Register */
25 __be32 srcr; /* 0x.0020 - SSI Receive Configuration Register */
26 __be32 stccr; /* 0x.0024 - SSI Transmit Clock Control Register */
27 __be32 srccr; /* 0x.0028 - SSI Receive Clock Control Register */
28 __be32 sfcsr; /* 0x.002C - SSI FIFO Control/Status Register */
29 __be32 str; /* 0x.0030 - SSI Test Register */
30 __be32 sor; /* 0x.0034 - SSI Option Register */
31 __be32 sacnt; /* 0x.0038 - SSI AC97 Control Register */
32 __be32 sacadd; /* 0x.003C - SSI AC97 Command Address Register */
33 __be32 sacdat; /* 0x.0040 - SSI AC97 Command Data Register */
34 __be32 satag; /* 0x.0044 - SSI AC97 Tag Register */
35 __be32 stmsk; /* 0x.0048 - SSI Transmit Time Slot Mask Register */
36 __be32 srmsk; /* 0x.004C - SSI Receive Time Slot Mask Register */
37 __be32 saccst; /* 0x.0050 - SSI AC97 Channel Status Register */
38 __be32 saccen; /* 0x.0054 - SSI AC97 Channel Enable Register */
39 __be32 saccdis; /* 0x.0058 - SSI AC97 Channel Disable Register */
40};
41
42#define CCSR_SSI_SCR_RFR_CLK_DIS 0x00000800
43#define CCSR_SSI_SCR_TFR_CLK_DIS 0x00000400
44#define CCSR_SSI_SCR_TCH_EN 0x00000100
45#define CCSR_SSI_SCR_SYS_CLK_EN 0x00000080
46#define CCSR_SSI_SCR_I2S_MODE_MASK 0x00000060
47#define CCSR_SSI_SCR_I2S_MODE_NORMAL 0x00000000
48#define CCSR_SSI_SCR_I2S_MODE_MASTER 0x00000020
49#define CCSR_SSI_SCR_I2S_MODE_SLAVE 0x00000040
50#define CCSR_SSI_SCR_SYN 0x00000010
51#define CCSR_SSI_SCR_NET 0x00000008
52#define CCSR_SSI_SCR_RE 0x00000004
53#define CCSR_SSI_SCR_TE 0x00000002
54#define CCSR_SSI_SCR_SSIEN 0x00000001
55
56#define CCSR_SSI_SISR_RFRC 0x01000000
57#define CCSR_SSI_SISR_TFRC 0x00800000
58#define CCSR_SSI_SISR_CMDAU 0x00040000
59#define CCSR_SSI_SISR_CMDDU 0x00020000
60#define CCSR_SSI_SISR_RXT 0x00010000
61#define CCSR_SSI_SISR_RDR1 0x00008000
62#define CCSR_SSI_SISR_RDR0 0x00004000
63#define CCSR_SSI_SISR_TDE1 0x00002000
64#define CCSR_SSI_SISR_TDE0 0x00001000
65#define CCSR_SSI_SISR_ROE1 0x00000800
66#define CCSR_SSI_SISR_ROE0 0x00000400
67#define CCSR_SSI_SISR_TUE1 0x00000200
68#define CCSR_SSI_SISR_TUE0 0x00000100
69#define CCSR_SSI_SISR_TFS 0x00000080
70#define CCSR_SSI_SISR_RFS 0x00000040
71#define CCSR_SSI_SISR_TLS 0x00000020
72#define CCSR_SSI_SISR_RLS 0x00000010
73#define CCSR_SSI_SISR_RFF1 0x00000008
74#define CCSR_SSI_SISR_RFF0 0x00000004
75#define CCSR_SSI_SISR_TFE1 0x00000002
76#define CCSR_SSI_SISR_TFE0 0x00000001
77
78#define CCSR_SSI_SIER_RFRC_EN 0x01000000
79#define CCSR_SSI_SIER_TFRC_EN 0x00800000
80#define CCSR_SSI_SIER_RDMAE 0x00400000
81#define CCSR_SSI_SIER_RIE 0x00200000
82#define CCSR_SSI_SIER_TDMAE 0x00100000
83#define CCSR_SSI_SIER_TIE 0x00080000
84#define CCSR_SSI_SIER_CMDAU_EN 0x00040000
85#define CCSR_SSI_SIER_CMDDU_EN 0x00020000
86#define CCSR_SSI_SIER_RXT_EN 0x00010000
87#define CCSR_SSI_SIER_RDR1_EN 0x00008000
88#define CCSR_SSI_SIER_RDR0_EN 0x00004000
89#define CCSR_SSI_SIER_TDE1_EN 0x00002000
90#define CCSR_SSI_SIER_TDE0_EN 0x00001000
91#define CCSR_SSI_SIER_ROE1_EN 0x00000800
92#define CCSR_SSI_SIER_ROE0_EN 0x00000400
93#define CCSR_SSI_SIER_TUE1_EN 0x00000200
94#define CCSR_SSI_SIER_TUE0_EN 0x00000100
95#define CCSR_SSI_SIER_TFS_EN 0x00000080
96#define CCSR_SSI_SIER_RFS_EN 0x00000040
97#define CCSR_SSI_SIER_TLS_EN 0x00000020
98#define CCSR_SSI_SIER_RLS_EN 0x00000010
99#define CCSR_SSI_SIER_RFF1_EN 0x00000008
100#define CCSR_SSI_SIER_RFF0_EN 0x00000004
101#define CCSR_SSI_SIER_TFE1_EN 0x00000002
102#define CCSR_SSI_SIER_TFE0_EN 0x00000001
103
104#define CCSR_SSI_STCR_TXBIT0 0x00000200
105#define CCSR_SSI_STCR_TFEN1 0x00000100
106#define CCSR_SSI_STCR_TFEN0 0x00000080
107#define CCSR_SSI_STCR_TFDIR 0x00000040
108#define CCSR_SSI_STCR_TXDIR 0x00000020
109#define CCSR_SSI_STCR_TSHFD 0x00000010
110#define CCSR_SSI_STCR_TSCKP 0x00000008
111#define CCSR_SSI_STCR_TFSI 0x00000004
112#define CCSR_SSI_STCR_TFSL 0x00000002
113#define CCSR_SSI_STCR_TEFS 0x00000001
114
115#define CCSR_SSI_SRCR_RXEXT 0x00000400
116#define CCSR_SSI_SRCR_RXBIT0 0x00000200
117#define CCSR_SSI_SRCR_RFEN1 0x00000100
118#define CCSR_SSI_SRCR_RFEN0 0x00000080
119#define CCSR_SSI_SRCR_RFDIR 0x00000040
120#define CCSR_SSI_SRCR_RXDIR 0x00000020
121#define CCSR_SSI_SRCR_RSHFD 0x00000010
122#define CCSR_SSI_SRCR_RSCKP 0x00000008
123#define CCSR_SSI_SRCR_RFSI 0x00000004
124#define CCSR_SSI_SRCR_RFSL 0x00000002
125#define CCSR_SSI_SRCR_REFS 0x00000001
126
127/* STCCR and SRCCR */
128#define CCSR_SSI_SxCCR_DIV2 0x00040000
129#define CCSR_SSI_SxCCR_PSR 0x00020000
130#define CCSR_SSI_SxCCR_WL_SHIFT 13
131#define CCSR_SSI_SxCCR_WL_MASK 0x0001E000
132#define CCSR_SSI_SxCCR_WL(x) \
133 (((((x) / 2) - 1) << CCSR_SSI_SxCCR_WL_SHIFT) & CCSR_SSI_SxCCR_WL_MASK)
134#define CCSR_SSI_SxCCR_DC_SHIFT 8
135#define CCSR_SSI_SxCCR_DC_MASK 0x00001F00
136#define CCSR_SSI_SxCCR_DC(x) \
137 ((((x) - 1) << CCSR_SSI_SxCCR_DC_SHIFT) & CCSR_SSI_SxCCR_DC_MASK)
138#define CCSR_SSI_SxCCR_PM_SHIFT 0
139#define CCSR_SSI_SxCCR_PM_MASK 0x000000FF
140#define CCSR_SSI_SxCCR_PM(x) \
141 ((((x) - 1) << CCSR_SSI_SxCCR_PM_SHIFT) & CCSR_SSI_SxCCR_PM_MASK)
142
143/*
144 * The xFCNT bits are read-only, and the xFWM bits are read/write. Use the
145 * CCSR_SSI_SFCSR_xFCNTy() macros to read the FIFO counters, and use the
146 * CCSR_SSI_SFCSR_xFWMy() macros to set the watermarks.
147 */
148#define CCSR_SSI_SFCSR_RFCNT1_SHIFT 28
149#define CCSR_SSI_SFCSR_RFCNT1_MASK 0xF0000000
150#define CCSR_SSI_SFCSR_RFCNT1(x) \
151 (((x) & CCSR_SSI_SFCSR_RFCNT1_MASK) >> CCSR_SSI_SFCSR_RFCNT1_SHIFT)
152#define CCSR_SSI_SFCSR_TFCNT1_SHIFT 24
153#define CCSR_SSI_SFCSR_TFCNT1_MASK 0x0F000000
154#define CCSR_SSI_SFCSR_TFCNT1(x) \
155 (((x) & CCSR_SSI_SFCSR_TFCNT1_MASK) >> CCSR_SSI_SFCSR_TFCNT1_SHIFT)
156#define CCSR_SSI_SFCSR_RFWM1_SHIFT 20
157#define CCSR_SSI_SFCSR_RFWM1_MASK 0x00F00000
158#define CCSR_SSI_SFCSR_RFWM1(x) \
159 (((x) << CCSR_SSI_SFCSR_RFWM1_SHIFT) & CCSR_SSI_SFCSR_RFWM1_MASK)
160#define CCSR_SSI_SFCSR_TFWM1_SHIFT 16
161#define CCSR_SSI_SFCSR_TFWM1_MASK 0x000F0000
162#define CCSR_SSI_SFCSR_TFWM1(x) \
163 (((x) << CCSR_SSI_SFCSR_TFWM1_SHIFT) & CCSR_SSI_SFCSR_TFWM1_MASK)
164#define CCSR_SSI_SFCSR_RFCNT0_SHIFT 12
165#define CCSR_SSI_SFCSR_RFCNT0_MASK 0x0000F000
166#define CCSR_SSI_SFCSR_RFCNT0(x) \
167 (((x) & CCSR_SSI_SFCSR_RFCNT0_MASK) >> CCSR_SSI_SFCSR_RFCNT0_SHIFT)
168#define CCSR_SSI_SFCSR_TFCNT0_SHIFT 8
169#define CCSR_SSI_SFCSR_TFCNT0_MASK 0x00000F00
170#define CCSR_SSI_SFCSR_TFCNT0(x) \
171 (((x) & CCSR_SSI_SFCSR_TFCNT0_MASK) >> CCSR_SSI_SFCSR_TFCNT0_SHIFT)
172#define CCSR_SSI_SFCSR_RFWM0_SHIFT 4
173#define CCSR_SSI_SFCSR_RFWM0_MASK 0x000000F0
174#define CCSR_SSI_SFCSR_RFWM0(x) \
175 (((x) << CCSR_SSI_SFCSR_RFWM0_SHIFT) & CCSR_SSI_SFCSR_RFWM0_MASK)
176#define CCSR_SSI_SFCSR_TFWM0_SHIFT 0
177#define CCSR_SSI_SFCSR_TFWM0_MASK 0x0000000F
178#define CCSR_SSI_SFCSR_TFWM0(x) \
179 (((x) << CCSR_SSI_SFCSR_TFWM0_SHIFT) & CCSR_SSI_SFCSR_TFWM0_MASK)
180
181#define CCSR_SSI_STR_TEST 0x00008000
182#define CCSR_SSI_STR_RCK2TCK 0x00004000
183#define CCSR_SSI_STR_RFS2TFS 0x00002000
184#define CCSR_SSI_STR_RXSTATE(x) (((x) >> 8) & 0x1F)
185#define CCSR_SSI_STR_TXD2RXD 0x00000080
186#define CCSR_SSI_STR_TCK2RCK 0x00000040
187#define CCSR_SSI_STR_TFS2RFS 0x00000020
188#define CCSR_SSI_STR_TXSTATE(x) ((x) & 0x1F)
189
190#define CCSR_SSI_SOR_CLKOFF 0x00000040
191#define CCSR_SSI_SOR_RX_CLR 0x00000020
192#define CCSR_SSI_SOR_TX_CLR 0x00000010
193#define CCSR_SSI_SOR_INIT 0x00000008
194#define CCSR_SSI_SOR_WAIT_SHIFT 1
195#define CCSR_SSI_SOR_WAIT_MASK 0x00000006
196#define CCSR_SSI_SOR_WAIT(x) (((x) & 3) << CCSR_SSI_SOR_WAIT_SHIFT)
197#define CCSR_SSI_SOR_SYNRST 0x00000001
198
199/* Instantiation data for an SSI interface
200 *
201 * This structure contains all the information that the the SSI driver needs
202 * to instantiate an SSI interface with ALSA. The machine driver should
203 * create this structure, fill it in, call fsl_ssi_create_dai(), and then
204 * delete the structure.
205 *
206 * id: which SSI this is (0, 1, etc. )
207 * ssi: pointer to the SSI's registers
208 * ssi_phys: physical address of the SSI registers
209 * irq: IRQ of this SSI
210 * dev: struct device, used to create the sysfs statistics file
211*/
212struct fsl_ssi_info {
213 unsigned int id;
214 struct ccsr_ssi __iomem *ssi;
215 dma_addr_t ssi_phys;
216 unsigned int irq;
217 struct device *dev;
218};
219
220struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info);
221void fsl_ssi_destroy_dai(struct snd_soc_cpu_dai *fsl_ssi_dai);
222
223#endif
224
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
new file mode 100644
index 000000000000..f26c4b2e8b6e
--- /dev/null
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -0,0 +1,631 @@
1/**
2 * Freescale MPC8610HPCD ALSA SoC Fabric driver
3 *
4 * Author: Timur Tabi <timur@freescale.com>
5 *
6 * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed
7 * under the terms of the GNU General Public License version 2. This
8 * program is licensed "as is" without any warranty of any kind, whether
9 * express or implied.
10 */
11
12#include <linux/module.h>
13#include <linux/interrupt.h>
14#include <linux/of_device.h>
15#include <linux/of_platform.h>
16#include <sound/soc.h>
17#include <asm/immap_86xx.h>
18
19#include "../codecs/cs4270.h"
20#include "fsl_dma.h"
21#include "fsl_ssi.h"
22
23/**
24 * mpc8610_hpcd_data: fabric-specific ASoC device data
25 *
26 * This structure contains data for a single sound platform device on an
27 * MPC8610 HPCD. Some of the data is taken from the device tree.
28 */
29struct mpc8610_hpcd_data {
30 struct snd_soc_device sound_devdata;
31 struct snd_soc_dai_link dai;
32 struct snd_soc_machine machine;
33 unsigned int dai_format;
34 unsigned int codec_clk_direction;
35 unsigned int cpu_clk_direction;
36 unsigned int clk_frequency;
37 struct ccsr_guts __iomem *guts;
38 struct ccsr_ssi __iomem *ssi;
39 unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */
40 unsigned int ssi_irq;
41 unsigned int dma_id; /* 0 = DMA1, 1 = DMA2, etc */
42 unsigned int dma_irq[2];
43 struct ccsr_dma_channel __iomem *dma[2];
44 unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
45};
46
47/**
48 * mpc8610_hpcd_machine_probe: initalize the board
49 *
50 * This function is called when platform_device_add() is called. It is used
51 * to initialize the board-specific hardware.
52 *
53 * Here we program the DMACR and PMUXCR registers.
54 */
55static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device)
56{
57 struct mpc8610_hpcd_data *machine_data =
58 sound_device->dev.platform_data;
59
60 /* Program the signal routing between the SSI and the DMA */
61 guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1,
62 machine_data->dma_channel_id[0], CCSR_GUTS_DMACR_DEV_SSI);
63 guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1,
64 machine_data->dma_channel_id[1], CCSR_GUTS_DMACR_DEV_SSI);
65
66 guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id,
67 machine_data->dma_channel_id[0], 0);
68 guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id,
69 machine_data->dma_channel_id[1], 0);
70
71 guts_set_pmuxcr_dma(machine_data->guts, 1, 0, 0);
72 guts_set_pmuxcr_dma(machine_data->guts, 1, 3, 0);
73 guts_set_pmuxcr_dma(machine_data->guts, 0, 3, 0);
74
75 switch (machine_data->ssi_id) {
76 case 0:
77 clrsetbits_be32(&machine_data->guts->pmuxcr,
78 CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_SSI);
79 break;
80 case 1:
81 clrsetbits_be32(&machine_data->guts->pmuxcr,
82 CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_SSI);
83 break;
84 }
85
86 return 0;
87}
88
89/**
90 * mpc8610_hpcd_startup: program the board with various hardware parameters
91 *
92 * This function takes board-specific information, like clock frequencies
93 * and serial data formats, and passes that information to the codec and
94 * transport drivers.
95 */
96static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
97{
98 struct snd_soc_pcm_runtime *rtd = substream->private_data;
99 struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
100 struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
101 struct mpc8610_hpcd_data *machine_data =
102 rtd->socdev->dev->platform_data;
103 int ret = 0;
104
105 /* Tell the CPU driver what the serial protocol is. */
106 if (cpu_dai->dai_ops.set_fmt) {
107 ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
108 machine_data->dai_format);
109 if (ret < 0) {
110 dev_err(substream->pcm->card->dev,
111 "could not set CPU driver audio format\n");
112 return ret;
113 }
114 }
115
116 /* Tell the codec driver what the serial protocol is. */
117 if (codec_dai->dai_ops.set_fmt) {
118 ret = codec_dai->dai_ops.set_fmt(codec_dai,
119 machine_data->dai_format);
120 if (ret < 0) {
121 dev_err(substream->pcm->card->dev,
122 "could not set codec driver audio format\n");
123 return ret;
124 }
125 }
126
127 /*
128 * Tell the CPU driver what the clock frequency is, and whether it's a
129 * slave or master.
130 */
131 if (cpu_dai->dai_ops.set_sysclk) {
132 ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, 0,
133 machine_data->clk_frequency,
134 machine_data->cpu_clk_direction);
135 if (ret < 0) {
136 dev_err(substream->pcm->card->dev,
137 "could not set CPU driver clock parameters\n");
138 return ret;
139 }
140 }
141
142 /*
143 * Tell the codec driver what the MCLK frequency is, and whether it's
144 * a slave or master.
145 */
146 if (codec_dai->dai_ops.set_sysclk) {
147 ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0,
148 machine_data->clk_frequency,
149 machine_data->codec_clk_direction);
150 if (ret < 0) {
151 dev_err(substream->pcm->card->dev,
152 "could not set codec driver clock params\n");
153 return ret;
154 }
155 }
156
157 return 0;
158}
159
160/**
161 * mpc8610_hpcd_machine_remove: Remove the sound device
162 *
163 * This function is called to remove the sound device for one SSI. We
164 * de-program the DMACR and PMUXCR register.
165 */
166int mpc8610_hpcd_machine_remove(struct platform_device *sound_device)
167{
168 struct mpc8610_hpcd_data *machine_data =
169 sound_device->dev.platform_data;
170
171 /* Restore the signal routing */
172
173 guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1,
174 machine_data->dma_channel_id[0], 0);
175 guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1,
176 machine_data->dma_channel_id[1], 0);
177
178 switch (machine_data->ssi_id) {
179 case 0:
180 clrsetbits_be32(&machine_data->guts->pmuxcr,
181 CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_LA);
182 break;
183 case 1:
184 clrsetbits_be32(&machine_data->guts->pmuxcr,
185 CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI1_LA);
186 break;
187 }
188
189 return 0;
190}
191
192/**
193 * mpc8610_hpcd_ops: ASoC fabric driver operations
194 */
195static struct snd_soc_ops mpc8610_hpcd_ops = {
196 .startup = mpc8610_hpcd_startup,
197};
198
199/**
200 * mpc8610_hpcd_machine: ASoC machine data
201 */
202static struct snd_soc_machine mpc8610_hpcd_machine = {
203 .probe = mpc8610_hpcd_machine_probe,
204 .remove = mpc8610_hpcd_machine_remove,
205 .name = "MPC8610 HPCD",
206 .num_links = 1,
207};
208
209/**
210 * mpc8610_hpcd_probe: OF probe function for the fabric driver
211 *
212 * This function gets called when an SSI node is found in the device tree.
213 *
214 * Although this is a fabric driver, the SSI node is the "master" node with
215 * respect to audio hardware connections. Therefore, we create a new ASoC
216 * device for each new SSI node that has a codec attached.
217 *
218 * FIXME: Currently, we only support one DMA controller, so if there are
219 * multiple SSI nodes with codecs, only the first will be supported.
220 *
221 * FIXME: Even if we did support multiple DMA controllers, we have no
222 * mechanism for assigning DMA controllers and channels to the individual
223 * SSI devices. We also probably aren't compatible with the generic Elo DMA
224 * device driver.
225 */
226static int mpc8610_hpcd_probe(struct of_device *ofdev,
227 const struct of_device_id *match)
228{
229 struct device_node *np = ofdev->node;
230 struct device_node *codec_np = NULL;
231 struct device_node *guts_np = NULL;
232 struct device_node *dma_np = NULL;
233 struct device_node *dma_channel_np = NULL;
234 const phandle *codec_ph;
235 const char *sprop;
236 const u32 *iprop;
237 struct resource res;
238 struct platform_device *sound_device = NULL;
239 struct mpc8610_hpcd_data *machine_data;
240 struct fsl_ssi_info ssi_info;
241 struct fsl_dma_info dma_info;
242 int ret = -ENODEV;
243
244 machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL);
245 if (!machine_data)
246 return -ENOMEM;
247
248 memset(&ssi_info, 0, sizeof(ssi_info));
249 memset(&dma_info, 0, sizeof(dma_info));
250
251 ssi_info.dev = &ofdev->dev;
252
253 /*
254 * We are only interested in SSIs with a codec phandle in them, so let's
255 * make sure this SSI has one.
256 */
257 codec_ph = of_get_property(np, "codec-handle", NULL);
258 if (!codec_ph)
259 goto error;
260
261 codec_np = of_find_node_by_phandle(*codec_ph);
262 if (!codec_np)
263 goto error;
264
265 /* The MPC8610 HPCD only knows about the CS4270 codec, so reject
266 anything else. */
267 if (!of_device_is_compatible(codec_np, "cirrus,cs4270"))
268 goto error;
269
270 /* Get the device ID */
271 iprop = of_get_property(np, "cell-index", NULL);
272 if (!iprop) {
273 dev_err(&ofdev->dev, "cell-index property not found\n");
274 ret = -EINVAL;
275 goto error;
276 }
277 machine_data->ssi_id = *iprop;
278 ssi_info.id = *iprop;
279
280 /* Get the serial format and clock direction. */
281 sprop = of_get_property(np, "fsl,mode", NULL);
282 if (!sprop) {
283 dev_err(&ofdev->dev, "fsl,mode property not found\n");
284 ret = -EINVAL;
285 goto error;
286 }
287
288 if (strcasecmp(sprop, "i2s-slave") == 0) {
289 machine_data->dai_format = SND_SOC_DAIFMT_I2S;
290 machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
291 machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
292
293 /*
294 * In i2s-slave mode, the codec has its own clock source, so we
295 * need to get the frequency from the device tree and pass it to
296 * the codec driver.
297 */
298 iprop = of_get_property(codec_np, "clock-frequency", NULL);
299 if (!iprop || !*iprop) {
300 dev_err(&ofdev->dev, "codec bus-frequency property "
301 "is missing or invalid\n");
302 ret = -EINVAL;
303 goto error;
304 }
305 machine_data->clk_frequency = *iprop;
306 } else if (strcasecmp(sprop, "i2s-master") == 0) {
307 machine_data->dai_format = SND_SOC_DAIFMT_I2S;
308 machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
309 machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
310 } else if (strcasecmp(sprop, "lj-slave") == 0) {
311 machine_data->dai_format = SND_SOC_DAIFMT_LEFT_J;
312 machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
313 machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
314 } else if (strcasecmp(sprop, "lj-master") == 0) {
315 machine_data->dai_format = SND_SOC_DAIFMT_LEFT_J;
316 machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
317 machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
318 } else if (strcasecmp(sprop, "rj-master") == 0) {
319 machine_data->dai_format = SND_SOC_DAIFMT_RIGHT_J;
320 machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
321 machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
322 } else if (strcasecmp(sprop, "rj-master") == 0) {
323 machine_data->dai_format = SND_SOC_DAIFMT_RIGHT_J;
324 machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
325 machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
326 } else if (strcasecmp(sprop, "ac97-slave") == 0) {
327 machine_data->dai_format = SND_SOC_DAIFMT_AC97;
328 machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
329 machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
330 } else if (strcasecmp(sprop, "ac97-master") == 0) {
331 machine_data->dai_format = SND_SOC_DAIFMT_AC97;
332 machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
333 machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
334 } else {
335 dev_err(&ofdev->dev,
336 "unrecognized fsl,mode property \"%s\"\n", sprop);
337 ret = -EINVAL;
338 goto error;
339 }
340
341 if (!machine_data->clk_frequency) {
342 dev_err(&ofdev->dev, "unknown clock frequency\n");
343 ret = -EINVAL;
344 goto error;
345 }
346
347 /* Read the SSI information from the device tree */
348 ret = of_address_to_resource(np, 0, &res);
349 if (ret) {
350 dev_err(&ofdev->dev, "could not obtain SSI address\n");
351 goto error;
352 }
353 if (!res.start) {
354 dev_err(&ofdev->dev, "invalid SSI address\n");
355 goto error;
356 }
357 ssi_info.ssi_phys = res.start;
358
359 machine_data->ssi = ioremap(ssi_info.ssi_phys, sizeof(struct ccsr_ssi));
360 if (!machine_data->ssi) {
361 dev_err(&ofdev->dev, "could not map SSI address %x\n",
362 ssi_info.ssi_phys);
363 ret = -EINVAL;
364 goto error;
365 }
366 ssi_info.ssi = machine_data->ssi;
367
368
369 /* Get the IRQ of the SSI */
370 machine_data->ssi_irq = irq_of_parse_and_map(np, 0);
371 if (!machine_data->ssi_irq) {
372 dev_err(&ofdev->dev, "could not get SSI IRQ\n");
373 ret = -EINVAL;
374 goto error;
375 }
376 ssi_info.irq = machine_data->ssi_irq;
377
378
379 /* Map the global utilities registers. */
380 guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
381 if (!guts_np) {
382 dev_err(&ofdev->dev, "could not obtain address of GUTS\n");
383 ret = -EINVAL;
384 goto error;
385 }
386 machine_data->guts = of_iomap(guts_np, 0);
387 of_node_put(guts_np);
388 if (!machine_data->guts) {
389 dev_err(&ofdev->dev, "could not map GUTS\n");
390 ret = -EINVAL;
391 goto error;
392 }
393
394 /* Find the DMA channels to use. For now, we always use the first DMA
395 controller. */
396 for_each_compatible_node(dma_np, NULL, "fsl,mpc8610-dma") {
397 iprop = of_get_property(dma_np, "cell-index", NULL);
398 if (iprop && (*iprop == 0)) {
399 of_node_put(dma_np);
400 break;
401 }
402 }
403 if (!dma_np) {
404 dev_err(&ofdev->dev, "could not find DMA node\n");
405 ret = -EINVAL;
406 goto error;
407 }
408 machine_data->dma_id = *iprop;
409
410 /*
411 * Find the DMA channels to use. For now, we always use DMA channel 0
412 * for playback, and DMA channel 1 for capture.
413 */
414 while ((dma_channel_np = of_get_next_child(dma_np, dma_channel_np))) {
415 iprop = of_get_property(dma_channel_np, "cell-index", NULL);
416 /* Is it DMA channel 0? */
417 if (iprop && (*iprop == 0)) {
418 /* dma_channel[0] and dma_irq[0] are for playback */
419 dma_info.dma_channel[0] = of_iomap(dma_channel_np, 0);
420 dma_info.dma_irq[0] =
421 irq_of_parse_and_map(dma_channel_np, 0);
422 machine_data->dma_channel_id[0] = *iprop;
423 continue;
424 }
425 if (iprop && (*iprop == 1)) {
426 /* dma_channel[1] and dma_irq[1] are for capture */
427 dma_info.dma_channel[1] = of_iomap(dma_channel_np, 0);
428 dma_info.dma_irq[1] =
429 irq_of_parse_and_map(dma_channel_np, 0);
430 machine_data->dma_channel_id[1] = *iprop;
431 continue;
432 }
433 }
434 if (!dma_info.dma_channel[0] || !dma_info.dma_channel[1] ||
435 !dma_info.dma_irq[0] || !dma_info.dma_irq[1]) {
436 dev_err(&ofdev->dev, "could not find DMA channels\n");
437 ret = -EINVAL;
438 goto error;
439 }
440
441 dma_info.ssi_stx_phys = ssi_info.ssi_phys +
442 offsetof(struct ccsr_ssi, stx0);
443 dma_info.ssi_srx_phys = ssi_info.ssi_phys +
444 offsetof(struct ccsr_ssi, srx0);
445
446 /* We have the DMA information, so tell the DMA driver what it is */
447 if (!fsl_dma_configure(&dma_info)) {
448 dev_err(&ofdev->dev, "could not instantiate DMA device\n");
449 ret = -EBUSY;
450 goto error;
451 }
452
453 /*
454 * Initialize our DAI data structure. We should probably get this
455 * information from the device tree.
456 */
457 machine_data->dai.name = "CS4270";
458 machine_data->dai.stream_name = "CS4270";
459
460 machine_data->dai.cpu_dai = fsl_ssi_create_dai(&ssi_info);
461 machine_data->dai.codec_dai = &cs4270_dai; /* The codec_dai we want */
462 machine_data->dai.ops = &mpc8610_hpcd_ops;
463
464 mpc8610_hpcd_machine.dai_link = &machine_data->dai;
465
466 /* Allocate a new audio platform device structure */
467 sound_device = platform_device_alloc("soc-audio", -1);
468 if (!sound_device) {
469 dev_err(&ofdev->dev, "platform device allocation failed\n");
470 ret = -ENOMEM;
471 goto error;
472 }
473
474 machine_data->sound_devdata.machine = &mpc8610_hpcd_machine;
475 machine_data->sound_devdata.codec_dev = &soc_codec_device_cs4270;
476 machine_data->sound_devdata.platform = &fsl_soc_platform;
477
478 sound_device->dev.platform_data = machine_data;
479
480
481 /* Set the platform device and ASoC device to point to each other */
482 platform_set_drvdata(sound_device, &machine_data->sound_devdata);
483
484 machine_data->sound_devdata.dev = &sound_device->dev;
485
486
487 /* Tell ASoC to probe us. This will call mpc8610_hpcd_machine.probe(),
488 if it exists. */
489 ret = platform_device_add(sound_device);
490
491 if (ret) {
492 dev_err(&ofdev->dev, "platform device add failed\n");
493 goto error;
494 }
495
496 dev_set_drvdata(&ofdev->dev, sound_device);
497
498 return 0;
499
500error:
501 of_node_put(codec_np);
502 of_node_put(guts_np);
503 of_node_put(dma_np);
504 of_node_put(dma_channel_np);
505
506 if (sound_device)
507 platform_device_unregister(sound_device);
508
509 if (machine_data->dai.cpu_dai)
510 fsl_ssi_destroy_dai(machine_data->dai.cpu_dai);
511
512 if (ssi_info.ssi)
513 iounmap(ssi_info.ssi);
514
515 if (ssi_info.irq)
516 irq_dispose_mapping(ssi_info.irq);
517
518 if (dma_info.dma_channel[0])
519 iounmap(dma_info.dma_channel[0]);
520
521 if (dma_info.dma_channel[1])
522 iounmap(dma_info.dma_channel[1]);
523
524 if (dma_info.dma_irq[0])
525 irq_dispose_mapping(dma_info.dma_irq[0]);
526
527 if (dma_info.dma_irq[1])
528 irq_dispose_mapping(dma_info.dma_irq[1]);
529
530 if (machine_data->guts)
531 iounmap(machine_data->guts);
532
533 kfree(machine_data);
534
535 return ret;
536}
537
538/**
539 * mpc8610_hpcd_remove: remove the OF device
540 *
541 * This function is called when the OF device is removed.
542 */
543static int mpc8610_hpcd_remove(struct of_device *ofdev)
544{
545 struct platform_device *sound_device = dev_get_drvdata(&ofdev->dev);
546 struct mpc8610_hpcd_data *machine_data =
547 sound_device->dev.platform_data;
548
549 platform_device_unregister(sound_device);
550
551 if (machine_data->dai.cpu_dai)
552 fsl_ssi_destroy_dai(machine_data->dai.cpu_dai);
553
554 if (machine_data->ssi)
555 iounmap(machine_data->ssi);
556
557 if (machine_data->dma[0])
558 iounmap(machine_data->dma[0]);
559
560 if (machine_data->dma[1])
561 iounmap(machine_data->dma[1]);
562
563 if (machine_data->dma_irq[0])
564 irq_dispose_mapping(machine_data->dma_irq[0]);
565
566 if (machine_data->dma_irq[1])
567 irq_dispose_mapping(machine_data->dma_irq[1]);
568
569 if (machine_data->guts)
570 iounmap(machine_data->guts);
571
572 kfree(machine_data);
573 sound_device->dev.platform_data = NULL;
574
575 dev_set_drvdata(&ofdev->dev, NULL);
576
577 return 0;
578}
579
580static struct of_device_id mpc8610_hpcd_match[] = {
581 {
582 .compatible = "fsl,mpc8610-ssi",
583 },
584 {}
585};
586MODULE_DEVICE_TABLE(of, mpc8610_hpcd_match);
587
588static struct of_platform_driver mpc8610_hpcd_of_driver = {
589 .owner = THIS_MODULE,
590 .name = "mpc8610_hpcd",
591 .match_table = mpc8610_hpcd_match,
592 .probe = mpc8610_hpcd_probe,
593 .remove = mpc8610_hpcd_remove,
594};
595
596/**
597 * mpc8610_hpcd_init: fabric driver initialization.
598 *
599 * This function is called when this module is loaded.
600 */
601static int __init mpc8610_hpcd_init(void)
602{
603 int ret;
604
605 printk(KERN_INFO "Freescale MPC8610 HPCD ALSA SoC fabric driver\n");
606
607 ret = of_register_platform_driver(&mpc8610_hpcd_of_driver);
608
609 if (ret)
610 printk(KERN_ERR
611 "mpc8610-hpcd: failed to register platform driver\n");
612
613 return ret;
614}
615
616/**
617 * mpc8610_hpcd_exit: fabric driver exit
618 *
619 * This function is called when this driver is unloaded.
620 */
621static void __exit mpc8610_hpcd_exit(void)
622{
623 of_unregister_platform_driver(&mpc8610_hpcd_of_driver);
624}
625
626module_init(mpc8610_hpcd_init);
627module_exit(mpc8610_hpcd_exit);
628
629MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
630MODULE_DESCRIPTION("Freescale MPC8610 HPCD ALSA SoC fabric driver");
631MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index a83e22937c27..484f883459e0 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -53,3 +53,12 @@ config SND_PXA2XX_SOC_TOSA
53 help 53 help
54 Say Y if you want to add support for SoC audio on Sharp 54 Say Y if you want to add support for SoC audio on Sharp
55 Zaurus SL-C6000x models (Tosa). 55 Zaurus SL-C6000x models (Tosa).
56
57config SND_PXA2XX_SOC_E800
58 tristate "SoC AC97 Audio support for e800"
59 depends on SND_PXA2XX_SOC && MACH_E800
60 select SND_SOC_WM9712
61 select SND_PXA2XX_SOC_AC97
62 help
63 Say Y if you want to add support for SoC audio on the
64 Toshiba e800 PDA
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index 78e0d6b07d1d..04e5646f75ba 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -11,10 +11,12 @@ obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o
11snd-soc-corgi-objs := corgi.o 11snd-soc-corgi-objs := corgi.o
12snd-soc-poodle-objs := poodle.o 12snd-soc-poodle-objs := poodle.o
13snd-soc-tosa-objs := tosa.o 13snd-soc-tosa-objs := tosa.o
14snd-soc-e800-objs := e800_wm9712.o
14snd-soc-spitz-objs := spitz.o 15snd-soc-spitz-objs := spitz.o
15 16
16obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o 17obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
17obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o 18obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
18obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o 19obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o
20obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o
19obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o 21obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
20 22
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index 5ee51a994ac3..3f34e531bebf 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -22,7 +22,6 @@
22#include <linux/timer.h> 22#include <linux/timer.h>
23#include <linux/interrupt.h> 23#include <linux/interrupt.h>
24#include <linux/platform_device.h> 24#include <linux/platform_device.h>
25#include <sound/driver.h>
26#include <sound/core.h> 25#include <sound/core.h>
27#include <sound/pcm.h> 26#include <sound/pcm.h>
28#include <sound/soc.h> 27#include <sound/soc.h>
diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c
new file mode 100644
index 000000000000..06e8afb25277
--- /dev/null
+++ b/sound/soc/pxa/e800_wm9712.c
@@ -0,0 +1,89 @@
1/*
2 * e800-wm9712.c -- SoC audio for e800
3 *
4 * Based on tosa.c
5 *
6 * Copyright 2007 (c) Ian Molton <spyro@f2s.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; version 2 ONLY.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/device.h>
17
18#include <sound/core.h>
19#include <sound/pcm.h>
20#include <sound/soc.h>
21#include <sound/soc-dapm.h>
22
23#include <asm/mach-types.h>
24#include <asm/arch/pxa-regs.h>
25#include <asm/arch/hardware.h>
26#include <asm/arch/audio.h>
27
28#include "../codecs/wm9712.h"
29#include "pxa2xx-pcm.h"
30#include "pxa2xx-ac97.h"
31
32static struct snd_soc_machine e800;
33
34static struct snd_soc_dai_link e800_dai[] = {
35{
36 .name = "AC97 Aux",
37 .stream_name = "AC97 Aux",
38 .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
39 .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
40},
41};
42
43static struct snd_soc_machine e800 = {
44 .name = "Toshiba e800",
45 .dai_link = e800_dai,
46 .num_links = ARRAY_SIZE(e800_dai),
47};
48
49static struct snd_soc_device e800_snd_devdata = {
50 .machine = &e800,
51 .platform = &pxa2xx_soc_platform,
52 .codec_dev = &soc_codec_dev_wm9712,
53};
54
55static struct platform_device *e800_snd_device;
56
57static int __init e800_init(void)
58{
59 int ret;
60
61 if (!machine_is_e800())
62 return -ENODEV;
63
64 e800_snd_device = platform_device_alloc("soc-audio", -1);
65 if (!e800_snd_device)
66 return -ENOMEM;
67
68 platform_set_drvdata(e800_snd_device, &e800_snd_devdata);
69 e800_snd_devdata.dev = &e800_snd_device->dev;
70 ret = platform_device_add(e800_snd_device);
71
72 if (ret)
73 platform_device_put(e800_snd_device);
74
75 return ret;
76}
77
78static void __exit e800_exit(void)
79{
80 platform_device_unregister(e800_snd_device);
81}
82
83module_init(e800_init);
84module_exit(e800_exit);
85
86/* Module information */
87MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
88MODULE_DESCRIPTION("ALSA SoC driver for e800");
89MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index 0915cf740421..5ae59bd309a3 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -19,7 +19,6 @@
19#include <linux/timer.h> 19#include <linux/timer.h>
20#include <linux/interrupt.h> 20#include <linux/interrupt.h>
21#include <linux/platform_device.h> 21#include <linux/platform_device.h>
22#include <sound/driver.h>
23#include <sound/core.h> 22#include <sound/core.h>
24#include <sound/pcm.h> 23#include <sound/pcm.h>
25#include <sound/soc.h> 24#include <sound/soc.h>
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index 60e6f4677f93..815c15336255 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -17,7 +17,6 @@
17#include <linux/wait.h> 17#include <linux/wait.h>
18#include <linux/delay.h> 18#include <linux/delay.h>
19 19
20#include <sound/driver.h>
21#include <sound/core.h> 20#include <sound/core.h>
22#include <sound/pcm.h> 21#include <sound/pcm.h>
23#include <sound/ac97_codec.h> 22#include <sound/ac97_codec.h>
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 50c5c83f67db..692b90002489 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -18,7 +18,6 @@
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/device.h> 19#include <linux/device.h>
20#include <linux/delay.h> 20#include <linux/delay.h>
21#include <sound/driver.h>
22#include <sound/core.h> 21#include <sound/core.h>
23#include <sound/pcm.h> 22#include <sound/pcm.h>
24#include <sound/initval.h> 23#include <sound/initval.h>
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index 35e8fa3a469c..daeaa4c8b876 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -16,7 +16,6 @@
16#include <linux/slab.h> 16#include <linux/slab.h>
17#include <linux/dma-mapping.h> 17#include <linux/dma-mapping.h>
18 18
19#include <sound/driver.h>
20#include <sound/core.h> 19#include <sound/core.h>
21#include <sound/pcm.h> 20#include <sound/pcm.h>
22#include <sound/pcm_params.h> 21#include <sound/pcm_params.h>
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index 4dd8f35312b3..d56709e15435 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -22,7 +22,6 @@
22#include <linux/timer.h> 22#include <linux/timer.h>
23#include <linux/interrupt.h> 23#include <linux/interrupt.h>
24#include <linux/platform_device.h> 24#include <linux/platform_device.h>
25#include <sound/driver.h>
26#include <sound/core.h> 25#include <sound/core.h>
27#include <sound/pcm.h> 26#include <sound/pcm.h>
28#include <sound/soc.h> 27#include <sound/soc.h>
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index 5504e30acf14..e4d40b528ca4 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -25,7 +25,6 @@
25#include <linux/moduleparam.h> 25#include <linux/moduleparam.h>
26#include <linux/device.h> 26#include <linux/device.h>
27 27
28#include <sound/driver.h>
29#include <sound/core.h> 28#include <sound/core.h>
30#include <sound/pcm.h> 29#include <sound/pcm.h>
31#include <sound/soc.h> 30#include <sound/soc.h>
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 5632a2e1518d..1f6dbfc4caa8 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -10,6 +10,9 @@ config SND_S3C24XX_SOC
10config SND_S3C24XX_SOC_I2S 10config SND_S3C24XX_SOC_I2S
11 tristate 11 tristate
12 12
13config SND_S3C2412_SOC_I2S
14 tristate
15
13config SND_S3C2443_SOC_AC97 16config SND_S3C2443_SOC_AC97
14 tristate 17 tristate
15 select AC97_BUS 18 select AC97_BUS
@@ -34,4 +37,12 @@ config SND_S3C24XX_SOC_SMDK2443_WM9710
34 Say Y if you want to add support for SoC audio on smdk2443 37 Say Y if you want to add support for SoC audio on smdk2443
35 with the WM9710. 38 with the WM9710.
36 39
40config SND_S3C24XX_SOC_LN2440SBC_ALC650
41 tristate "SoC AC97 Audio support for LN2440SBC - ALC650"
42 depends on SND_S3C24XX_SOC
43 select SND_S3C2443_SOC_AC97
44 select SND_SOC_AC97_CODEC
45 help
46 Say Y if you want to add support for SoC audio on ln2440sbc
47 with the ALC650.
37 48
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 13c92f0fa1e4..0aa5fb0b9700 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -1,15 +1,19 @@
1# S3c24XX Platform Support 1# S3c24XX Platform Support
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-s3c2443-ac97-objs := s3c2443-ac97.o 5snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o
5 6
6obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o 7obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
7obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o 8obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
8obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o 9obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o
10obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
9 11
10# S3C24XX Machine Support 12# S3C24XX Machine Support
11snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o 13snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
12snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o 14snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
15snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o
13 16
14obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o 17obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
15obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o 18obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
19obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c
new file mode 100644
index 000000000000..9ed8f2e8da10
--- /dev/null
+++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c
@@ -0,0 +1,85 @@
1/*
2 * SoC audio for ln2440sbc
3 *
4 * Copyright 2007 KonekTel, a.s.
5 * Author: Ivan Kuten
6 * ivan.kuten@promwad.com
7 *
8 * Heavily based on smdk2443_wm9710.c
9 * Copyright 2007 Wolfson Microelectronics PLC.
10 * Author: Graeme Gregory
11 * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
16 *
17 */
18
19#include <linux/module.h>
20#include <linux/device.h>
21#include <sound/core.h>
22#include <sound/pcm.h>
23#include <sound/soc.h>
24#include <sound/soc-dapm.h>
25
26#include "../codecs/ac97.h"
27#include "s3c24xx-pcm.h"
28#include "s3c24xx-ac97.h"
29
30static struct snd_soc_machine ln2440sbc;
31
32static struct snd_soc_dai_link ln2440sbc_dai[] = {
33{
34 .name = "AC97",
35 .stream_name = "AC97 HiFi",
36 .cpu_dai = &s3c2443_ac97_dai[0],
37 .codec_dai = &ac97_dai,
38},
39};
40
41static struct snd_soc_machine ln2440sbc = {
42 .name = "LN2440SBC",
43 .dai_link = ln2440sbc_dai,
44 .num_links = ARRAY_SIZE(ln2440sbc_dai),
45};
46
47static struct snd_soc_device ln2440sbc_snd_ac97_devdata = {
48 .machine = &ln2440sbc,
49 .platform = &s3c24xx_soc_platform,
50 .codec_dev = &soc_codec_dev_ac97,
51};
52
53static struct platform_device *ln2440sbc_snd_ac97_device;
54
55static int __init ln2440sbc_init(void)
56{
57 int ret;
58
59 ln2440sbc_snd_ac97_device = platform_device_alloc("soc-audio", -1);
60 if (!ln2440sbc_snd_ac97_device)
61 return -ENOMEM;
62
63 platform_set_drvdata(ln2440sbc_snd_ac97_device,
64 &ln2440sbc_snd_ac97_devdata);
65 ln2440sbc_snd_ac97_devdata.dev = &ln2440sbc_snd_ac97_device->dev;
66 ret = platform_device_add(ln2440sbc_snd_ac97_device);
67
68 if (ret)
69 platform_device_put(ln2440sbc_snd_ac97_device);
70
71 return ret;
72}
73
74static void __exit ln2440sbc_exit(void)
75{
76 platform_device_unregister(ln2440sbc_snd_ac97_device);
77}
78
79module_init(ln2440sbc_init);
80module_exit(ln2440sbc_exit);
81
82/* Module information */
83MODULE_AUTHOR("Ivan Kuten");
84MODULE_DESCRIPTION("ALSA SoC ALC650 LN2440SBC");
85MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index f1f6b9478af9..6ee115ceb011 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -22,7 +22,6 @@
22#include <linux/interrupt.h> 22#include <linux/interrupt.h>
23#include <linux/platform_device.h> 23#include <linux/platform_device.h>
24#include <linux/i2c.h> 24#include <linux/i2c.h>
25#include <sound/driver.h>
26#include <sound/core.h> 25#include <sound/core.h>
27#include <sound/pcm.h> 26#include <sound/pcm.h>
28#include <sound/soc.h> 27#include <sound/soc.h>
@@ -30,13 +29,15 @@
30 29
31#include <asm/mach-types.h> 30#include <asm/mach-types.h>
32#include <asm/hardware/scoop.h> 31#include <asm/hardware/scoop.h>
33#include <asm/arch/regs-iis.h>
34#include <asm/arch/regs-clock.h> 32#include <asm/arch/regs-clock.h>
35#include <asm/arch/regs-gpio.h> 33#include <asm/arch/regs-gpio.h>
36#include <asm/hardware.h> 34#include <asm/hardware.h>
37#include <asm/arch/audio.h> 35#include <asm/arch/audio.h>
38#include <asm/io.h> 36#include <asm/io.h>
39#include <asm/arch/spi-gpio.h> 37#include <asm/arch/spi-gpio.h>
38
39#include <asm/plat-s3c24xx/regs-iis.h>
40
40#include "../codecs/wm8753.h" 41#include "../codecs/wm8753.h"
41#include "lm4857.h" 42#include "lm4857.h"
42#include "s3c24xx-pcm.h" 43#include "s3c24xx-pcm.h"
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
new file mode 100644
index 000000000000..c4a46dd589b3
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c2412-i2s.c
@@ -0,0 +1,744 @@
1/* sound/soc/s3c24xx/s3c2412-i2s.c
2 *
3 * ALSA Soc Audio Layer - S3C2412 I2S driver
4 *
5 * Copyright (c) 2006 Wolfson Microelectronics PLC.
6 * Graeme Gregory graeme.gregory@wolfsonmicro.com
7 * linux@wolfsonmicro.com
8 *
9 * Copyright (c) 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
26#include <sound/core.h>
27#include <sound/pcm.h>
28#include <sound/pcm_params.h>
29#include <sound/initval.h>
30#include <sound/soc.h>
31#include <asm/hardware.h>
32
33#include <linux/io.h>
34#include <asm/dma.h>
35
36#include <asm/plat-s3c24xx/regs-s3c2412-iis.h>
37
38#include <asm/arch/regs-gpio.h>
39#include <asm/arch/audio.h>
40#include <asm/arch/dma.h>
41
42#include "s3c24xx-pcm.h"
43#include "s3c2412-i2s.h"
44
45#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
54static struct s3c2410_dma_client s3c2412_dma_client_out = {
55 .name = "I2S PCM Stereo out"
56};
57
58static struct s3c2410_dma_client s3c2412_dma_client_in = {
59 .name = "I2S PCM Stereo in"
60};
61
62static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_out = {
63 .client = &s3c2412_dma_client_out,
64 .channel = DMACH_I2S_OUT,
65 .dma_addr = S3C2410_PA_IIS + S3C2412_IISTXD,
66 .dma_size = 4,
67};
68
69static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_in = {
70 .client = &s3c2412_dma_client_in,
71 .channel = DMACH_I2S_IN,
72 .dma_addr = S3C2410_PA_IIS + S3C2412_IISRXD,
73 .dma_size = 4,
74};
75
76struct s3c2412_i2s_info {
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_cpu_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{
348 struct snd_soc_pcm_runtime *rtd = substream->private_data;
349 u32 iismod;
350
351 DBG("Entered %s\n", __func__);
352
353 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
354 rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_out;
355 else
356 rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_in;
357
358 /* Working copies of register */
359 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
360 DBG("%s: r: IISMOD: %x\n", __func__, iismod);
361
362 switch (params_format(params)) {
363 case SNDRV_PCM_FORMAT_S8:
364 iismod |= S3C2412_IISMOD_8BIT;
365 break;
366 case SNDRV_PCM_FORMAT_S16_LE:
367 iismod &= ~S3C2412_IISMOD_8BIT;
368 break;
369 }
370
371 writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD);
372 DBG("%s: w: IISMOD: %x\n", __func__, iismod);
373 return 0;
374}
375
376static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
377{
378 int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
379 unsigned long irqs;
380 int ret = 0;
381
382 DBG("Entered %s\n", __func__);
383
384 switch (cmd) {
385 case SNDRV_PCM_TRIGGER_START:
386 /* On start, ensure that the FIFOs are cleared and reset. */
387
388 writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
389 s3c2412_i2s.regs + S3C2412_IISFIC);
390
391 /* clear again, just in case */
392 writel(0x0, s3c2412_i2s.regs + S3C2412_IISFIC);
393
394 case SNDRV_PCM_TRIGGER_RESUME:
395 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
396 if (!s3c2412_snd_is_clkmaster()) {
397 ret = s3c2412_snd_lrsync();
398 if (ret)
399 goto exit_err;
400 }
401
402 local_irq_save(irqs);
403
404 if (capture)
405 s3c2412_snd_rxctrl(1);
406 else
407 s3c2412_snd_txctrl(1);
408
409 local_irq_restore(irqs);
410 break;
411
412 case SNDRV_PCM_TRIGGER_STOP:
413 case SNDRV_PCM_TRIGGER_SUSPEND:
414 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
415 local_irq_save(irqs);
416
417 if (capture)
418 s3c2412_snd_rxctrl(0);
419 else
420 s3c2412_snd_txctrl(0);
421
422 local_irq_restore(irqs);
423 break;
424 default:
425 ret = -EINVAL;
426 break;
427 }
428
429exit_err:
430 return ret;
431}
432
433/* default table of all avaialable root fs divisors */
434static unsigned int s3c2412_iis_fs[] = { 256, 512, 384, 768, 0 };
435
436int s3c2412_iis_calc_rate(struct s3c2412_rate_calc *info,
437 unsigned int *fstab,
438 unsigned int rate, struct clk *clk)
439{
440 unsigned long clkrate = clk_get_rate(clk);
441 unsigned int div;
442 unsigned int fsclk;
443 unsigned int actual;
444 unsigned int fs;
445 unsigned int fsdiv;
446 signed int deviation = 0;
447 unsigned int best_fs = 0;
448 unsigned int best_div = 0;
449 unsigned int best_rate = 0;
450 unsigned int best_deviation = INT_MAX;
451
452
453 if (fstab == NULL)
454 fstab = s3c2412_iis_fs;
455
456 for (fs = 0;; fs++) {
457 fsdiv = s3c2412_iis_fs[fs];
458
459 if (fsdiv == 0)
460 break;
461
462 fsclk = clkrate / fsdiv;
463 div = fsclk / rate;
464
465 if ((fsclk % rate) > (rate / 2))
466 div++;
467
468 if (div <= 1)
469 continue;
470
471 actual = clkrate / (fsdiv * div);
472 deviation = actual - rate;
473
474 printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n",
475 fsdiv, div, actual, deviation);
476
477 deviation = abs(deviation);
478
479 if (deviation < best_deviation) {
480 best_fs = fsdiv;
481 best_div = div;
482 best_rate = actual;
483 best_deviation = deviation;
484 }
485
486 if (deviation == 0)
487 break;
488 }
489
490 printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n",
491 best_fs, best_div, best_rate);
492
493 info->fs_div = best_fs;
494 info->clk_div = best_div;
495
496 return 0;
497}
498EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate);
499
500/*
501 * Set S3C2412 Clock source
502 */
503static int s3c2412_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai,
504 int clk_id, unsigned int freq, int dir)
505{
506 u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
507
508 DBG("%s(%p, %d, %u, %d)\n", __func__, cpu_dai, clk_id,
509 freq, dir);
510
511 switch (clk_id) {
512 case S3C2412_CLKSRC_PCLK:
513 iismod &= ~S3C2412_IISMOD_MASTER_MASK;
514 iismod |= S3C2412_IISMOD_MASTER_INTERNAL;
515 break;
516 case S3C2412_CLKSRC_I2SCLK:
517 iismod &= ~S3C2412_IISMOD_MASTER_MASK;
518 iismod |= S3C2412_IISMOD_MASTER_EXTERNAL;
519 break;
520 default:
521 return -EINVAL;
522 }
523
524 writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD);
525 return 0;
526}
527
528/*
529 * Set S3C2412 Clock dividers
530 */
531static int s3c2412_i2s_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai,
532 int div_id, int div)
533{
534 struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
535 u32 reg;
536
537 DBG("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
538
539 switch (div_id) {
540 case S3C2412_DIV_BCLK:
541 reg = readl(i2s->regs + S3C2412_IISMOD);
542 reg &= ~S3C2412_IISMOD_BCLK_MASK;
543 writel(reg | div, i2s->regs + S3C2412_IISMOD);
544
545 DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
546 break;
547
548 case S3C2412_DIV_RCLK:
549 if (div > 3) {
550 /* convert value to bit field */
551
552 switch (div) {
553 case 256:
554 div = S3C2412_IISMOD_RCLK_256FS;
555 break;
556
557 case 384:
558 div = S3C2412_IISMOD_RCLK_384FS;
559 break;
560
561 case 512:
562 div = S3C2412_IISMOD_RCLK_512FS;
563 break;
564
565 case 768:
566 div = S3C2412_IISMOD_RCLK_768FS;
567 break;
568
569 default:
570 return -EINVAL;
571 }
572 }
573
574 reg = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
575 reg &= ~S3C2412_IISMOD_RCLK_MASK;
576 writel(reg | div, i2s->regs + S3C2412_IISMOD);
577 DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
578 break;
579
580 case S3C2412_DIV_PRESCALER:
581 if (div >= 0) {
582 writel((div << 8) | S3C2412_IISPSR_PSREN,
583 i2s->regs + S3C2412_IISPSR);
584 } else {
585 writel(0x0, i2s->regs + S3C2412_IISPSR);
586 }
587 DBG("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
588 break;
589
590 default:
591 return -EINVAL;
592 }
593
594 return 0;
595}
596
597struct clk *s3c2412_get_iisclk(void)
598{
599 return s3c2412_i2s.iis_clk;
600}
601EXPORT_SYMBOL_GPL(s3c2412_get_iisclk);
602
603
604static int s3c2412_i2s_probe(struct platform_device *pdev)
605{
606 DBG("Entered %s\n", __func__);
607
608 s3c2412_i2s.dev = &pdev->dev;
609
610 s3c2412_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100);
611 if (s3c2412_i2s.regs == NULL)
612 return -ENXIO;
613
614 s3c2412_i2s.iis_pclk = clk_get(&pdev->dev, "iis");
615 if (s3c2412_i2s.iis_pclk == NULL) {
616 DBG("failed to get iis_clock\n");
617 iounmap(s3c2412_i2s.regs);
618 return -ENODEV;
619 }
620
621 s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk");
622 if (s3c2412_i2s.iis_cclk == NULL) {
623 DBG("failed to get i2sclk clock\n");
624 iounmap(s3c2412_i2s.regs);
625 return -ENODEV;
626 }
627
628 clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll"));
629
630 clk_enable(s3c2412_i2s.iis_pclk);
631 clk_enable(s3c2412_i2s.iis_cclk);
632
633 s3c2412_i2s.iis_clk = s3c2412_i2s.iis_pclk;
634
635 /* Configure the I2S pins in correct mode */
636 s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);
637 s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK);
638 s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);
639 s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
640 s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
641
642 s3c2412_snd_txctrl(0);
643 s3c2412_snd_rxctrl(0);
644
645 return 0;
646}
647
648#ifdef CONFIG_PM
649static int s3c2412_i2s_suspend(struct platform_device *dev,
650 struct snd_soc_cpu_dai *dai)
651{
652 struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
653 u32 iismod;
654
655 if (dai->active) {
656 i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
657 i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
658 i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
659
660 /* some basic suspend checks */
661
662 iismod = readl(i2s->regs + S3C2412_IISMOD);
663
664 if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
665 dev_warn(&dev->dev, "%s: RXDMA active?\n", __func__);
666
667 if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
668 dev_warn(&dev->dev, "%s: TXDMA active?\n", __func__);
669
670 if (iismod & S3C2412_IISCON_IIS_ACTIVE)
671 dev_warn(&dev->dev, "%s: IIS active\n", __func__);
672 }
673
674 return 0;
675}
676
677static int s3c2412_i2s_resume(struct platform_device *pdev,
678 struct snd_soc_cpu_dai *dai)
679{
680 struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
681
682 dev_info(&pdev->dev, "dai_active %d, IISMOD %08x, IISCON %08x\n",
683 dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
684
685 if (dai->active) {
686 writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
687 writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
688 writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
689
690 writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
691 i2s->regs + S3C2412_IISFIC);
692
693 ndelay(250);
694 writel(0x0, i2s->regs + S3C2412_IISFIC);
695
696 }
697
698 return 0;
699}
700#else
701#define s3c2412_i2s_suspend NULL
702#define s3c2412_i2s_resume NULL
703#endif /* CONFIG_PM */
704
705#define S3C2412_I2S_RATES \
706 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
707 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
708 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
709
710struct snd_soc_cpu_dai s3c2412_i2s_dai = {
711 .name = "s3c2412-i2s",
712 .id = 0,
713 .type = SND_SOC_DAI_I2S,
714 .probe = s3c2412_i2s_probe,
715 .suspend = s3c2412_i2s_suspend,
716 .resume = s3c2412_i2s_resume,
717 .playback = {
718 .channels_min = 2,
719 .channels_max = 2,
720 .rates = S3C2412_I2S_RATES,
721 .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
722 },
723 .capture = {
724 .channels_min = 2,
725 .channels_max = 2,
726 .rates = S3C2412_I2S_RATES,
727 .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
728 },
729 .ops = {
730 .trigger = s3c2412_i2s_trigger,
731 .hw_params = s3c2412_i2s_hw_params,
732 },
733 .dai_ops = {
734 .set_fmt = s3c2412_i2s_set_fmt,
735 .set_clkdiv = s3c2412_i2s_set_clkdiv,
736 .set_sysclk = s3c2412_i2s_set_sysclk,
737 },
738};
739EXPORT_SYMBOL_GPL(s3c2412_i2s_dai);
740
741/* Module information */
742MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
743MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
744MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/s3c24xx/s3c2412-i2s.h
new file mode 100644
index 000000000000..27f48e1ffa86
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c2412-i2s.h
@@ -0,0 +1,38 @@
1/* sound/soc/s3c24xx/s3c2412-i2s.c
2 *
3 * ALSA Soc Audio Layer - S3C2412 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#ifndef __SND_SOC_S3C24XX_S3C2412_I2S_H
16#define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__
17
18#define S3C2412_DIV_BCLK (1)
19#define S3C2412_DIV_RCLK (2)
20#define S3C2412_DIV_PRESCALER (3)
21
22#define S3C2412_CLKSRC_PCLK (0)
23#define S3C2412_CLKSRC_I2SCLK (1)
24
25extern struct clk *s3c2412_get_iisclk(void);
26
27extern struct snd_soc_cpu_dai s3c2412_i2s_dai;
28
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 */
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c
index 758a2637e7ac..1c1ddbf7f3c0 100644
--- a/sound/soc/s3c24xx/s3c2443-ac97.c
+++ b/sound/soc/s3c24xx/s3c2443-ac97.c
@@ -23,7 +23,6 @@
23#include <linux/delay.h> 23#include <linux/delay.h>
24#include <linux/clk.h> 24#include <linux/clk.h>
25 25
26#include <sound/driver.h>
27#include <sound/core.h> 26#include <sound/core.h>
28#include <sound/pcm.h> 27#include <sound/pcm.h>
29#include <sound/ac97_codec.h> 28#include <sound/ac97_codec.h>
@@ -253,7 +252,7 @@ static int s3c2443_ac97_probe(struct platform_device *pdev)
253 ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE; 252 ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
254 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); 253 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
255 254
256 ret = request_irq(IRQ_S3C2443_AC97, s3c2443_ac97_irq, 255 ret = request_irq(IRQ_S3C244x_AC97, s3c2443_ac97_irq,
257 IRQF_DISABLED, "AC97", NULL); 256 IRQF_DISABLED, "AC97", NULL);
258 if (ret < 0) { 257 if (ret < 0) {
259 printk(KERN_ERR "s3c24xx-ac97: interrupt request failed.\n"); 258 printk(KERN_ERR "s3c24xx-ac97: interrupt request failed.\n");
@@ -266,7 +265,7 @@ static int s3c2443_ac97_probe(struct platform_device *pdev)
266 265
267static void s3c2443_ac97_remove(struct platform_device *pdev) 266static void s3c2443_ac97_remove(struct platform_device *pdev)
268{ 267{
269 free_irq(IRQ_S3C2443_AC97, NULL); 268 free_irq(IRQ_S3C244x_AC97, NULL);
270 clk_disable(s3c24xx_ac97.ac97_clk); 269 clk_disable(s3c24xx_ac97.ac97_clk);
271 clk_put(s3c24xx_ac97.ac97_clk); 270 clk_put(s3c24xx_ac97.ac97_clk);
272 iounmap(s3c24xx_ac97.regs); 271 iounmap(s3c24xx_ac97.regs);
diff --git a/sound/soc/s3c24xx/s3c24xx-ac97.h b/sound/soc/s3c24xx/s3c24xx-ac97.h
index 2b835e8260fa..bf03e8ed16c3 100644
--- a/sound/soc/s3c24xx/s3c24xx-ac97.h
+++ b/sound/soc/s3c24xx/s3c24xx-ac97.h
@@ -20,6 +20,12 @@
20#define AC_CMD_ADDR(x) (x << 16) 20#define AC_CMD_ADDR(x) (x << 16)
21#define AC_CMD_DATA(x) (x & 0xffff) 21#define AC_CMD_DATA(x) (x & 0xffff)
22 22
23#ifdef CONFIG_CPU_S3C2440
24#define IRQ_S3C244x_AC97 IRQ_S3C2440_AC97
25#else
26#define IRQ_S3C244x_AC97 IRQ_S3C2443_AC97
27#endif
28
23extern struct snd_soc_cpu_dai s3c2443_ac97_dai[]; 29extern struct snd_soc_cpu_dai s3c2443_ac97_dai[];
24 30
25#endif /*S3C24XXAC97_H_*/ 31#endif /*S3C24XXAC97_H_*/
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
index cd89c4105fcd..0a3c630951be 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.c
@@ -24,7 +24,7 @@
24#include <linux/device.h> 24#include <linux/device.h>
25#include <linux/delay.h> 25#include <linux/delay.h>
26#include <linux/clk.h> 26#include <linux/clk.h>
27#include <sound/driver.h> 27#include <linux/jiffies.h>
28#include <sound/core.h> 28#include <sound/core.h>
29#include <sound/pcm.h> 29#include <sound/pcm.h>
30#include <sound/pcm_params.h> 30#include <sound/pcm_params.h>
@@ -33,13 +33,14 @@
33 33
34#include <asm/hardware.h> 34#include <asm/hardware.h>
35#include <asm/io.h> 35#include <asm/io.h>
36#include <asm/arch/regs-iis.h>
37#include <asm/arch/regs-gpio.h> 36#include <asm/arch/regs-gpio.h>
38#include <asm/arch/regs-clock.h> 37#include <asm/arch/regs-clock.h>
39#include <asm/arch/audio.h> 38#include <asm/arch/audio.h>
40#include <asm/dma.h> 39#include <asm/dma.h>
41#include <asm/arch/dma.h> 40#include <asm/arch/dma.h>
42 41
42#include <asm/plat-s3c24xx/regs-iis.h>
43
43#include "s3c24xx-pcm.h" 44#include "s3c24xx-pcm.h"
44#include "s3c24xx-i2s.h" 45#include "s3c24xx-i2s.h"
45 46
@@ -75,6 +76,10 @@ static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_in = {
75struct s3c24xx_i2s_info { 76struct s3c24xx_i2s_info {
76 void __iomem *regs; 77 void __iomem *regs;
77 struct clk *iis_clk; 78 struct clk *iis_clk;
79 u32 iiscon;
80 u32 iismod;
81 u32 iisfcon;
82 u32 iispsr;
78}; 83};
79static struct s3c24xx_i2s_info s3c24xx_i2s; 84static struct s3c24xx_i2s_info s3c24xx_i2s;
80 85
@@ -184,7 +189,7 @@ static int s3c24xx_snd_lrsync(void)
184 if (iiscon & S3C2410_IISCON_LRINDEX) 189 if (iiscon & S3C2410_IISCON_LRINDEX)
185 break; 190 break;
186 191
187 if (timeout < jiffies) 192 if (time_after(jiffies, timeout))
188 return -ETIMEDOUT; 193 return -ETIMEDOUT;
189 } 194 }
190 195
@@ -405,6 +410,38 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev)
405 return 0; 410 return 0;
406} 411}
407 412
413#ifdef CONFIG_PM
414int s3c24xx_i2s_suspend(struct platform_device *pdev,
415 struct snd_soc_cpu_dai *cpu_dai)
416{
417 s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
418 s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
419 s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
420 s3c24xx_i2s.iispsr = readl(s3c24xx_i2s.regs + S3C2410_IISPSR);
421
422 clk_disable(s3c24xx_i2s.iis_clk);
423
424 return 0;
425}
426
427int s3c24xx_i2s_resume(struct platform_device *pdev,
428 struct snd_soc_cpu_dai *cpu_dai)
429{
430 clk_enable(s3c24xx_i2s.iis_clk);
431
432 writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
433 writel(s3c24xx_i2s.iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
434 writel(s3c24xx_i2s.iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
435 writel(s3c24xx_i2s.iispsr, s3c24xx_i2s.regs + S3C2410_IISPSR);
436
437 return 0;
438}
439#else
440#define s3c24xx_i2s_suspend NULL
441#define s3c24xx_i2s_resume NULL
442#endif
443
444
408#define S3C24XX_I2S_RATES \ 445#define S3C24XX_I2S_RATES \
409 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ 446 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
410 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 447 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
@@ -415,6 +452,8 @@ struct snd_soc_cpu_dai s3c24xx_i2s_dai = {
415 .id = 0, 452 .id = 0,
416 .type = SND_SOC_DAI_I2S, 453 .type = SND_SOC_DAI_I2S,
417 .probe = s3c24xx_i2s_probe, 454 .probe = s3c24xx_i2s_probe,
455 .suspend = s3c24xx_i2s_suspend,
456 .resume = s3c24xx_i2s_resume,
418 .playback = { 457 .playback = {
419 .channels_min = 2, 458 .channels_min = 2,
420 .channels_max = 2, 459 .channels_max = 2,
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c
index 4107a87d4de3..29a6c82f873a 100644
--- a/sound/soc/s3c24xx/s3c24xx-pcm.c
+++ b/sound/soc/s3c24xx/s3c24xx-pcm.c
@@ -24,7 +24,6 @@
24#include <linux/slab.h> 24#include <linux/slab.h>
25#include <linux/dma-mapping.h> 25#include <linux/dma-mapping.h>
26 26
27#include <sound/driver.h>
28#include <sound/core.h> 27#include <sound/core.h>
29#include <sound/pcm.h> 28#include <sound/pcm.h>
30#include <sound/pcm_params.h> 29#include <sound/pcm_params.h>
@@ -49,7 +48,9 @@ static const struct snd_pcm_hardware s3c24xx_pcm_hardware = {
49 .info = SNDRV_PCM_INFO_INTERLEAVED | 48 .info = SNDRV_PCM_INFO_INTERLEAVED |
50 SNDRV_PCM_INFO_BLOCK_TRANSFER | 49 SNDRV_PCM_INFO_BLOCK_TRANSFER |
51 SNDRV_PCM_INFO_MMAP | 50 SNDRV_PCM_INFO_MMAP |
52 SNDRV_PCM_INFO_MMAP_VALID, 51 SNDRV_PCM_INFO_MMAP_VALID |
52 SNDRV_PCM_INFO_PAUSE |
53 SNDRV_PCM_INFO_RESUME,
53 .formats = SNDRV_PCM_FMTBIT_S16_LE | 54 .formats = SNDRV_PCM_FMTBIT_S16_LE |
54 SNDRV_PCM_FMTBIT_U16_LE | 55 SNDRV_PCM_FMTBIT_U16_LE |
55 SNDRV_PCM_FMTBIT_U8 | 56 SNDRV_PCM_FMTBIT_U8 |
@@ -176,28 +177,6 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream,
176 } 177 }
177 } 178 }
178 179
179 /* channel needs configuring for mem=>device, increment memory addr,
180 * sync to pclk, half-word transfers to the IIS-FIFO. */
181 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
182 s3c2410_dma_devconfig(prtd->params->channel,
183 S3C2410_DMASRC_MEM, S3C2410_DISRCC_INC |
184 S3C2410_DISRCC_APB, prtd->params->dma_addr);
185
186 s3c2410_dma_config(prtd->params->channel,
187 prtd->params->dma_size,
188 S3C2410_DCON_SYNC_PCLK |
189 S3C2410_DCON_HANDSHAKE);
190 } else {
191 s3c2410_dma_config(prtd->params->channel,
192 prtd->params->dma_size,
193 S3C2410_DCON_HANDSHAKE |
194 S3C2410_DCON_SYNC_PCLK);
195
196 s3c2410_dma_devconfig(prtd->params->channel,
197 S3C2410_DMASRC_HW, 0x3,
198 prtd->params->dma_addr);
199 }
200
201 s3c2410_dma_set_buffdone_fn(prtd->params->channel, 180 s3c2410_dma_set_buffdone_fn(prtd->params->channel,
202 s3c24xx_audio_buffdone); 181 s3c24xx_audio_buffdone);
203 182
@@ -246,6 +225,28 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream)
246 if (!prtd->params) 225 if (!prtd->params)
247 return 0; 226 return 0;
248 227
228 /* channel needs configuring for mem=>device, increment memory addr,
229 * sync to pclk, half-word transfers to the IIS-FIFO. */
230 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
231 s3c2410_dma_devconfig(prtd->params->channel,
232 S3C2410_DMASRC_MEM, S3C2410_DISRCC_INC |
233 S3C2410_DISRCC_APB, prtd->params->dma_addr);
234
235 s3c2410_dma_config(prtd->params->channel,
236 prtd->params->dma_size,
237 S3C2410_DCON_SYNC_PCLK |
238 S3C2410_DCON_HANDSHAKE);
239 } else {
240 s3c2410_dma_config(prtd->params->channel,
241 prtd->params->dma_size,
242 S3C2410_DCON_HANDSHAKE |
243 S3C2410_DCON_SYNC_PCLK);
244
245 s3c2410_dma_devconfig(prtd->params->channel,
246 S3C2410_DMASRC_HW, 0x3,
247 prtd->params->dma_addr);
248 }
249
249 /* flush the DMA channel */ 250 /* flush the DMA channel */
250 s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH); 251 s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH);
251 prtd->dma_loaded = 0; 252 prtd->dma_loaded = 0;
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
index d46cd811ceb3..b4a56302b9ab 100644
--- a/sound/soc/s3c24xx/smdk2443_wm9710.c
+++ b/sound/soc/s3c24xx/smdk2443_wm9710.c
@@ -17,7 +17,6 @@
17 17
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/device.h> 19#include <linux/device.h>
20#include <sound/driver.h>
21#include <sound/core.h> 20#include <sound/core.h>
22#include <sound/pcm.h> 21#include <sound/pcm.h>
23#include <sound/soc.h> 22#include <sound/soc.h>
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
index cdee374b843e..7a3ce80d6727 100644
--- a/sound/soc/sh/dma-sh7760.c
+++ b/sound/soc/sh/dma-sh7760.c
@@ -16,7 +16,6 @@
16#include <linux/init.h> 16#include <linux/init.h>
17#include <linux/platform_device.h> 17#include <linux/platform_device.h>
18#include <linux/dma-mapping.h> 18#include <linux/dma-mapping.h>
19#include <sound/driver.h>
20#include <sound/core.h> 19#include <sound/core.h>
21#include <sound/pcm.h> 20#include <sound/pcm.h>
22#include <sound/pcm_params.h> 21#include <sound/pcm_params.h>
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
index 8e3f03908cdb..b7b676b3d671 100644
--- a/sound/soc/sh/hac.c
+++ b/sound/soc/sh/hac.c
@@ -21,7 +21,6 @@
21#include <linux/interrupt.h> 21#include <linux/interrupt.h>
22#include <linux/wait.h> 22#include <linux/wait.h>
23#include <linux/delay.h> 23#include <linux/delay.h>
24#include <sound/driver.h>
25#include <sound/core.h> 24#include <sound/core.h>
26#include <sound/pcm.h> 25#include <sound/pcm.h>
27#include <sound/ac97_codec.h> 26#include <sound/ac97_codec.h>
@@ -105,7 +104,7 @@ static int hac_get_codec_data(struct hac_priv *hac, unsigned short r,
105 unsigned int to1, to2, i; 104 unsigned int to1, to2, i;
106 unsigned short adr; 105 unsigned short adr;
107 106
108 for (i = 0; i < AC97_READ_RETRY; ++i) { 107 for (i = AC97_READ_RETRY; i; i--) {
109 *v = 0; 108 *v = 0;
110 /* wait for HAC to receive something from the codec */ 109 /* wait for HAC to receive something from the codec */
111 for (to1 = TMO_E4; 110 for (to1 = TMO_E4;
@@ -132,7 +131,7 @@ static int hac_get_codec_data(struct hac_priv *hac, unsigned short r,
132 udelay(21); 131 udelay(21);
133 } 132 }
134 HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY); 133 HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
135 return (i < AC97_READ_RETRY); 134 return i;
136} 135}
137 136
138static unsigned short hac_read_codec_aux(struct hac_priv *hac, 137static unsigned short hac_read_codec_aux(struct hac_priv *hac,
@@ -141,7 +140,7 @@ static unsigned short hac_read_codec_aux(struct hac_priv *hac,
141 unsigned short val; 140 unsigned short val;
142 unsigned int i, to; 141 unsigned int i, to;
143 142
144 for (i = 0; i < AC97_READ_RETRY; i++) { 143 for (i = AC97_READ_RETRY; i; i--) {
145 /* send_read_request */ 144 /* send_read_request */
146 local_irq_disable(); 145 local_irq_disable();
147 HACREG(HACTSR) &= ~(TSR_CMDAMT); 146 HACREG(HACTSR) &= ~(TSR_CMDAMT);
@@ -159,10 +158,7 @@ static unsigned short hac_read_codec_aux(struct hac_priv *hac,
159 break; 158 break;
160 } 159 }
161 160
162 if (i == AC97_READ_RETRY) 161 return i ? val : ~0;
163 return ~0;
164
165 return val;
166} 162}
167 163
168static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg, 164static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
@@ -172,7 +168,7 @@ static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
172 struct hac_priv *hac = &hac_cpu_data[unit_id]; 168 struct hac_priv *hac = &hac_cpu_data[unit_id];
173 unsigned int i, to; 169 unsigned int i, to;
174 /* write_codec_aux */ 170 /* write_codec_aux */
175 for (i = 0; i < AC97_WRITE_RETRY; i++) { 171 for (i = AC97_WRITE_RETRY; i; i--) {
176 /* send_write_request */ 172 /* send_write_request */
177 local_irq_disable(); 173 local_irq_disable();
178 HACREG(HACTSR) &= ~(TSR_CMDDMT | TSR_CMDAMT); 174 HACREG(HACTSR) &= ~(TSR_CMDDMT | TSR_CMDAMT);
diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c
index 5563f14511fa..2f91de84c5c7 100644
--- a/sound/soc/sh/sh7760-ac97.c
+++ b/sound/soc/sh/sh7760-ac97.c
@@ -9,7 +9,6 @@
9#include <linux/module.h> 9#include <linux/module.h>
10#include <linux/moduleparam.h> 10#include <linux/moduleparam.h>
11#include <linux/platform_device.h> 11#include <linux/platform_device.h>
12#include <sound/driver.h>
13#include <sound/core.h> 12#include <sound/core.h>
14#include <sound/pcm.h> 13#include <sound/pcm.h>
15#include <sound/soc.h> 14#include <sound/soc.h>
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
index b72bc316cb8e..3388bc3d62d1 100644
--- a/sound/soc/sh/ssi.c
+++ b/sound/soc/sh/ssi.c
@@ -30,7 +30,6 @@
30#include <linux/init.h> 30#include <linux/init.h>
31#include <linux/module.h> 31#include <linux/module.h>
32#include <linux/platform_device.h> 32#include <linux/platform_device.h>
33#include <sound/driver.h>
34#include <sound/core.h> 33#include <sound/core.h>
35#include <sound/pcm.h> 34#include <sound/pcm.h>
36#include <sound/initval.h> 35#include <sound/initval.h>
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index e6a67b58f296..9eb5479787c1 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -32,7 +32,6 @@
32#include <linux/pm.h> 32#include <linux/pm.h>
33#include <linux/bitops.h> 33#include <linux/bitops.h>
34#include <linux/platform_device.h> 34#include <linux/platform_device.h>
35#include <sound/driver.h>
36#include <sound/core.h> 35#include <sound/core.h>
37#include <sound/pcm.h> 36#include <sound/pcm.h>
38#include <sound/pcm_params.h> 37#include <sound/pcm_params.h>
@@ -288,16 +287,25 @@ static void close_delayed_work(struct work_struct *work)
288 /* are we waiting on this codec DAI stream */ 287 /* are we waiting on this codec DAI stream */
289 if (codec_dai->pop_wait == 1) { 288 if (codec_dai->pop_wait == 1) {
290 289
290 /* power down the codec to D1 if no longer active */
291 if (codec->active == 0) {
292 dbg("pop wq D1 %s %s\n", codec->name,
293 codec_dai->playback.stream_name);
294 snd_soc_dapm_device_event(socdev,
295 SNDRV_CTL_POWER_D1);
296 }
297
291 codec_dai->pop_wait = 0; 298 codec_dai->pop_wait = 0;
292 snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name, 299 snd_soc_dapm_stream_event(codec,
300 codec_dai->playback.stream_name,
293 SND_SOC_DAPM_STREAM_STOP); 301 SND_SOC_DAPM_STREAM_STOP);
294 302
295 /* power down the codec power domain if no longer active */ 303 /* power down the codec power domain if no longer active */
296 if (codec->active == 0) { 304 if (codec->active == 0) {
297 dbg("pop wq D3 %s %s\n", codec->name, 305 dbg("pop wq D3 %s %s\n", codec->name,
298 codec_dai->playback.stream_name); 306 codec_dai->playback.stream_name);
299 if (codec->dapm_event) 307 snd_soc_dapm_device_event(socdev,
300 codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot); 308 SNDRV_CTL_POWER_D3hot);
301 } 309 }
302 } 310 }
303 } 311 }
@@ -353,12 +361,12 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
353 } else { 361 } else {
354 /* capture streams can be powered down now */ 362 /* capture streams can be powered down now */
355 snd_soc_dapm_stream_event(codec, 363 snd_soc_dapm_stream_event(codec,
356 codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_STOP); 364 codec_dai->capture.stream_name,
365 SND_SOC_DAPM_STREAM_STOP);
357 366
358 if (codec->active == 0 && codec_dai->pop_wait == 0){ 367 if (codec->active == 0 && codec_dai->pop_wait == 0)
359 if (codec->dapm_event) 368 snd_soc_dapm_device_event(socdev,
360 codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot); 369 SNDRV_CTL_POWER_D3hot);
361 }
362 } 370 }
363 371
364 mutex_unlock(&pcm_mutex); 372 mutex_unlock(&pcm_mutex);
@@ -433,8 +441,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
433 /* no delayed work - do we need to power up codec */ 441 /* no delayed work - do we need to power up codec */
434 if (codec->dapm_state != SNDRV_CTL_POWER_D0) { 442 if (codec->dapm_state != SNDRV_CTL_POWER_D0) {
435 443
436 if (codec->dapm_event) 444 snd_soc_dapm_device_event(socdev, SNDRV_CTL_POWER_D1);
437 codec->dapm_event(codec, SNDRV_CTL_POWER_D1);
438 445
439 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 446 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
440 snd_soc_dapm_stream_event(codec, 447 snd_soc_dapm_stream_event(codec,
@@ -445,8 +452,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
445 codec_dai->capture.stream_name, 452 codec_dai->capture.stream_name,
446 SND_SOC_DAPM_STREAM_START); 453 SND_SOC_DAPM_STREAM_START);
447 454
448 if (codec->dapm_event) 455 snd_soc_dapm_device_event(socdev, SNDRV_CTL_POWER_D0);
449 codec->dapm_event(codec, SNDRV_CTL_POWER_D0);
450 if (codec_dai->dai_ops.digital_mute) 456 if (codec_dai->dai_ops.digital_mute)
451 codec_dai->dai_ops.digital_mute(codec_dai, 0); 457 codec_dai->dai_ops.digital_mute(codec_dai, 0);
452 458
@@ -639,6 +645,10 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
639 dai->dai_ops.digital_mute(dai, 1); 645 dai->dai_ops.digital_mute(dai, 1);
640 } 646 }
641 647
648 /* suspend all pcms */
649 for (i = 0; i < machine->num_links; i++)
650 snd_pcm_suspend_all(machine->dai_link[i].pcm);
651
642 if (machine->suspend_pre) 652 if (machine->suspend_pre)
643 machine->suspend_pre(pdev, state); 653 machine->suspend_pre(pdev, state);
644 654
@@ -873,6 +883,7 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
873 return ret; 883 return ret;
874 } 884 }
875 885
886 dai_link->pcm = pcm;
876 pcm->private_data = rtd; 887 pcm->private_data = rtd;
877 soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap; 888 soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap;
878 soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer; 889 soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer;
@@ -1090,7 +1101,6 @@ int snd_soc_register_card(struct snd_soc_device *socdev)
1090 struct snd_soc_machine *machine = socdev->machine; 1101 struct snd_soc_machine *machine = socdev->machine;
1091 int ret = 0, i, ac97 = 0, err = 0; 1102 int ret = 0, i, ac97 = 0, err = 0;
1092 1103
1093 mutex_lock(&codec->mutex);
1094 for(i = 0; i < machine->num_links; i++) { 1104 for(i = 0; i < machine->num_links; i++) {
1095 if (socdev->machine->dai_link[i].init) { 1105 if (socdev->machine->dai_link[i].init) {
1096 err = socdev->machine->dai_link[i].init(codec); 1106 err = socdev->machine->dai_link[i].init(codec);
@@ -1116,12 +1126,14 @@ int snd_soc_register_card(struct snd_soc_device *socdev)
1116 goto out; 1126 goto out;
1117 } 1127 }
1118 1128
1129 mutex_lock(&codec->mutex);
1119#ifdef CONFIG_SND_SOC_AC97_BUS 1130#ifdef CONFIG_SND_SOC_AC97_BUS
1120 if (ac97) { 1131 if (ac97) {
1121 ret = soc_ac97_dev_register(codec); 1132 ret = soc_ac97_dev_register(codec);
1122 if (ret < 0) { 1133 if (ret < 0) {
1123 printk(KERN_ERR "asoc: AC97 device register failed\n"); 1134 printk(KERN_ERR "asoc: AC97 device register failed\n");
1124 snd_card_free(codec->card); 1135 snd_card_free(codec->card);
1136 mutex_unlock(&codec->mutex);
1125 goto out; 1137 goto out;
1126 } 1138 }
1127 } 1139 }
@@ -1134,8 +1146,10 @@ int snd_soc_register_card(struct snd_soc_device *socdev)
1134 err = device_create_file(socdev->dev, &dev_attr_codec_reg); 1146 err = device_create_file(socdev->dev, &dev_attr_codec_reg);
1135 if (err < 0) 1147 if (err < 0)
1136 printk(KERN_WARNING "asoc: failed to add codec sysfs entries\n"); 1148 printk(KERN_WARNING "asoc: failed to add codec sysfs entries\n");
1137out: 1149
1138 mutex_unlock(&codec->mutex); 1150 mutex_unlock(&codec->mutex);
1151
1152out:
1139 return ret; 1153 return ret;
1140} 1154}
1141EXPORT_SYMBOL_GPL(snd_soc_register_card); 1155EXPORT_SYMBOL_GPL(snd_soc_register_card);
@@ -1215,7 +1229,6 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
1215 memcpy(&template, _template, sizeof(template)); 1229 memcpy(&template, _template, sizeof(template));
1216 if (long_name) 1230 if (long_name)
1217 template.name = long_name; 1231 template.name = long_name;
1218 template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1219 template.index = 0; 1232 template.index = 0;
1220 1233
1221 return snd_ctl_new1(&template, data); 1234 return snd_ctl_new1(&template, data);
@@ -1350,13 +1363,16 @@ EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext);
1350int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, 1363int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
1351 struct snd_ctl_elem_info *uinfo) 1364 struct snd_ctl_elem_info *uinfo)
1352{ 1365{
1353 int mask = kcontrol->private_value; 1366 int max = kcontrol->private_value;
1367
1368 if (max == 1)
1369 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1370 else
1371 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1354 1372
1355 uinfo->type =
1356 mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
1357 uinfo->count = 1; 1373 uinfo->count = 1;
1358 uinfo->value.integer.min = 0; 1374 uinfo->value.integer.min = 0;
1359 uinfo->value.integer.max = mask; 1375 uinfo->value.integer.max = max;
1360 return 0; 1376 return 0;
1361} 1377}
1362EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); 1378EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext);
@@ -1373,15 +1389,18 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext);
1373int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, 1389int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
1374 struct snd_ctl_elem_info *uinfo) 1390 struct snd_ctl_elem_info *uinfo)
1375{ 1391{
1376 int mask = (kcontrol->private_value >> 16) & 0xff; 1392 int max = (kcontrol->private_value >> 16) & 0xff;
1377 int shift = (kcontrol->private_value >> 8) & 0x0f; 1393 int shift = (kcontrol->private_value >> 8) & 0x0f;
1378 int rshift = (kcontrol->private_value >> 12) & 0x0f; 1394 int rshift = (kcontrol->private_value >> 12) & 0x0f;
1379 1395
1380 uinfo->type = 1396 if (max == 1)
1381 mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 1397 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1398 else
1399 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1400
1382 uinfo->count = shift == rshift ? 1 : 2; 1401 uinfo->count = shift == rshift ? 1 : 2;
1383 uinfo->value.integer.min = 0; 1402 uinfo->value.integer.min = 0;
1384 uinfo->value.integer.max = mask; 1403 uinfo->value.integer.max = max;
1385 return 0; 1404 return 0;
1386} 1405}
1387EXPORT_SYMBOL_GPL(snd_soc_info_volsw); 1406EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
@@ -1402,7 +1421,8 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
1402 int reg = kcontrol->private_value & 0xff; 1421 int reg = kcontrol->private_value & 0xff;
1403 int shift = (kcontrol->private_value >> 8) & 0x0f; 1422 int shift = (kcontrol->private_value >> 8) & 0x0f;
1404 int rshift = (kcontrol->private_value >> 12) & 0x0f; 1423 int rshift = (kcontrol->private_value >> 12) & 0x0f;
1405 int mask = (kcontrol->private_value >> 16) & 0xff; 1424 int max = (kcontrol->private_value >> 16) & 0xff;
1425 int mask = (1 << fls(max)) - 1;
1406 int invert = (kcontrol->private_value >> 24) & 0x01; 1426 int invert = (kcontrol->private_value >> 24) & 0x01;
1407 1427
1408 ucontrol->value.integer.value[0] = 1428 ucontrol->value.integer.value[0] =
@@ -1412,10 +1432,10 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
1412 (snd_soc_read(codec, reg) >> rshift) & mask; 1432 (snd_soc_read(codec, reg) >> rshift) & mask;
1413 if (invert) { 1433 if (invert) {
1414 ucontrol->value.integer.value[0] = 1434 ucontrol->value.integer.value[0] =
1415 mask - ucontrol->value.integer.value[0]; 1435 max - ucontrol->value.integer.value[0];
1416 if (shift != rshift) 1436 if (shift != rshift)
1417 ucontrol->value.integer.value[1] = 1437 ucontrol->value.integer.value[1] =
1418 mask - ucontrol->value.integer.value[1]; 1438 max - ucontrol->value.integer.value[1];
1419 } 1439 }
1420 1440
1421 return 0; 1441 return 0;
@@ -1438,25 +1458,24 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
1438 int reg = kcontrol->private_value & 0xff; 1458 int reg = kcontrol->private_value & 0xff;
1439 int shift = (kcontrol->private_value >> 8) & 0x0f; 1459 int shift = (kcontrol->private_value >> 8) & 0x0f;
1440 int rshift = (kcontrol->private_value >> 12) & 0x0f; 1460 int rshift = (kcontrol->private_value >> 12) & 0x0f;
1441 int mask = (kcontrol->private_value >> 16) & 0xff; 1461 int max = (kcontrol->private_value >> 16) & 0xff;
1462 int mask = (1 << fls(max)) - 1;
1442 int invert = (kcontrol->private_value >> 24) & 0x01; 1463 int invert = (kcontrol->private_value >> 24) & 0x01;
1443 int err;
1444 unsigned short val, val2, val_mask; 1464 unsigned short val, val2, val_mask;
1445 1465
1446 val = (ucontrol->value.integer.value[0] & mask); 1466 val = (ucontrol->value.integer.value[0] & mask);
1447 if (invert) 1467 if (invert)
1448 val = mask - val; 1468 val = max - val;
1449 val_mask = mask << shift; 1469 val_mask = mask << shift;
1450 val = val << shift; 1470 val = val << shift;
1451 if (shift != rshift) { 1471 if (shift != rshift) {
1452 val2 = (ucontrol->value.integer.value[1] & mask); 1472 val2 = (ucontrol->value.integer.value[1] & mask);
1453 if (invert) 1473 if (invert)
1454 val2 = mask - val2; 1474 val2 = max - val2;
1455 val_mask |= mask << rshift; 1475 val_mask |= mask << rshift;
1456 val |= val2 << rshift; 1476 val |= val2 << rshift;
1457 } 1477 }
1458 err = snd_soc_update_bits(codec, reg, val_mask, val); 1478 return snd_soc_update_bits(codec, reg, val_mask, val);
1459 return err;
1460} 1479}
1461EXPORT_SYMBOL_GPL(snd_soc_put_volsw); 1480EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
1462 1481
@@ -1473,13 +1492,16 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
1473int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, 1492int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
1474 struct snd_ctl_elem_info *uinfo) 1493 struct snd_ctl_elem_info *uinfo)
1475{ 1494{
1476 int mask = (kcontrol->private_value >> 12) & 0xff; 1495 int max = (kcontrol->private_value >> 12) & 0xff;
1496
1497 if (max == 1)
1498 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1499 else
1500 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1477 1501
1478 uinfo->type =
1479 mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
1480 uinfo->count = 2; 1502 uinfo->count = 2;
1481 uinfo->value.integer.min = 0; 1503 uinfo->value.integer.min = 0;
1482 uinfo->value.integer.max = mask; 1504 uinfo->value.integer.max = max;
1483 return 0; 1505 return 0;
1484} 1506}
1485EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r); 1507EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r);
@@ -1500,7 +1522,8 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
1500 int reg = kcontrol->private_value & 0xff; 1522 int reg = kcontrol->private_value & 0xff;
1501 int reg2 = (kcontrol->private_value >> 24) & 0xff; 1523 int reg2 = (kcontrol->private_value >> 24) & 0xff;
1502 int shift = (kcontrol->private_value >> 8) & 0x0f; 1524 int shift = (kcontrol->private_value >> 8) & 0x0f;
1503 int mask = (kcontrol->private_value >> 12) & 0xff; 1525 int max = (kcontrol->private_value >> 12) & 0xff;
1526 int mask = (1<<fls(max))-1;
1504 int invert = (kcontrol->private_value >> 20) & 0x01; 1527 int invert = (kcontrol->private_value >> 20) & 0x01;
1505 1528
1506 ucontrol->value.integer.value[0] = 1529 ucontrol->value.integer.value[0] =
@@ -1509,9 +1532,9 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
1509 (snd_soc_read(codec, reg2) >> shift) & mask; 1532 (snd_soc_read(codec, reg2) >> shift) & mask;
1510 if (invert) { 1533 if (invert) {
1511 ucontrol->value.integer.value[0] = 1534 ucontrol->value.integer.value[0] =
1512 mask - ucontrol->value.integer.value[0]; 1535 max - ucontrol->value.integer.value[0];
1513 ucontrol->value.integer.value[1] = 1536 ucontrol->value.integer.value[1] =
1514 mask - ucontrol->value.integer.value[1]; 1537 max - ucontrol->value.integer.value[1];
1515 } 1538 }
1516 1539
1517 return 0; 1540 return 0;
@@ -1534,7 +1557,8 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
1534 int reg = kcontrol->private_value & 0xff; 1557 int reg = kcontrol->private_value & 0xff;
1535 int reg2 = (kcontrol->private_value >> 24) & 0xff; 1558 int reg2 = (kcontrol->private_value >> 24) & 0xff;
1536 int shift = (kcontrol->private_value >> 8) & 0x0f; 1559 int shift = (kcontrol->private_value >> 8) & 0x0f;
1537 int mask = (kcontrol->private_value >> 12) & 0xff; 1560 int max = (kcontrol->private_value >> 12) & 0xff;
1561 int mask = (1 << fls(max)) - 1;
1538 int invert = (kcontrol->private_value >> 20) & 0x01; 1562 int invert = (kcontrol->private_value >> 20) & 0x01;
1539 int err; 1563 int err;
1540 unsigned short val, val2, val_mask; 1564 unsigned short val, val2, val_mask;
@@ -1544,8 +1568,8 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
1544 val2 = (ucontrol->value.integer.value[1] & mask); 1568 val2 = (ucontrol->value.integer.value[1] & mask);
1545 1569
1546 if (invert) { 1570 if (invert) {
1547 val = mask - val; 1571 val = max - val;
1548 val2 = mask - val2; 1572 val2 = max - val2;
1549 } 1573 }
1550 1574
1551 val = val << shift; 1575 val = val << shift;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 29a546fecacf..620d7ea3c15f 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -43,7 +43,6 @@
43#include <linux/bitops.h> 43#include <linux/bitops.h>
44#include <linux/platform_device.h> 44#include <linux/platform_device.h>
45#include <linux/jiffies.h> 45#include <linux/jiffies.h>
46#include <sound/driver.h>
47#include <sound/core.h> 46#include <sound/core.h>
48#include <sound/pcm.h> 47#include <sound/pcm.h>
49#include <sound/pcm_params.h> 48#include <sound/pcm_params.h>
@@ -524,11 +523,13 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
524 continue; 523 continue;
525 524
526 if (event == SND_SOC_DAPM_STREAM_START) { 525 if (event == SND_SOC_DAPM_STREAM_START) {
527 ret = w->event(w, SND_SOC_DAPM_PRE_PMU); 526 ret = w->event(w,
527 NULL, SND_SOC_DAPM_PRE_PMU);
528 if (ret < 0) 528 if (ret < 0)
529 return ret; 529 return ret;
530 } else if (event == SND_SOC_DAPM_STREAM_STOP) { 530 } else if (event == SND_SOC_DAPM_STREAM_STOP) {
531 ret = w->event(w, SND_SOC_DAPM_PRE_PMD); 531 ret = w->event(w,
532 NULL, SND_SOC_DAPM_PRE_PMD);
532 if (ret < 0) 533 if (ret < 0)
533 return ret; 534 return ret;
534 } 535 }
@@ -539,11 +540,13 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
539 continue; 540 continue;
540 541
541 if (event == SND_SOC_DAPM_STREAM_START) { 542 if (event == SND_SOC_DAPM_STREAM_START) {
542 ret = w->event(w, SND_SOC_DAPM_POST_PMU); 543 ret = w->event(w,
544 NULL, SND_SOC_DAPM_POST_PMU);
543 if (ret < 0) 545 if (ret < 0)
544 return ret; 546 return ret;
545 } else if (event == SND_SOC_DAPM_STREAM_STOP) { 547 } else if (event == SND_SOC_DAPM_STREAM_STOP) {
546 ret = w->event(w, SND_SOC_DAPM_POST_PMD); 548 ret = w->event(w,
549 NULL, SND_SOC_DAPM_POST_PMD);
547 if (ret < 0) 550 if (ret < 0)
548 return ret; 551 return ret;
549 } 552 }
@@ -567,26 +570,30 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
567 if (power) { 570 if (power) {
568 /* power up event */ 571 /* power up event */
569 if (w->event_flags & SND_SOC_DAPM_PRE_PMU) { 572 if (w->event_flags & SND_SOC_DAPM_PRE_PMU) {
570 ret = w->event(w, SND_SOC_DAPM_PRE_PMU); 573 ret = w->event(w,
574 NULL, SND_SOC_DAPM_PRE_PMU);
571 if (ret < 0) 575 if (ret < 0)
572 return ret; 576 return ret;
573 } 577 }
574 dapm_update_bits(w); 578 dapm_update_bits(w);
575 if (w->event_flags & SND_SOC_DAPM_POST_PMU){ 579 if (w->event_flags & SND_SOC_DAPM_POST_PMU){
576 ret = w->event(w, SND_SOC_DAPM_POST_PMU); 580 ret = w->event(w,
581 NULL, SND_SOC_DAPM_POST_PMU);
577 if (ret < 0) 582 if (ret < 0)
578 return ret; 583 return ret;
579 } 584 }
580 } else { 585 } else {
581 /* power down event */ 586 /* power down event */
582 if (w->event_flags & SND_SOC_DAPM_PRE_PMD) { 587 if (w->event_flags & SND_SOC_DAPM_PRE_PMD) {
583 ret = w->event(w, SND_SOC_DAPM_PRE_PMD); 588 ret = w->event(w,
589 NULL, SND_SOC_DAPM_PRE_PMD);
584 if (ret < 0) 590 if (ret < 0)
585 return ret; 591 return ret;
586 } 592 }
587 dapm_update_bits(w); 593 dapm_update_bits(w);
588 if (w->event_flags & SND_SOC_DAPM_POST_PMD) { 594 if (w->event_flags & SND_SOC_DAPM_POST_PMD) {
589 ret = w->event(w, SND_SOC_DAPM_POST_PMD); 595 ret = w->event(w,
596 NULL, SND_SOC_DAPM_POST_PMD);
590 if (ret < 0) 597 if (ret < 0)
591 return ret; 598 return ret;
592 } 599 }
@@ -692,7 +699,7 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
692 return 0; 699 return 0;
693} 700}
694 701
695/* test and update the power status of a mixer widget */ 702/* test and update the power status of a mixer or switch widget */
696static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, 703static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
697 struct snd_kcontrol *kcontrol, int reg, 704 struct snd_kcontrol *kcontrol, int reg,
698 int val_mask, int val, int invert) 705 int val_mask, int val, int invert)
@@ -700,7 +707,8 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
700 struct snd_soc_dapm_path *path; 707 struct snd_soc_dapm_path *path;
701 int found = 0; 708 int found = 0;
702 709
703 if (widget->id != snd_soc_dapm_mixer) 710 if (widget->id != snd_soc_dapm_mixer &&
711 widget->id != snd_soc_dapm_switch)
704 return -ENODEV; 712 return -ENODEV;
705 713
706 if (!snd_soc_test_bits(widget->codec, reg, val_mask, val)) 714 if (!snd_soc_test_bits(widget->codec, reg, val_mask, val))
@@ -963,7 +971,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
963{ 971{
964 struct snd_soc_dapm_widget *w; 972 struct snd_soc_dapm_widget *w;
965 973
966 mutex_lock(&codec->mutex);
967 list_for_each_entry(w, &codec->dapm_widgets, list) 974 list_for_each_entry(w, &codec->dapm_widgets, list)
968 { 975 {
969 if (w->new) 976 if (w->new)
@@ -998,7 +1005,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
998 } 1005 }
999 1006
1000 dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); 1007 dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
1001 mutex_unlock(&codec->mutex);
1002 return 0; 1008 return 0;
1003} 1009}
1004EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); 1010EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
@@ -1019,8 +1025,9 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
1019 int reg = kcontrol->private_value & 0xff; 1025 int reg = kcontrol->private_value & 0xff;
1020 int shift = (kcontrol->private_value >> 8) & 0x0f; 1026 int shift = (kcontrol->private_value >> 8) & 0x0f;
1021 int rshift = (kcontrol->private_value >> 12) & 0x0f; 1027 int rshift = (kcontrol->private_value >> 12) & 0x0f;
1022 int mask = (kcontrol->private_value >> 16) & 0xff; 1028 int max = (kcontrol->private_value >> 16) & 0xff;
1023 int invert = (kcontrol->private_value >> 24) & 0x01; 1029 int invert = (kcontrol->private_value >> 24) & 0x01;
1030 int mask = (1 << fls(max)) - 1;
1024 1031
1025 /* return the saved value if we are powered down */ 1032 /* return the saved value if we are powered down */
1026 if (widget->id == snd_soc_dapm_pga && !widget->power) { 1033 if (widget->id == snd_soc_dapm_pga && !widget->power) {
@@ -1035,10 +1042,10 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
1035 (snd_soc_read(widget->codec, reg) >> rshift) & mask; 1042 (snd_soc_read(widget->codec, reg) >> rshift) & mask;
1036 if (invert) { 1043 if (invert) {
1037 ucontrol->value.integer.value[0] = 1044 ucontrol->value.integer.value[0] =
1038 mask - ucontrol->value.integer.value[0]; 1045 max - ucontrol->value.integer.value[0];
1039 if (shift != rshift) 1046 if (shift != rshift)
1040 ucontrol->value.integer.value[1] = 1047 ucontrol->value.integer.value[1] =
1041 mask - ucontrol->value.integer.value[1]; 1048 max - ucontrol->value.integer.value[1];
1042 } 1049 }
1043 1050
1044 return 0; 1051 return 0;
@@ -1061,7 +1068,8 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
1061 int reg = kcontrol->private_value & 0xff; 1068 int reg = kcontrol->private_value & 0xff;
1062 int shift = (kcontrol->private_value >> 8) & 0x0f; 1069 int shift = (kcontrol->private_value >> 8) & 0x0f;
1063 int rshift = (kcontrol->private_value >> 12) & 0x0f; 1070 int rshift = (kcontrol->private_value >> 12) & 0x0f;
1064 int mask = (kcontrol->private_value >> 16) & 0xff; 1071 int max = (kcontrol->private_value >> 16) & 0xff;
1072 int mask = (1 << fls(max)) - 1;
1065 int invert = (kcontrol->private_value >> 24) & 0x01; 1073 int invert = (kcontrol->private_value >> 24) & 0x01;
1066 unsigned short val, val2, val_mask; 1074 unsigned short val, val2, val_mask;
1067 int ret; 1075 int ret;
@@ -1069,13 +1077,13 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
1069 val = (ucontrol->value.integer.value[0] & mask); 1077 val = (ucontrol->value.integer.value[0] & mask);
1070 1078
1071 if (invert) 1079 if (invert)
1072 val = mask - val; 1080 val = max - val;
1073 val_mask = mask << shift; 1081 val_mask = mask << shift;
1074 val = val << shift; 1082 val = val << shift;
1075 if (shift != rshift) { 1083 if (shift != rshift) {
1076 val2 = (ucontrol->value.integer.value[1] & mask); 1084 val2 = (ucontrol->value.integer.value[1] & mask);
1077 if (invert) 1085 if (invert)
1078 val2 = mask - val2; 1086 val2 = max - val2;
1079 val_mask |= mask << rshift; 1087 val_mask |= mask << rshift;
1080 val |= val2 << rshift; 1088 val |= val2 << rshift;
1081 } 1089 }
@@ -1093,13 +1101,17 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
1093 dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert); 1101 dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert);
1094 if (widget->event) { 1102 if (widget->event) {
1095 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { 1103 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
1096 ret = widget->event(widget, SND_SOC_DAPM_PRE_REG); 1104 ret = widget->event(widget, kcontrol,
1097 if (ret < 0) 1105 SND_SOC_DAPM_PRE_REG);
1106 if (ret < 0) {
1107 ret = 1;
1098 goto out; 1108 goto out;
1109 }
1099 } 1110 }
1100 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); 1111 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
1101 if (widget->event_flags & SND_SOC_DAPM_POST_REG) 1112 if (widget->event_flags & SND_SOC_DAPM_POST_REG)
1102 ret = widget->event(widget, SND_SOC_DAPM_POST_REG); 1113 ret = widget->event(widget, kcontrol,
1114 SND_SOC_DAPM_POST_REG);
1103 } else 1115 } else
1104 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); 1116 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
1105 1117
@@ -1174,13 +1186,15 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
1174 dapm_mux_update_power(widget, kcontrol, mask, mux, e); 1186 dapm_mux_update_power(widget, kcontrol, mask, mux, e);
1175 if (widget->event) { 1187 if (widget->event) {
1176 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { 1188 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
1177 ret = widget->event(widget, SND_SOC_DAPM_PRE_REG); 1189 ret = widget->event(widget,
1190 kcontrol, SND_SOC_DAPM_PRE_REG);
1178 if (ret < 0) 1191 if (ret < 0)
1179 goto out; 1192 goto out;
1180 } 1193 }
1181 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); 1194 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
1182 if (widget->event_flags & SND_SOC_DAPM_POST_REG) 1195 if (widget->event_flags & SND_SOC_DAPM_POST_REG)
1183 ret = widget->event(widget, SND_SOC_DAPM_POST_REG); 1196 ret = widget->event(widget,
1197 kcontrol, SND_SOC_DAPM_POST_REG);
1184 } else 1198 } else
1185 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); 1199 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
1186 1200
@@ -1280,6 +1294,29 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
1280EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); 1294EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
1281 1295
1282/** 1296/**
1297 * snd_soc_dapm_device_event - send a device event to the dapm core
1298 * @socdev: audio device
1299 * @event: device event
1300 *
1301 * Sends a device event to the dapm core. The core then makes any
1302 * necessary machine or codec power changes..
1303 *
1304 * Returns 0 for success else error.
1305 */
1306int snd_soc_dapm_device_event(struct snd_soc_device *socdev, int event)
1307{
1308 struct snd_soc_codec *codec = socdev->codec;
1309 struct snd_soc_machine *machine = socdev->machine;
1310
1311 if (machine->dapm_event)
1312 machine->dapm_event(machine, event);
1313 if (codec->dapm_event)
1314 codec->dapm_event(codec, event);
1315 return 0;
1316}
1317EXPORT_SYMBOL_GPL(snd_soc_dapm_device_event);
1318
1319/**
1283 * snd_soc_dapm_set_endpoint - set audio endpoint status 1320 * snd_soc_dapm_set_endpoint - set audio endpoint status
1284 * @codec: audio codec 1321 * @codec: audio codec
1285 * @endpoint: audio signal endpoint (or start point) 1322 * @endpoint: audio signal endpoint (or start point)