diff options
author | Liam Girdwood <lg@opensource.wolfsonmicro.com> | 2006-10-19 14:35:56 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2007-02-09 03:01:07 -0500 |
commit | a71a468a50f1385855e28864e26251b02df829bb (patch) | |
tree | 243daee96ea5c55c88a186aa03b7917f7ad533f6 /sound/soc | |
parent | 543a0fbe18d0b44f3d037fe6b59458fa0c0d5e4b (diff) |
[ALSA] ASoC: Add support for BCLK based on (Rate * Chn * Word Size)
This patch adds support for the DAI BCLK to be generated by multiplying
Rate * Channels * Word Size (RCW).
This now gives 3 options for BCLK clocking and synchronisation :-
1. BCLK = Rate * x
2. BCLK = MCLK / x
3. BCLK = Rate * Chn * Word Size. (New)
Changes:-
o Add support for RCW generation of BCLK
o Update Documentation to include RCW.
o Update DAI documentation for label = value DAI modes.
o Add RCW support to wm8731, wm8750 and pxa2xx-i2s drivers.
Signed-off-by: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/wm8731.c | 33 | ||||
-rw-r--r-- | sound/soc/codecs/wm8750.c | 15 | ||||
-rw-r--r-- | sound/soc/pxa/pxa2xx-i2s.c | 3 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 215 |
4 files changed, 196 insertions, 70 deletions
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 9adbd2d401c4..412291241ece 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -90,32 +90,36 @@ static struct snd_soc_dai_mode wm8731_modes[] = { | |||
90 | .pcmfmt = WM8731_HIFI_BITS, | 90 | .pcmfmt = WM8731_HIFI_BITS, |
91 | .pcmrate = SNDRV_PCM_RATE_8000, | 91 | .pcmrate = SNDRV_PCM_RATE_8000, |
92 | .pcmdir = WM8731_DIR, | 92 | .pcmdir = WM8731_DIR, |
93 | .flags = SND_SOC_DAI_BFS_RATE, | ||
93 | .fs = 1536, | 94 | .fs = 1536, |
94 | .bfs = SND_SOC_FSB(64), | 95 | .bfs = 64, |
95 | }, | 96 | }, |
96 | { | 97 | { |
97 | .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | 98 | .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, |
98 | .pcmfmt = WM8731_HIFI_BITS, | 99 | .pcmfmt = WM8731_HIFI_BITS, |
99 | .pcmrate = SNDRV_PCM_RATE_8000, | 100 | .pcmrate = SNDRV_PCM_RATE_8000, |
100 | .pcmdir = WM8731_DIR, | 101 | .pcmdir = WM8731_DIR, |
102 | .flags = SND_SOC_DAI_BFS_RATE, | ||
101 | .fs = 2304, | 103 | .fs = 2304, |
102 | .bfs = SND_SOC_FSB(64), | 104 | .bfs = 64, |
103 | }, | 105 | }, |
104 | { | 106 | { |
105 | .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | 107 | .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, |
106 | .pcmfmt = WM8731_HIFI_BITS, | 108 | .pcmfmt = WM8731_HIFI_BITS, |
107 | .pcmrate = SNDRV_PCM_RATE_8000, | 109 | .pcmrate = SNDRV_PCM_RATE_8000, |
108 | .pcmdir = WM8731_DIR, | 110 | .pcmdir = WM8731_DIR, |
111 | .flags = SND_SOC_DAI_BFS_RATE, | ||
109 | .fs = 1408, | 112 | .fs = 1408, |
110 | .bfs = SND_SOC_FSB(64), | 113 | .bfs = 64, |
111 | }, | 114 | }, |
112 | { | 115 | { |
113 | .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | 116 | .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, |
114 | .pcmfmt = WM8731_HIFI_BITS, | 117 | .pcmfmt = WM8731_HIFI_BITS, |
115 | .pcmrate = SNDRV_PCM_RATE_8000, | 118 | .pcmrate = SNDRV_PCM_RATE_8000, |
116 | .pcmdir = WM8731_DIR, | 119 | .pcmdir = WM8731_DIR, |
120 | .flags = SND_SOC_DAI_BFS_RATE, | ||
117 | .fs = 2112, | 121 | .fs = 2112, |
118 | .bfs = SND_SOC_FSB(64), | 122 | .bfs = 64, |
119 | }, | 123 | }, |
120 | 124 | ||
121 | /* 32k */ | 125 | /* 32k */ |
@@ -124,16 +128,18 @@ static struct snd_soc_dai_mode wm8731_modes[] = { | |||
124 | .pcmfmt = WM8731_HIFI_BITS, | 128 | .pcmfmt = WM8731_HIFI_BITS, |
125 | .pcmrate = SNDRV_PCM_RATE_32000, | 129 | .pcmrate = SNDRV_PCM_RATE_32000, |
126 | .pcmdir = WM8731_DIR, | 130 | .pcmdir = WM8731_DIR, |
131 | .flags = SND_SOC_DAI_BFS_RATE, | ||
127 | .fs = 384, | 132 | .fs = 384, |
128 | .bfs = SND_SOC_FSB(64), | 133 | .bfs = 64, |
129 | }, | 134 | }, |
130 | { | 135 | { |
131 | .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | 136 | .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, |
132 | .pcmfmt = WM8731_HIFI_BITS, | 137 | .pcmfmt = WM8731_HIFI_BITS, |
133 | .pcmrate = SNDRV_PCM_RATE_32000, | 138 | .pcmrate = SNDRV_PCM_RATE_32000, |
134 | .pcmdir = WM8731_DIR, | 139 | .pcmdir = WM8731_DIR, |
140 | .flags = SND_SOC_DAI_BFS_RATE, | ||
135 | .fs = 576, | 141 | .fs = 576, |
136 | .bfs = SND_SOC_FSB(64), | 142 | .bfs = 64, |
137 | }, | 143 | }, |
138 | 144 | ||
139 | /* 44.1k & 48k */ | 145 | /* 44.1k & 48k */ |
@@ -142,16 +148,18 @@ static struct snd_soc_dai_mode wm8731_modes[] = { | |||
142 | .pcmfmt = WM8731_HIFI_BITS, | 148 | .pcmfmt = WM8731_HIFI_BITS, |
143 | .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | 149 | .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, |
144 | .pcmdir = WM8731_DIR, | 150 | .pcmdir = WM8731_DIR, |
151 | .flags = SND_SOC_DAI_BFS_RATE, | ||
145 | .fs = 256, | 152 | .fs = 256, |
146 | .bfs = SND_SOC_FSB(64), | 153 | .bfs = 64, |
147 | }, | 154 | }, |
148 | { | 155 | { |
149 | .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | 156 | .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, |
150 | .pcmfmt = WM8731_HIFI_BITS, | 157 | .pcmfmt = WM8731_HIFI_BITS, |
151 | .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | 158 | .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, |
152 | .pcmdir = WM8731_DIR, | 159 | .pcmdir = WM8731_DIR, |
160 | .flags = SND_SOC_DAI_BFS_RATE, | ||
153 | .fs = 384, | 161 | .fs = 384, |
154 | .bfs = SND_SOC_FSB(64), | 162 | .bfs = 64, |
155 | }, | 163 | }, |
156 | 164 | ||
157 | /* 88.2 & 96k */ | 165 | /* 88.2 & 96k */ |
@@ -160,17 +168,18 @@ static struct snd_soc_dai_mode wm8731_modes[] = { | |||
160 | .pcmfmt = WM8731_HIFI_BITS, | 168 | .pcmfmt = WM8731_HIFI_BITS, |
161 | .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, | 169 | .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, |
162 | .pcmdir = WM8731_DIR, | 170 | .pcmdir = WM8731_DIR, |
171 | .flags = SND_SOC_DAI_BFS_RATE, | ||
163 | .fs = 128, | 172 | .fs = 128, |
164 | .bfs = SND_SOC_FSB(64), | 173 | .bfs = 64, |
165 | |||
166 | }, | 174 | }, |
167 | { | 175 | { |
168 | .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | 176 | .fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, |
169 | .pcmfmt = WM8731_HIFI_BITS, | 177 | .pcmfmt = WM8731_HIFI_BITS, |
170 | .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, | 178 | .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, |
171 | .pcmdir = WM8731_DIR, | 179 | .pcmdir = WM8731_DIR, |
180 | .flags = SND_SOC_DAI_BFS_RATE, | ||
172 | .fs = 192, | 181 | .fs = 192, |
173 | .bfs = SND_SOC_FSB(64), | 182 | .bfs = 64, |
174 | }, | 183 | }, |
175 | 184 | ||
176 | /* USB codec frame and clock master modes */ | 185 | /* USB codec frame and clock master modes */ |
@@ -237,7 +246,7 @@ static struct snd_soc_dai_mode wm8731_modes[] = { | |||
237 | .pcmdir = WM8731_DIR, | 246 | .pcmdir = WM8731_DIR, |
238 | .flags = SND_SOC_DAI_BFS_DIV, | 247 | .flags = SND_SOC_DAI_BFS_DIV, |
239 | .fs = SND_SOC_FS_ALL, | 248 | .fs = SND_SOC_FS_ALL, |
240 | .bfs = SND_SOC_FSBD_ALL, | 249 | .bfs = SND_SOC_FSB_ALL, |
241 | }, | 250 | }, |
242 | }; | 251 | }; |
243 | 252 | ||
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 243da712d9c1..c5d13a9454d9 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -343,7 +343,7 @@ static struct snd_soc_dai_mode wm8750_modes[] = { | |||
343 | .pcmdir = WM8750_DIR, | 343 | .pcmdir = WM8750_DIR, |
344 | .flags = SND_SOC_DAI_BFS_DIV, | 344 | .flags = SND_SOC_DAI_BFS_DIV, |
345 | .fs = SND_SOC_FS_ALL, | 345 | .fs = SND_SOC_FS_ALL, |
346 | .bfs = SND_SOC_FSBD_ALL, | 346 | .bfs = SND_SOC_FSB_ALL, |
347 | }, | 347 | }, |
348 | }; | 348 | }; |
349 | 349 | ||
@@ -829,6 +829,9 @@ static inline int get_coeff(int mclk, int rate) | |||
829 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) | 829 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) |
830 | return i; | 830 | return i; |
831 | } | 831 | } |
832 | |||
833 | printk(KERN_ERR "wm8750: could not get coeff for mclk %d @ rate %d\n", | ||
834 | mclk, rate); | ||
832 | return -EINVAL; | 835 | return -EINVAL; |
833 | } | 836 | } |
834 | 837 | ||
@@ -836,13 +839,7 @@ static inline int get_coeff(int mclk, int rate) | |||
836 | static unsigned int wm8750_config_sysclk(struct snd_soc_codec_dai *dai, | 839 | static unsigned int wm8750_config_sysclk(struct snd_soc_codec_dai *dai, |
837 | struct snd_soc_clock_info *info, unsigned int clk) | 840 | struct snd_soc_clock_info *info, unsigned int clk) |
838 | { | 841 | { |
839 | dai->mclk = 0; | 842 | dai->mclk = clk; |
840 | |||
841 | /* check that the calculated FS and rate actually match a clock from | ||
842 | * the machine driver */ | ||
843 | if (info->fs * info->rate == clk) | ||
844 | dai->mclk = clk; | ||
845 | |||
846 | return dai->mclk; | 843 | return dai->mclk; |
847 | } | 844 | } |
848 | 845 | ||
@@ -859,7 +856,7 @@ static int wm8750_pcm_prepare(struct snd_pcm_substream *substream) | |||
859 | if (i < 0) | 856 | if (i < 0) |
860 | return i; | 857 | return i; |
861 | 858 | ||
862 | bfs = SND_SOC_FSB_REAL(rtd->codec_dai->dai_runtime.bfs); | 859 | bfs = SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs); |
863 | 860 | ||
864 | /* set master/slave audio interface */ | 861 | /* set master/slave audio interface */ |
865 | switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) { | 862 | switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) { |
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 99f1da32744b..98b167fe68e5 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c | |||
@@ -126,7 +126,8 @@ static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = { | |||
126 | .pcmrate = PXA_I2S_RATES, | 126 | .pcmrate = PXA_I2S_RATES, |
127 | .pcmdir = PXA_I2S_DIR, | 127 | .pcmdir = PXA_I2S_DIR, |
128 | .fs = SND_SOC_FS_ALL, | 128 | .fs = SND_SOC_FS_ALL, |
129 | .bfs = SND_SOC_FSB(64), | 129 | .flags = SND_SOC_DAI_BFS_RATE, |
130 | .bfs = 64, | ||
130 | .priv = 0x48, | 131 | .priv = 0x48, |
131 | }, | 132 | }, |
132 | }; | 133 | }; |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2ce0c8251dc3..6da1616bf776 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -51,6 +51,8 @@ | |||
51 | #define dbgc(format, arg...) | 51 | #define dbgc(format, arg...) |
52 | #endif | 52 | #endif |
53 | 53 | ||
54 | #define CODEC_CPU(codec, cpu) ((codec << 4) | cpu) | ||
55 | |||
54 | static DEFINE_MUTEX(pcm_mutex); | 56 | static DEFINE_MUTEX(pcm_mutex); |
55 | static DEFINE_MUTEX(io_mutex); | 57 | static DEFINE_MUTEX(io_mutex); |
56 | static struct workqueue_struct *soc_workq; | 58 | static struct workqueue_struct *soc_workq; |
@@ -150,11 +152,11 @@ static unsigned inline int soc_get_mclk(struct snd_soc_pcm_runtime *rtd, | |||
150 | } | 152 | } |
151 | 153 | ||
152 | /* changes a bitclk multiplier mask to a divider mask */ | 154 | /* changes a bitclk multiplier mask to a divider mask */ |
153 | static u16 soc_bfs_mult_to_div(u16 bfs, int rate, unsigned int mclk, | 155 | static u64 soc_bfs_rcw_to_div(u64 bfs, int rate, unsigned int mclk, |
154 | unsigned int pcmfmt, unsigned int chn) | 156 | unsigned int pcmfmt, unsigned int chn) |
155 | { | 157 | { |
156 | int i, j; | 158 | int i, j; |
157 | u16 bfs_ = 0; | 159 | u64 bfs_ = 0; |
158 | int size = snd_pcm_format_physical_width(pcmfmt), min = 0; | 160 | int size = snd_pcm_format_physical_width(pcmfmt), min = 0; |
159 | 161 | ||
160 | if (size <= 0) | 162 | if (size <= 0) |
@@ -162,17 +164,14 @@ static u16 soc_bfs_mult_to_div(u16 bfs, int rate, unsigned int mclk, | |||
162 | 164 | ||
163 | /* the minimum bit clock that has enough bandwidth */ | 165 | /* the minimum bit clock that has enough bandwidth */ |
164 | min = size * rate * chn; | 166 | min = size * rate * chn; |
165 | dbgc("mult --> div min bclk %d with mclk %d\n", min, mclk); | 167 | dbgc("rcw --> div min bclk %d with mclk %d\n", min, mclk); |
166 | 168 | ||
167 | for (i = 0; i < 16; i++) { | 169 | for (i = 0; i < 64; i++) { |
168 | if ((bfs >> i) & 0x1) { | 170 | if ((bfs >> i) & 0x1) { |
169 | j = rate * SND_SOC_FSB_REAL(1<<i); | 171 | j = min * (i + 1); |
170 | 172 | bfs_ |= SND_SOC_FSBD(mclk/j); | |
171 | if (j >= min) { | 173 | dbgc("rcw --> div support mult %d\n", |
172 | bfs_ |= SND_SOC_FSBD(mclk/j); | 174 | SND_SOC_FSBD_REAL(1<<i)); |
173 | dbgc("mult --> div support mult %d\n", | ||
174 | SND_SOC_FSB_REAL(1<<i)); | ||
175 | } | ||
176 | } | 175 | } |
177 | } | 176 | } |
178 | 177 | ||
@@ -180,11 +179,11 @@ static u16 soc_bfs_mult_to_div(u16 bfs, int rate, unsigned int mclk, | |||
180 | } | 179 | } |
181 | 180 | ||
182 | /* changes a bitclk divider mask to a multiplier mask */ | 181 | /* changes a bitclk divider mask to a multiplier mask */ |
183 | static u16 soc_bfs_div_to_mult(u16 bfs, int rate, unsigned int mclk, | 182 | static u64 soc_bfs_div_to_rcw(u64 bfs, int rate, unsigned int mclk, |
184 | unsigned int pcmfmt, unsigned int chn) | 183 | unsigned int pcmfmt, unsigned int chn) |
185 | { | 184 | { |
186 | int i, j; | 185 | int i, j; |
187 | u16 bfs_ = 0; | 186 | u64 bfs_ = 0; |
188 | 187 | ||
189 | int size = snd_pcm_format_physical_width(pcmfmt), min = 0; | 188 | int size = snd_pcm_format_physical_width(pcmfmt), min = 0; |
190 | 189 | ||
@@ -193,15 +192,15 @@ static u16 soc_bfs_div_to_mult(u16 bfs, int rate, unsigned int mclk, | |||
193 | 192 | ||
194 | /* the minimum bit clock that has enough bandwidth */ | 193 | /* the minimum bit clock that has enough bandwidth */ |
195 | min = size * rate * chn; | 194 | min = size * rate * chn; |
196 | dbgc("div to mult min bclk %d with mclk %d\n", min, mclk); | 195 | dbgc("div to rcw min bclk %d with mclk %d\n", min, mclk); |
197 | 196 | ||
198 | for (i = 0; i < 16; i++) { | 197 | for (i = 0; i < 64; i++) { |
199 | if ((bfs >> i) & 0x1) { | 198 | if ((bfs >> i) & 0x1) { |
200 | j = mclk / (SND_SOC_FSBD_REAL(1<<i)); | 199 | j = mclk / (i + 1); |
201 | if (j >= min) { | 200 | if (j >= min) { |
202 | bfs_ |= SND_SOC_FSB(j/rate); | 201 | bfs_ |= SND_SOC_FSBW(j/min); |
203 | dbgc("div --> mult support div %d\n", | 202 | dbgc("div --> rcw support div %d\n", |
204 | SND_SOC_FSBD_REAL(1<<i)); | 203 | SND_SOC_FSBW_REAL(1<<i)); |
205 | } | 204 | } |
206 | } | 205 | } |
207 | } | 206 | } |
@@ -209,6 +208,52 @@ static u16 soc_bfs_div_to_mult(u16 bfs, int rate, unsigned int mclk, | |||
209 | return bfs_; | 208 | return bfs_; |
210 | } | 209 | } |
211 | 210 | ||
211 | /* changes a constant bitclk to a multiplier mask */ | ||
212 | static u64 soc_bfs_rate_to_rcw(u64 bfs, int rate, unsigned int mclk, | ||
213 | unsigned int pcmfmt, unsigned int chn) | ||
214 | { | ||
215 | unsigned int bfs_ = rate * bfs; | ||
216 | int size = snd_pcm_format_physical_width(pcmfmt), min = 0; | ||
217 | |||
218 | if (size <= 0) | ||
219 | return 0; | ||
220 | |||
221 | /* the minimum bit clock that has enough bandwidth */ | ||
222 | min = size * rate * chn; | ||
223 | dbgc("rate --> rcw min bclk %d with mclk %d\n", min, mclk); | ||
224 | |||
225 | if (bfs_ < min) | ||
226 | return 0; | ||
227 | else { | ||
228 | bfs_ = SND_SOC_FSBW(bfs_/min); | ||
229 | dbgc("rate --> rcw support div %d\n", SND_SOC_FSBW_REAL(bfs_)); | ||
230 | return bfs_; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | /* changes a bitclk multiplier mask to a divider mask */ | ||
235 | static u64 soc_bfs_rate_to_div(u64 bfs, int rate, unsigned int mclk, | ||
236 | unsigned int pcmfmt, unsigned int chn) | ||
237 | { | ||
238 | unsigned int bfs_ = rate * bfs; | ||
239 | int size = snd_pcm_format_physical_width(pcmfmt), min = 0; | ||
240 | |||
241 | if (size <= 0) | ||
242 | return 0; | ||
243 | |||
244 | /* the minimum bit clock that has enough bandwidth */ | ||
245 | min = size * rate * chn; | ||
246 | dbgc("rate --> div min bclk %d with mclk %d\n", min, mclk); | ||
247 | |||
248 | if (bfs_ < min) | ||
249 | return 0; | ||
250 | else { | ||
251 | bfs_ = SND_SOC_FSBW(mclk/bfs_); | ||
252 | dbgc("rate --> div support div %d\n", SND_SOC_FSBD_REAL(bfs_)); | ||
253 | return bfs_; | ||
254 | } | ||
255 | } | ||
256 | |||
212 | /* Matches codec DAI and SoC CPU DAI hardware parameters */ | 257 | /* Matches codec DAI and SoC CPU DAI hardware parameters */ |
213 | static int soc_hw_match_params(struct snd_pcm_substream *substream, | 258 | static int soc_hw_match_params(struct snd_pcm_substream *substream, |
214 | struct snd_pcm_hw_params *params) | 259 | struct snd_pcm_hw_params *params) |
@@ -217,9 +262,10 @@ static int soc_hw_match_params(struct snd_pcm_substream *substream, | |||
217 | struct snd_soc_dai_mode *codec_dai_mode = NULL; | 262 | struct snd_soc_dai_mode *codec_dai_mode = NULL; |
218 | struct snd_soc_dai_mode *cpu_dai_mode = NULL; | 263 | struct snd_soc_dai_mode *cpu_dai_mode = NULL; |
219 | struct snd_soc_clock_info clk_info; | 264 | struct snd_soc_clock_info clk_info; |
220 | unsigned int fs, mclk, codec_bfs, cpu_bfs, rate = params_rate(params), | 265 | unsigned int fs, mclk, rate = params_rate(params), |
221 | chn, j, k, cpu_bclk, codec_bclk, pcmrate; | 266 | chn, j, k, cpu_bclk, codec_bclk, pcmrate; |
222 | u16 fmt = 0; | 267 | u16 fmt = 0; |
268 | u64 codec_bfs, cpu_bfs; | ||
223 | 269 | ||
224 | dbg("asoc: match version %s\n", SND_SOC_VERSION); | 270 | dbg("asoc: match version %s\n", SND_SOC_VERSION); |
225 | clk_info.rate = rate; | 271 | clk_info.rate = rate; |
@@ -309,44 +355,98 @@ static int soc_hw_match_params(struct snd_pcm_substream *substream, | |||
309 | * used in the codec and cpu DAI modes. We always choose the | 355 | * used in the codec and cpu DAI modes. We always choose the |
310 | * lowest possible clocks to reduce power. | 356 | * lowest possible clocks to reduce power. |
311 | */ | 357 | */ |
312 | if (codec_dai_mode->flags & cpu_dai_mode->flags & | 358 | switch (CODEC_CPU(codec_dai_mode->flags, cpu_dai_mode->flags)) { |
313 | SND_SOC_DAI_BFS_DIV) { | 359 | case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_DIV): |
314 | /* cpu & codec bfs dividers */ | 360 | /* cpu & codec bfs dividers */ |
315 | rtd->cpu_dai->dai_runtime.bfs = | 361 | rtd->cpu_dai->dai_runtime.bfs = |
316 | rtd->codec_dai->dai_runtime.bfs = | 362 | rtd->codec_dai->dai_runtime.bfs = |
317 | 1 << (fls(codec_dai_mode->bfs & cpu_dai_mode->bfs) - 1); | 363 | 1 << (fls(codec_dai_mode->bfs & cpu_dai_mode->bfs) - 1); |
318 | } else if (codec_dai_mode->flags & SND_SOC_DAI_BFS_DIV) { | 364 | break; |
319 | /* normalise bfs codec divider & cpu mult */ | 365 | case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_RCW): |
320 | codec_bfs = soc_bfs_div_to_mult(codec_dai_mode->bfs, rate, | 366 | /* normalise bfs codec divider & cpu rcw mult */ |
367 | codec_bfs = soc_bfs_div_to_rcw(codec_dai_mode->bfs, rate, | ||
321 | mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); | 368 | mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); |
322 | rtd->cpu_dai->dai_runtime.bfs = | 369 | rtd->cpu_dai->dai_runtime.bfs = |
323 | 1 << (ffs(codec_bfs & cpu_dai_mode->bfs) - 1); | 370 | 1 << (ffs(codec_bfs & cpu_dai_mode->bfs) - 1); |
324 | cpu_bfs = soc_bfs_mult_to_div(cpu_dai_mode->bfs, rate, mclk, | 371 | cpu_bfs = soc_bfs_rcw_to_div(cpu_dai_mode->bfs, rate, mclk, |
325 | rtd->codec_dai->dai_runtime.pcmfmt, chn); | 372 | rtd->codec_dai->dai_runtime.pcmfmt, chn); |
326 | rtd->codec_dai->dai_runtime.bfs = | 373 | rtd->codec_dai->dai_runtime.bfs = |
327 | 1 << (fls(codec_dai_mode->bfs & cpu_bfs) - 1); | 374 | 1 << (fls(codec_dai_mode->bfs & cpu_bfs) - 1); |
328 | } else if (cpu_dai_mode->flags & SND_SOC_DAI_BFS_DIV) { | 375 | break; |
329 | /* normalise bfs codec mult & cpu divider */ | 376 | case CODEC_CPU(SND_SOC_DAI_BFS_RCW, SND_SOC_DAI_BFS_DIV): |
330 | codec_bfs = soc_bfs_mult_to_div(codec_dai_mode->bfs, rate, | 377 | /* normalise bfs codec rcw mult & cpu divider */ |
378 | codec_bfs = soc_bfs_rcw_to_div(codec_dai_mode->bfs, rate, | ||
331 | mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); | 379 | mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); |
332 | rtd->cpu_dai->dai_runtime.bfs = | 380 | rtd->cpu_dai->dai_runtime.bfs = |
333 | 1 << (fls(codec_bfs & cpu_dai_mode->bfs) -1); | 381 | 1 << (fls(codec_bfs & cpu_dai_mode->bfs) -1); |
334 | cpu_bfs = soc_bfs_div_to_mult(cpu_dai_mode->bfs, rate, mclk, | 382 | cpu_bfs = soc_bfs_div_to_rcw(cpu_dai_mode->bfs, rate, mclk, |
335 | rtd->codec_dai->dai_runtime.pcmfmt, chn); | 383 | rtd->codec_dai->dai_runtime.pcmfmt, chn); |
336 | rtd->codec_dai->dai_runtime.bfs = | 384 | rtd->codec_dai->dai_runtime.bfs = |
337 | 1 << (ffs(codec_dai_mode->bfs & cpu_bfs) -1); | 385 | 1 << (ffs(codec_dai_mode->bfs & cpu_bfs) -1); |
338 | } else { | 386 | break; |
339 | /* codec & cpu bfs rate multipliers */ | 387 | case CODEC_CPU(SND_SOC_DAI_BFS_RCW, SND_SOC_DAI_BFS_RCW): |
388 | /* codec & cpu bfs rate rcw multipliers */ | ||
340 | rtd->cpu_dai->dai_runtime.bfs = | 389 | rtd->cpu_dai->dai_runtime.bfs = |
341 | rtd->codec_dai->dai_runtime.bfs = | 390 | rtd->codec_dai->dai_runtime.bfs = |
342 | 1 << (ffs(codec_dai_mode->bfs & cpu_dai_mode->bfs) -1); | 391 | 1 << (ffs(codec_dai_mode->bfs & cpu_dai_mode->bfs) -1); |
392 | break; | ||
393 | case CODEC_CPU(SND_SOC_DAI_BFS_DIV, SND_SOC_DAI_BFS_RATE): | ||
394 | /* normalise cpu bfs rate const multiplier & codec div */ | ||
395 | cpu_bfs = soc_bfs_rate_to_div(cpu_dai_mode->bfs, rate, | ||
396 | mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); | ||
397 | if(codec_dai_mode->bfs & cpu_bfs) { | ||
398 | rtd->codec_dai->dai_runtime.bfs = cpu_bfs; | ||
399 | rtd->cpu_dai->dai_runtime.bfs = cpu_dai_mode->bfs; | ||
400 | } else | ||
401 | rtd->cpu_dai->dai_runtime.bfs = 0; | ||
402 | break; | ||
403 | case CODEC_CPU(SND_SOC_DAI_BFS_RCW, SND_SOC_DAI_BFS_RATE): | ||
404 | /* normalise cpu bfs rate const multiplier & codec rcw mult */ | ||
405 | cpu_bfs = soc_bfs_rate_to_rcw(cpu_dai_mode->bfs, rate, | ||
406 | mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); | ||
407 | if(codec_dai_mode->bfs & cpu_bfs) { | ||
408 | rtd->codec_dai->dai_runtime.bfs = cpu_bfs; | ||
409 | rtd->cpu_dai->dai_runtime.bfs = cpu_dai_mode->bfs; | ||
410 | } else | ||
411 | rtd->cpu_dai->dai_runtime.bfs = 0; | ||
412 | break; | ||
413 | case CODEC_CPU(SND_SOC_DAI_BFS_RATE, SND_SOC_DAI_BFS_RCW): | ||
414 | /* normalise cpu bfs rate rcw multiplier & codec const mult */ | ||
415 | codec_bfs = soc_bfs_rate_to_rcw(codec_dai_mode->bfs, rate, | ||
416 | mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); | ||
417 | if(cpu_dai_mode->bfs & codec_bfs) { | ||
418 | rtd->cpu_dai->dai_runtime.bfs = codec_bfs; | ||
419 | rtd->codec_dai->dai_runtime.bfs = codec_dai_mode->bfs; | ||
420 | } else | ||
421 | rtd->cpu_dai->dai_runtime.bfs = 0; | ||
422 | break; | ||
423 | case CODEC_CPU(SND_SOC_DAI_BFS_RATE, SND_SOC_DAI_BFS_DIV): | ||
424 | /* normalise cpu bfs div & codec const mult */ | ||
425 | codec_bfs = soc_bfs_rate_to_div(codec_dai_mode->bfs, rate, | ||
426 | mclk, rtd->codec_dai->dai_runtime.pcmfmt, chn); | ||
427 | if(codec_dai_mode->bfs & codec_bfs) { | ||
428 | rtd->cpu_dai->dai_runtime.bfs = codec_bfs; | ||
429 | rtd->codec_dai->dai_runtime.bfs = codec_dai_mode->bfs; | ||
430 | } else | ||
431 | rtd->cpu_dai->dai_runtime.bfs = 0; | ||
432 | break; | ||
433 | case CODEC_CPU(SND_SOC_DAI_BFS_RATE, SND_SOC_DAI_BFS_RATE): | ||
434 | /* cpu & codec constant mult */ | ||
435 | if(codec_dai_mode->bfs == cpu_dai_mode->bfs) | ||
436 | rtd->cpu_dai->dai_runtime.bfs = | ||
437 | rtd->codec_dai->dai_runtime.bfs = | ||
438 | codec_dai_mode->bfs; | ||
439 | else | ||
440 | rtd->cpu_dai->dai_runtime.bfs = | ||
441 | rtd->codec_dai->dai_runtime.bfs = 0; | ||
442 | break; | ||
343 | } | 443 | } |
344 | 444 | ||
345 | /* make sure the bit clock speed is acceptable */ | 445 | /* make sure the bit clock speed is acceptable */ |
346 | if (!rtd->cpu_dai->dai_runtime.bfs || | 446 | if (!rtd->cpu_dai->dai_runtime.bfs || |
347 | !rtd->codec_dai->dai_runtime.bfs) { | 447 | !rtd->codec_dai->dai_runtime.bfs) { |
348 | dbgc("asoc: DAI[%d:%d] failed to match BFS\n", j, k); | 448 | dbgc("asoc: DAI[%d:%d] failed to match BFS\n", j, k); |
349 | dbgc("asoc: cpu_dai %x codec %x\n", | 449 | dbgc("asoc: cpu_dai %llu codec %llu\n", |
350 | rtd->cpu_dai->dai_runtime.bfs, | 450 | rtd->cpu_dai->dai_runtime.bfs, |
351 | rtd->codec_dai->dai_runtime.bfs); | 451 | rtd->codec_dai->dai_runtime.bfs); |
352 | dbgc("asoc: mclk %d hwfmt %x\n", mclk, fmt); | 452 | dbgc("asoc: mclk %d hwfmt %x\n", mclk, fmt); |
@@ -378,26 +478,41 @@ found: | |||
378 | dbg("asoc: codec fs %d mclk %d bfs div %d bclk %d\n", | 478 | dbg("asoc: codec fs %d mclk %d bfs div %d bclk %d\n", |
379 | rtd->codec_dai->dai_runtime.fs, mclk, | 479 | rtd->codec_dai->dai_runtime.fs, mclk, |
380 | SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk); | 480 | SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk); |
381 | } else { | 481 | } else if(rtd->codec_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RATE) { |
382 | codec_bclk = params_rate(params) * | 482 | codec_bclk = params_rate(params) * rtd->codec_dai->dai_runtime.bfs; |
383 | SND_SOC_FSB_REAL(rtd->codec_dai->dai_runtime.bfs); | 483 | dbg("asoc: codec fs %d mclk %d bfs rate mult %llu bclk %d\n", |
384 | dbg("asoc: codec fs %d mclk %d bfs mult %d bclk %d\n", | ||
385 | rtd->codec_dai->dai_runtime.fs, mclk, | 484 | rtd->codec_dai->dai_runtime.fs, mclk, |
386 | SND_SOC_FSB_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk); | 485 | rtd->codec_dai->dai_runtime.bfs, codec_bclk); |
387 | } | 486 | } else if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RCW) { |
487 | codec_bclk = params_rate(params) * params_channels(params) * | ||
488 | snd_pcm_format_physical_width(rtd->codec_dai->dai_runtime.pcmfmt) * | ||
489 | SND_SOC_FSBW_REAL(rtd->codec_dai->dai_runtime.bfs); | ||
490 | dbg("asoc: codec fs %d mclk %d bfs rcw mult %d bclk %d\n", | ||
491 | rtd->codec_dai->dai_runtime.fs, mclk, | ||
492 | SND_SOC_FSBW_REAL(rtd->codec_dai->dai_runtime.bfs), codec_bclk); | ||
493 | } else | ||
494 | codec_bclk = 0; | ||
495 | |||
388 | if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_DIV) { | 496 | if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_DIV) { |
389 | cpu_bclk = (rtd->cpu_dai->dai_runtime.fs * params_rate(params)) / | 497 | cpu_bclk = (rtd->cpu_dai->dai_runtime.fs * params_rate(params)) / |
390 | SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs); | 498 | SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs); |
391 | dbg("asoc: cpu fs %d mclk %d bfs div %d bclk %d\n", | 499 | dbg("asoc: cpu fs %d mclk %d bfs div %d bclk %d\n", |
392 | rtd->cpu_dai->dai_runtime.fs, mclk, | 500 | rtd->cpu_dai->dai_runtime.fs, mclk, |
393 | SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk); | 501 | SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk); |
394 | } else { | 502 | } else if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RATE) { |
395 | cpu_bclk = params_rate(params) * | 503 | cpu_bclk = params_rate(params) * rtd->cpu_dai->dai_runtime.bfs; |
396 | SND_SOC_FSB_REAL(rtd->cpu_dai->dai_runtime.bfs); | 504 | dbg("asoc: cpu fs %d mclk %d bfs rate mult %llu bclk %d\n", |
397 | dbg("asoc: cpu fs %d mclk %d bfs mult %d bclk %d\n", | ||
398 | rtd->cpu_dai->dai_runtime.fs, mclk, | 505 | rtd->cpu_dai->dai_runtime.fs, mclk, |
399 | SND_SOC_FSB_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk); | 506 | rtd->cpu_dai->dai_runtime.bfs, cpu_bclk); |
400 | } | 507 | } else if (rtd->cpu_dai->dai_runtime.flags == SND_SOC_DAI_BFS_RCW) { |
508 | cpu_bclk = params_rate(params) * params_channels(params) * | ||
509 | snd_pcm_format_physical_width(rtd->cpu_dai->dai_runtime.pcmfmt) * | ||
510 | SND_SOC_FSBW_REAL(rtd->cpu_dai->dai_runtime.bfs); | ||
511 | dbg("asoc: cpu fs %d mclk %d bfs mult rcw %d bclk %d\n", | ||
512 | rtd->cpu_dai->dai_runtime.fs, mclk, | ||
513 | SND_SOC_FSBW_REAL(rtd->cpu_dai->dai_runtime.bfs), cpu_bclk); | ||
514 | } else | ||
515 | cpu_bclk = 0; | ||
401 | 516 | ||
402 | /* | 517 | /* |
403 | * Check we have matching bitclocks. If we don't then it means the | 518 | * Check we have matching bitclocks. If we don't then it means the |
@@ -405,7 +520,7 @@ found: | |||
405 | * machine sysclock function) is wrong compared with the supported DAI | 520 | * machine sysclock function) is wrong compared with the supported DAI |
406 | * modes for the codec or cpu DAI. | 521 | * modes for the codec or cpu DAI. |
407 | */ | 522 | */ |
408 | if (cpu_bclk != codec_bclk){ | 523 | if (cpu_bclk != codec_bclk && cpu_bclk){ |
409 | printk(KERN_ERR | 524 | printk(KERN_ERR |
410 | "asoc: codec and cpu bitclocks differ, audio may be wrong speed\n" | 525 | "asoc: codec and cpu bitclocks differ, audio may be wrong speed\n" |
411 | ); | 526 | ); |
@@ -723,14 +838,18 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
723 | mutex_lock(&pcm_mutex); | 838 | mutex_lock(&pcm_mutex); |
724 | if (platform->pcm_ops->prepare) { | 839 | if (platform->pcm_ops->prepare) { |
725 | ret = platform->pcm_ops->prepare(substream); | 840 | ret = platform->pcm_ops->prepare(substream); |
726 | if (ret < 0) | 841 | if (ret < 0) { |
842 | printk(KERN_ERR "asoc: platform prepare error\n"); | ||
727 | goto out; | 843 | goto out; |
844 | } | ||
728 | } | 845 | } |
729 | 846 | ||
730 | if (rtd->codec_dai->ops.prepare) { | 847 | if (rtd->codec_dai->ops.prepare) { |
731 | ret = rtd->codec_dai->ops.prepare(substream); | 848 | ret = rtd->codec_dai->ops.prepare(substream); |
732 | if (ret < 0) | 849 | if (ret < 0) { |
850 | printk(KERN_ERR "asoc: codec DAI prepare error\n"); | ||
733 | goto out; | 851 | goto out; |
852 | } | ||
734 | } | 853 | } |
735 | 854 | ||
736 | if (rtd->cpu_dai->ops.prepare) | 855 | if (rtd->cpu_dai->ops.prepare) |