aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/omap/omap-mcbsp.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-03-18 13:22:37 -0400
committerTakashi Iwai <tiwai@suse.de>2012-03-18 13:22:37 -0400
commitcb3f2adc03ab055b19c677a6283523861fafebdd (patch)
tree59cfb6800f0635a4aec16c8e0da619f27e51ee79 /sound/soc/omap/omap-mcbsp.c
parent44c76a960a62fcc46cbcaa0a22a34e666a729329 (diff)
parent828006de1bddf83b6ecf03ec459c15f7c7c22db7 (diff)
Merge branch 'topic/asoc' into for-linus
Diffstat (limited to 'sound/soc/omap/omap-mcbsp.c')
-rw-r--r--sound/soc/omap/omap-mcbsp.c321
1 files changed, 173 insertions, 148 deletions
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 017371913ec3..6912ac7cb625 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -25,6 +25,7 @@
25#include <linux/init.h> 25#include <linux/init.h>
26#include <linux/module.h> 26#include <linux/module.h>
27#include <linux/device.h> 27#include <linux/device.h>
28#include <linux/pm_runtime.h>
28#include <sound/core.h> 29#include <sound/core.h>
29#include <sound/pcm.h> 30#include <sound/pcm.h>
30#include <sound/pcm_params.h> 31#include <sound/pcm_params.h>
@@ -33,6 +34,7 @@
33 34
34#include <plat/dma.h> 35#include <plat/dma.h>
35#include <plat/mcbsp.h> 36#include <plat/mcbsp.h>
37#include "mcbsp.h"
36#include "omap-mcbsp.h" 38#include "omap-mcbsp.h"
37#include "omap-pcm.h" 39#include "omap-pcm.h"
38 40
@@ -46,42 +48,31 @@
46 .private_value = (unsigned long) &(struct soc_mixer_control) \ 48 .private_value = (unsigned long) &(struct soc_mixer_control) \
47 {.min = xmin, .max = xmax} } 49 {.min = xmin, .max = xmax} }
48 50
49struct omap_mcbsp_data { 51enum {
50 unsigned int bus_id; 52 OMAP_MCBSP_WORD_8 = 0,
51 struct omap_mcbsp_reg_cfg regs; 53 OMAP_MCBSP_WORD_12,
52 unsigned int fmt; 54 OMAP_MCBSP_WORD_16,
53 /* 55 OMAP_MCBSP_WORD_20,
54 * Flags indicating is the bus already activated and configured by 56 OMAP_MCBSP_WORD_24,
55 * another substream 57 OMAP_MCBSP_WORD_32,
56 */
57 int active;
58 int configured;
59 unsigned int in_freq;
60 int clk_div;
61 int wlen;
62}; 58};
63 59
64static struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
65
66/* 60/*
67 * Stream DMA parameters. DMA request line and port address are set runtime 61 * Stream DMA parameters. DMA request line and port address are set runtime
68 * since they are different between OMAP1 and later OMAPs 62 * since they are different between OMAP1 and later OMAPs
69 */ 63 */
70static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2];
71
72static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream) 64static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
73{ 65{
74 struct snd_soc_pcm_runtime *rtd = substream->private_data; 66 struct snd_soc_pcm_runtime *rtd = substream->private_data;
75 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 67 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
76 struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); 68 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
77 struct omap_pcm_dma_data *dma_data; 69 struct omap_pcm_dma_data *dma_data;
78 int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id);
79 int words; 70 int words;
80 71
81 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); 72 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
82 73
83 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ 74 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
84 if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) 75 if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
85 /* 76 /*
86 * Configure McBSP threshold based on either: 77 * Configure McBSP threshold based on either:
87 * packet_size, when the sDMA is in packet mode, or 78 * packet_size, when the sDMA is in packet mode, or
@@ -91,15 +82,15 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
91 words = dma_data->packet_size; 82 words = dma_data->packet_size;
92 else 83 else
93 words = snd_pcm_lib_period_bytes(substream) / 84 words = snd_pcm_lib_period_bytes(substream) /
94 (mcbsp_data->wlen / 8); 85 (mcbsp->wlen / 8);
95 else 86 else
96 words = 1; 87 words = 1;
97 88
98 /* Configure McBSP internal buffer usage */ 89 /* Configure McBSP internal buffer usage */
99 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 90 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
100 omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, words); 91 omap_mcbsp_set_tx_threshold(mcbsp, words);
101 else 92 else
102 omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, words); 93 omap_mcbsp_set_rx_threshold(mcbsp, words);
103} 94}
104 95
105static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params, 96static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
@@ -109,12 +100,12 @@ static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
109 SNDRV_PCM_HW_PARAM_BUFFER_SIZE); 100 SNDRV_PCM_HW_PARAM_BUFFER_SIZE);
110 struct snd_interval *channels = hw_param_interval(params, 101 struct snd_interval *channels = hw_param_interval(params,
111 SNDRV_PCM_HW_PARAM_CHANNELS); 102 SNDRV_PCM_HW_PARAM_CHANNELS);
112 struct omap_mcbsp_data *mcbsp_data = rule->private; 103 struct omap_mcbsp *mcbsp = rule->private;
113 struct snd_interval frames; 104 struct snd_interval frames;
114 int size; 105 int size;
115 106
116 snd_interval_any(&frames); 107 snd_interval_any(&frames);
117 size = omap_mcbsp_get_fifo_size(mcbsp_data->bus_id); 108 size = mcbsp->pdata->buffer_size;
118 109
119 frames.min = size / channels->min; 110 frames.min = size / channels->min;
120 frames.integer = 1; 111 frames.integer = 1;
@@ -124,12 +115,11 @@ static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
124static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, 115static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
125 struct snd_soc_dai *cpu_dai) 116 struct snd_soc_dai *cpu_dai)
126{ 117{
127 struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); 118 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
128 int bus_id = mcbsp_data->bus_id;
129 int err = 0; 119 int err = 0;
130 120
131 if (!cpu_dai->active) 121 if (!cpu_dai->active)
132 err = omap_mcbsp_request(bus_id); 122 err = omap_mcbsp_request(mcbsp);
133 123
134 /* 124 /*
135 * OMAP3 McBSP FIFO is word structured. 125 * OMAP3 McBSP FIFO is word structured.
@@ -146,16 +136,16 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
146 * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words) 136 * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
147 * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words) 137 * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
148 */ 138 */
149 if (cpu_is_omap34xx() || cpu_is_omap44xx()) { 139 if (mcbsp->pdata->buffer_size) {
150 /* 140 /*
151 * Rule for the buffer size. We should not allow 141 * Rule for the buffer size. We should not allow
152 * smaller buffer than the FIFO size to avoid underruns 142 * smaller buffer than the FIFO size to avoid underruns
153 */ 143 */
154 snd_pcm_hw_rule_add(substream->runtime, 0, 144 snd_pcm_hw_rule_add(substream->runtime, 0,
155 SNDRV_PCM_HW_PARAM_CHANNELS, 145 SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
156 omap_mcbsp_hwrule_min_buffersize, 146 omap_mcbsp_hwrule_min_buffersize,
157 mcbsp_data, 147 mcbsp,
158 SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); 148 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
159 149
160 /* Make sure, that the period size is always even */ 150 /* Make sure, that the period size is always even */
161 snd_pcm_hw_constraint_step(substream->runtime, 0, 151 snd_pcm_hw_constraint_step(substream->runtime, 0,
@@ -168,33 +158,33 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
168static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream, 158static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
169 struct snd_soc_dai *cpu_dai) 159 struct snd_soc_dai *cpu_dai)
170{ 160{
171 struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); 161 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
172 162
173 if (!cpu_dai->active) { 163 if (!cpu_dai->active) {
174 omap_mcbsp_free(mcbsp_data->bus_id); 164 omap_mcbsp_free(mcbsp);
175 mcbsp_data->configured = 0; 165 mcbsp->configured = 0;
176 } 166 }
177} 167}
178 168
179static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, 169static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
180 struct snd_soc_dai *cpu_dai) 170 struct snd_soc_dai *cpu_dai)
181{ 171{
182 struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); 172 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
183 int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 173 int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
184 174
185 switch (cmd) { 175 switch (cmd) {
186 case SNDRV_PCM_TRIGGER_START: 176 case SNDRV_PCM_TRIGGER_START:
187 case SNDRV_PCM_TRIGGER_RESUME: 177 case SNDRV_PCM_TRIGGER_RESUME:
188 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 178 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
189 mcbsp_data->active++; 179 mcbsp->active++;
190 omap_mcbsp_start(mcbsp_data->bus_id, play, !play); 180 omap_mcbsp_start(mcbsp, play, !play);
191 break; 181 break;
192 182
193 case SNDRV_PCM_TRIGGER_STOP: 183 case SNDRV_PCM_TRIGGER_STOP:
194 case SNDRV_PCM_TRIGGER_SUSPEND: 184 case SNDRV_PCM_TRIGGER_SUSPEND:
195 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 185 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
196 omap_mcbsp_stop(mcbsp_data->bus_id, play, !play); 186 omap_mcbsp_stop(mcbsp, play, !play);
197 mcbsp_data->active--; 187 mcbsp->active--;
198 break; 188 break;
199 default: 189 default:
200 err = -EINVAL; 190 err = -EINVAL;
@@ -209,14 +199,14 @@ static snd_pcm_sframes_t omap_mcbsp_dai_delay(
209{ 199{
210 struct snd_soc_pcm_runtime *rtd = substream->private_data; 200 struct snd_soc_pcm_runtime *rtd = substream->private_data;
211 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 201 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
212 struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); 202 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
213 u16 fifo_use; 203 u16 fifo_use;
214 snd_pcm_sframes_t delay; 204 snd_pcm_sframes_t delay;
215 205
216 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 206 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
217 fifo_use = omap_mcbsp_get_tx_delay(mcbsp_data->bus_id); 207 fifo_use = omap_mcbsp_get_tx_delay(mcbsp);
218 else 208 else
219 fifo_use = omap_mcbsp_get_rx_delay(mcbsp_data->bus_id); 209 fifo_use = omap_mcbsp_get_rx_delay(mcbsp);
220 210
221 /* 211 /*
222 * Divide the used locations with the channel count to get the 212 * Divide the used locations with the channel count to get the
@@ -232,19 +222,14 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
232 struct snd_pcm_hw_params *params, 222 struct snd_pcm_hw_params *params,
233 struct snd_soc_dai *cpu_dai) 223 struct snd_soc_dai *cpu_dai)
234{ 224{
235 struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); 225 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
236 struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; 226 struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
237 struct omap_pcm_dma_data *dma_data; 227 struct omap_pcm_dma_data *dma_data;
238 int dma, bus_id = mcbsp_data->bus_id;
239 int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT; 228 int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
240 int pkt_size = 0; 229 int pkt_size = 0;
241 unsigned long port;
242 unsigned int format, div, framesize, master; 230 unsigned int format, div, framesize, master;
243 231
244 dma_data = &omap_mcbsp_dai_dma_params[cpu_dai->id][substream->stream]; 232 dma_data = &mcbsp->dma_data[substream->stream];
245
246 dma = omap_mcbsp_dma_ch_params(bus_id, substream->stream);
247 port = omap_mcbsp_dma_reg_params(bus_id, substream->stream);
248 233
249 switch (params_format(params)) { 234 switch (params_format(params)) {
250 case SNDRV_PCM_FORMAT_S16_LE: 235 case SNDRV_PCM_FORMAT_S16_LE:
@@ -258,20 +243,17 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
258 default: 243 default:
259 return -EINVAL; 244 return -EINVAL;
260 } 245 }
261 if (cpu_is_omap34xx() || cpu_is_omap44xx()) { 246 if (mcbsp->pdata->buffer_size) {
262 dma_data->set_threshold = omap_mcbsp_set_threshold; 247 dma_data->set_threshold = omap_mcbsp_set_threshold;
263 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ 248 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
264 if (omap_mcbsp_get_dma_op_mode(bus_id) == 249 if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
265 MCBSP_DMA_MODE_THRESHOLD) {
266 int period_words, max_thrsh; 250 int period_words, max_thrsh;
267 251
268 period_words = params_period_bytes(params) / (wlen / 8); 252 period_words = params_period_bytes(params) / (wlen / 8);
269 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 253 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
270 max_thrsh = omap_mcbsp_get_max_tx_threshold( 254 max_thrsh = mcbsp->max_tx_thres;
271 mcbsp_data->bus_id);
272 else 255 else
273 max_thrsh = omap_mcbsp_get_max_rx_threshold( 256 max_thrsh = mcbsp->max_rx_thres;
274 mcbsp_data->bus_id);
275 /* 257 /*
276 * If the period contains less or equal number of words, 258 * If the period contains less or equal number of words,
277 * we are using the original threshold mode setup: 259 * we are using the original threshold mode setup:
@@ -304,15 +286,12 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
304 } 286 }
305 } 287 }
306 288
307 dma_data->name = substream->stream ? "Audio Capture" : "Audio Playback";
308 dma_data->dma_req = dma;
309 dma_data->port_addr = port;
310 dma_data->sync_mode = sync_mode; 289 dma_data->sync_mode = sync_mode;
311 dma_data->packet_size = pkt_size; 290 dma_data->packet_size = pkt_size;
312 291
313 snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); 292 snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
314 293
315 if (mcbsp_data->configured) { 294 if (mcbsp->configured) {
316 /* McBSP already configured by another stream */ 295 /* McBSP already configured by another stream */
317 return 0; 296 return 0;
318 } 297 }
@@ -321,7 +300,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
321 regs->xcr2 &= ~(RPHASE | XFRLEN2(0x7f) | XWDLEN2(7)); 300 regs->xcr2 &= ~(RPHASE | XFRLEN2(0x7f) | XWDLEN2(7));
322 regs->rcr1 &= ~(RFRLEN1(0x7f) | RWDLEN1(7)); 301 regs->rcr1 &= ~(RFRLEN1(0x7f) | RWDLEN1(7));
323 regs->xcr1 &= ~(XFRLEN1(0x7f) | XWDLEN1(7)); 302 regs->xcr1 &= ~(XFRLEN1(0x7f) | XWDLEN1(7));
324 format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK; 303 format = mcbsp->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
325 wpf = channels = params_channels(params); 304 wpf = channels = params_channels(params);
326 if (channels == 2 && (format == SND_SOC_DAIFMT_I2S || 305 if (channels == 2 && (format == SND_SOC_DAIFMT_I2S ||
327 format == SND_SOC_DAIFMT_LEFT_J)) { 306 format == SND_SOC_DAIFMT_LEFT_J)) {
@@ -359,10 +338,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
359 338
360 /* In McBSP master modes, FRAME (i.e. sample rate) is generated 339 /* In McBSP master modes, FRAME (i.e. sample rate) is generated
361 * by _counting_ BCLKs. Calculate frame size in BCLKs */ 340 * by _counting_ BCLKs. Calculate frame size in BCLKs */
362 master = mcbsp_data->fmt & SND_SOC_DAIFMT_MASTER_MASK; 341 master = mcbsp->fmt & SND_SOC_DAIFMT_MASTER_MASK;
363 if (master == SND_SOC_DAIFMT_CBS_CFS) { 342 if (master == SND_SOC_DAIFMT_CBS_CFS) {
364 div = mcbsp_data->clk_div ? mcbsp_data->clk_div : 1; 343 div = mcbsp->clk_div ? mcbsp->clk_div : 1;
365 framesize = (mcbsp_data->in_freq / div) / params_rate(params); 344 framesize = (mcbsp->in_freq / div) / params_rate(params);
366 345
367 if (framesize < wlen * channels) { 346 if (framesize < wlen * channels) {
368 printk(KERN_ERR "%s: not enough bandwidth for desired rate and " 347 printk(KERN_ERR "%s: not enough bandwidth for desired rate and "
@@ -388,9 +367,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
388 break; 367 break;
389 } 368 }
390 369
391 omap_mcbsp_config(bus_id, &mcbsp_data->regs); 370 omap_mcbsp_config(mcbsp, &mcbsp->cfg_regs);
392 mcbsp_data->wlen = wlen; 371 mcbsp->wlen = wlen;
393 mcbsp_data->configured = 1; 372 mcbsp->configured = 1;
394 373
395 return 0; 374 return 0;
396} 375}
@@ -402,14 +381,14 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
402static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, 381static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
403 unsigned int fmt) 382 unsigned int fmt)
404{ 383{
405 struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); 384 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
406 struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; 385 struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
407 bool inv_fs = false; 386 bool inv_fs = false;
408 387
409 if (mcbsp_data->configured) 388 if (mcbsp->configured)
410 return 0; 389 return 0;
411 390
412 mcbsp_data->fmt = fmt; 391 mcbsp->fmt = fmt;
413 memset(regs, 0, sizeof(*regs)); 392 memset(regs, 0, sizeof(*regs));
414 /* Generic McBSP register settings */ 393 /* Generic McBSP register settings */
415 regs->spcr2 |= XINTM(3) | FREE; 394 regs->spcr2 |= XINTM(3) | FREE;
@@ -504,13 +483,13 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
504static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai, 483static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
505 int div_id, int div) 484 int div_id, int div)
506{ 485{
507 struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); 486 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
508 struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; 487 struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
509 488
510 if (div_id != OMAP_MCBSP_CLKGDV) 489 if (div_id != OMAP_MCBSP_CLKGDV)
511 return -ENODEV; 490 return -ENODEV;
512 491
513 mcbsp_data->clk_div = div; 492 mcbsp->clk_div = div;
514 regs->srgr1 &= ~CLKGDV(0xff); 493 regs->srgr1 &= ~CLKGDV(0xff);
515 regs->srgr1 |= CLKGDV(div - 1); 494 regs->srgr1 |= CLKGDV(div - 1);
516 495
@@ -521,28 +500,32 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
521 int clk_id, unsigned int freq, 500 int clk_id, unsigned int freq,
522 int dir) 501 int dir)
523{ 502{
524 struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); 503 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
525 struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; 504 struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
526 int err = 0; 505 int err = 0;
527 506
528 if (mcbsp_data->active) { 507 if (mcbsp->active) {
529 if (freq == mcbsp_data->in_freq) 508 if (freq == mcbsp->in_freq)
530 return 0; 509 return 0;
531 else 510 else
532 return -EBUSY; 511 return -EBUSY;
533 } 512 }
534 513
535 /* The McBSP signal muxing functions are only available on McBSP1 */ 514 if (clk_id == OMAP_MCBSP_SYSCLK_CLK ||
536 if (clk_id == OMAP_MCBSP_CLKR_SRC_CLKR || 515 clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK ||
537 clk_id == OMAP_MCBSP_CLKR_SRC_CLKX || 516 clk_id == OMAP_MCBSP_SYSCLK_CLKS_EXT ||
538 clk_id == OMAP_MCBSP_FSR_SRC_FSR || 517 clk_id == OMAP_MCBSP_SYSCLK_CLKX_EXT ||
539 clk_id == OMAP_MCBSP_FSR_SRC_FSX) 518 clk_id == OMAP_MCBSP_SYSCLK_CLKR_EXT) {
540 if (cpu_class_is_omap1() || mcbsp_data->bus_id != 0) 519 mcbsp->in_freq = freq;
541 return -EINVAL; 520 regs->srgr2 &= ~CLKSM;
542 521 regs->pcr0 &= ~SCLKME;
543 mcbsp_data->in_freq = freq; 522 } else if (cpu_class_is_omap1()) {
544 regs->srgr2 &= ~CLKSM; 523 /*
545 regs->pcr0 &= ~SCLKME; 524 * McBSP CLKR/FSR signal muxing functions are only available on
525 * OMAP2 or newer versions
526 */
527 return -EINVAL;
528 }
546 529
547 switch (clk_id) { 530 switch (clk_id) {
548 case OMAP_MCBSP_SYSCLK_CLK: 531 case OMAP_MCBSP_SYSCLK_CLK:
@@ -553,7 +536,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
553 err = -EINVAL; 536 err = -EINVAL;
554 break; 537 break;
555 } 538 }
556 err = omap2_mcbsp_set_clks_src(mcbsp_data->bus_id, 539 err = omap2_mcbsp_set_clks_src(mcbsp,
557 MCBSP_CLKS_PRCM_SRC); 540 MCBSP_CLKS_PRCM_SRC);
558 break; 541 break;
559 case OMAP_MCBSP_SYSCLK_CLKS_EXT: 542 case OMAP_MCBSP_SYSCLK_CLKS_EXT:
@@ -561,7 +544,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
561 err = 0; 544 err = 0;
562 break; 545 break;
563 } 546 }
564 err = omap2_mcbsp_set_clks_src(mcbsp_data->bus_id, 547 err = omap2_mcbsp_set_clks_src(mcbsp,
565 MCBSP_CLKS_PAD_SRC); 548 MCBSP_CLKS_PAD_SRC);
566 break; 549 break;
567 550
@@ -573,24 +556,16 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
573 556
574 557
575 case OMAP_MCBSP_CLKR_SRC_CLKR: 558 case OMAP_MCBSP_CLKR_SRC_CLKR:
576 if (cpu_class_is_omap1()) 559 err = omap_mcbsp_6pin_src_mux(mcbsp, CLKR_SRC_CLKR);
577 break;
578 omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKR);
579 break; 560 break;
580 case OMAP_MCBSP_CLKR_SRC_CLKX: 561 case OMAP_MCBSP_CLKR_SRC_CLKX:
581 if (cpu_class_is_omap1()) 562 err = omap_mcbsp_6pin_src_mux(mcbsp, CLKR_SRC_CLKX);
582 break;
583 omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKX);
584 break; 563 break;
585 case OMAP_MCBSP_FSR_SRC_FSR: 564 case OMAP_MCBSP_FSR_SRC_FSR:
586 if (cpu_class_is_omap1()) 565 err = omap_mcbsp_6pin_src_mux(mcbsp, FSR_SRC_FSR);
587 break;
588 omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSR);
589 break; 566 break;
590 case OMAP_MCBSP_FSR_SRC_FSX: 567 case OMAP_MCBSP_FSR_SRC_FSX:
591 if (cpu_class_is_omap1()) 568 err = omap_mcbsp_6pin_src_mux(mcbsp, FSR_SRC_FSX);
592 break;
593 omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSX);
594 break; 569 break;
595 default: 570 default:
596 err = -ENODEV; 571 err = -ENODEV;
@@ -610,15 +585,27 @@ static const struct snd_soc_dai_ops mcbsp_dai_ops = {
610 .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, 585 .set_sysclk = omap_mcbsp_dai_set_dai_sysclk,
611}; 586};
612 587
613static int mcbsp_dai_probe(struct snd_soc_dai *dai) 588static int omap_mcbsp_probe(struct snd_soc_dai *dai)
614{ 589{
615 mcbsp_data[dai->id].bus_id = dai->id; 590 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai);
616 snd_soc_dai_set_drvdata(dai, &mcbsp_data[dai->id].bus_id); 591
592 pm_runtime_enable(mcbsp->dev);
593
594 return 0;
595}
596
597static int omap_mcbsp_remove(struct snd_soc_dai *dai)
598{
599 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai);
600
601 pm_runtime_disable(mcbsp->dev);
602
617 return 0; 603 return 0;
618} 604}
619 605
620static struct snd_soc_dai_driver omap_mcbsp_dai = { 606static struct snd_soc_dai_driver omap_mcbsp_dai = {
621 .probe = mcbsp_dai_probe, 607 .probe = omap_mcbsp_probe,
608 .remove = omap_mcbsp_remove,
622 .playback = { 609 .playback = {
623 .channels_min = 1, 610 .channels_min = 1,
624 .channels_max = 16, 611 .channels_max = 16,
@@ -649,11 +636,13 @@ static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
649 return 0; 636 return 0;
650} 637}
651 638
652#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(id, channel) \ 639#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(channel) \
653static int \ 640static int \
654omap_mcbsp##id##_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \ 641omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \
655 struct snd_ctl_elem_value *uc) \ 642 struct snd_ctl_elem_value *uc) \
656{ \ 643{ \
644 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
645 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
657 struct soc_mixer_control *mc = \ 646 struct soc_mixer_control *mc = \
658 (struct soc_mixer_control *)kc->private_value; \ 647 (struct soc_mixer_control *)kc->private_value; \
659 int max = mc->max; \ 648 int max = mc->max; \
@@ -664,46 +653,44 @@ omap_mcbsp##id##_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \
664 return -EINVAL; \ 653 return -EINVAL; \
665 \ 654 \
666 /* OMAP McBSP implementation uses index values 0..4 */ \ 655 /* OMAP McBSP implementation uses index values 0..4 */ \
667 return omap_st_set_chgain((id)-1, channel, val); \ 656 return omap_st_set_chgain(mcbsp, channel, val); \
668} 657}
669 658
670#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(id, channel) \ 659#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(channel) \
671static int \ 660static int \
672omap_mcbsp##id##_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \ 661omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \
673 struct snd_ctl_elem_value *uc) \ 662 struct snd_ctl_elem_value *uc) \
674{ \ 663{ \
664 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
665 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
675 s16 chgain; \ 666 s16 chgain; \
676 \ 667 \
677 if (omap_st_get_chgain((id)-1, channel, &chgain)) \ 668 if (omap_st_get_chgain(mcbsp, channel, &chgain)) \
678 return -EAGAIN; \ 669 return -EAGAIN; \
679 \ 670 \
680 uc->value.integer.value[0] = chgain; \ 671 uc->value.integer.value[0] = chgain; \
681 return 0; \ 672 return 0; \
682} 673}
683 674
684OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 0) 675OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(0)
685OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 1) 676OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(1)
686OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 0) 677OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(0)
687OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 1) 678OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(1)
688OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 0)
689OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 1)
690OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 0)
691OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 1)
692 679
693static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol, 680static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
694 struct snd_ctl_elem_value *ucontrol) 681 struct snd_ctl_elem_value *ucontrol)
695{ 682{
696 struct soc_mixer_control *mc = 683 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
697 (struct soc_mixer_control *)kcontrol->private_value; 684 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
698 u8 value = ucontrol->value.integer.value[0]; 685 u8 value = ucontrol->value.integer.value[0];
699 686
700 if (value == omap_st_is_enabled(mc->reg)) 687 if (value == omap_st_is_enabled(mcbsp))
701 return 0; 688 return 0;
702 689
703 if (value) 690 if (value)
704 omap_st_enable(mc->reg); 691 omap_st_enable(mcbsp);
705 else 692 else
706 omap_st_disable(mc->reg); 693 omap_st_disable(mcbsp);
707 694
708 return 1; 695 return 1;
709} 696}
@@ -711,10 +698,10 @@ static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
711static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol, 698static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
712 struct snd_ctl_elem_value *ucontrol) 699 struct snd_ctl_elem_value *ucontrol)
713{ 700{
714 struct soc_mixer_control *mc = 701 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
715 (struct soc_mixer_control *)kcontrol->private_value; 702 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
716 703
717 ucontrol->value.integer.value[0] = omap_st_is_enabled(mc->reg); 704 ucontrol->value.integer.value[0] = omap_st_is_enabled(mcbsp);
718 return 0; 705 return 0;
719} 706}
720 707
@@ -723,12 +710,12 @@ static const struct snd_kcontrol_new omap_mcbsp2_st_controls[] = {
723 omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), 710 omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),
724 OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 0 Volume", 711 OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 0 Volume",
725 -32768, 32767, 712 -32768, 32767,
726 omap_mcbsp2_get_st_ch0_volume, 713 omap_mcbsp_get_st_ch0_volume,
727 omap_mcbsp2_set_st_ch0_volume), 714 omap_mcbsp_set_st_ch0_volume),
728 OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 1 Volume", 715 OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 1 Volume",
729 -32768, 32767, 716 -32768, 32767,
730 omap_mcbsp2_get_st_ch1_volume, 717 omap_mcbsp_get_st_ch1_volume,
731 omap_mcbsp2_set_st_ch1_volume), 718 omap_mcbsp_set_st_ch1_volume),
732}; 719};
733 720
734static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = { 721static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = {
@@ -736,25 +723,30 @@ static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = {
736 omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), 723 omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),
737 OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 0 Volume", 724 OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 0 Volume",
738 -32768, 32767, 725 -32768, 32767,
739 omap_mcbsp3_get_st_ch0_volume, 726 omap_mcbsp_get_st_ch0_volume,
740 omap_mcbsp3_set_st_ch0_volume), 727 omap_mcbsp_set_st_ch0_volume),
741 OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 1 Volume", 728 OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 1 Volume",
742 -32768, 32767, 729 -32768, 32767,
743 omap_mcbsp3_get_st_ch1_volume, 730 omap_mcbsp_get_st_ch1_volume,
744 omap_mcbsp3_set_st_ch1_volume), 731 omap_mcbsp_set_st_ch1_volume),
745}; 732};
746 733
747int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id) 734int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)
748{ 735{
749 if (!cpu_is_omap34xx()) 736 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
737 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
738
739 if (!mcbsp->st_data)
750 return -ENODEV; 740 return -ENODEV;
751 741
752 switch (mcbsp_id) { 742 switch (cpu_dai->id) {
753 case 1: /* McBSP 2 */ 743 case 2: /* McBSP 2 */
754 return snd_soc_add_controls(codec, omap_mcbsp2_st_controls, 744 return snd_soc_add_dai_controls(cpu_dai,
745 omap_mcbsp2_st_controls,
755 ARRAY_SIZE(omap_mcbsp2_st_controls)); 746 ARRAY_SIZE(omap_mcbsp2_st_controls));
756 case 2: /* McBSP 3 */ 747 case 3: /* McBSP 3 */
757 return snd_soc_add_controls(codec, omap_mcbsp3_st_controls, 748 return snd_soc_add_dai_controls(cpu_dai,
749 omap_mcbsp3_st_controls,
758 ARRAY_SIZE(omap_mcbsp3_st_controls)); 750 ARRAY_SIZE(omap_mcbsp3_st_controls));
759 default: 751 default:
760 break; 752 break;
@@ -766,18 +758,51 @@ EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
766 758
767static __devinit int asoc_mcbsp_probe(struct platform_device *pdev) 759static __devinit int asoc_mcbsp_probe(struct platform_device *pdev)
768{ 760{
769 return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai); 761 struct omap_mcbsp_platform_data *pdata = dev_get_platdata(&pdev->dev);
762 struct omap_mcbsp *mcbsp;
763 int ret;
764
765 if (!pdata) {
766 dev_err(&pdev->dev, "missing platform data.\n");
767 return -EINVAL;
768 }
769 mcbsp = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcbsp), GFP_KERNEL);
770 if (!mcbsp)
771 return -ENOMEM;
772
773 mcbsp->id = pdev->id;
774 mcbsp->pdata = pdata;
775 mcbsp->dev = &pdev->dev;
776 platform_set_drvdata(pdev, mcbsp);
777
778 ret = omap_mcbsp_init(pdev);
779 if (!ret)
780 return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai);
781
782 return ret;
770} 783}
771 784
772static int __devexit asoc_mcbsp_remove(struct platform_device *pdev) 785static int __devexit asoc_mcbsp_remove(struct platform_device *pdev)
773{ 786{
787 struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
788
774 snd_soc_unregister_dai(&pdev->dev); 789 snd_soc_unregister_dai(&pdev->dev);
790
791 if (mcbsp->pdata->ops && mcbsp->pdata->ops->free)
792 mcbsp->pdata->ops->free(mcbsp->id);
793
794 omap_mcbsp_sysfs_remove(mcbsp);
795
796 clk_put(mcbsp->fclk);
797
798 platform_set_drvdata(pdev, NULL);
799
775 return 0; 800 return 0;
776} 801}
777 802
778static struct platform_driver asoc_mcbsp_driver = { 803static struct platform_driver asoc_mcbsp_driver = {
779 .driver = { 804 .driver = {
780 .name = "omap-mcbsp-dai", 805 .name = "omap-mcbsp",
781 .owner = THIS_MODULE, 806 .owner = THIS_MODULE,
782 }, 807 },
783 808