aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/omap/Kconfig2
-rw-r--r--sound/soc/omap/Makefile2
-rw-r--r--sound/soc/omap/am3517evm.c2
-rw-r--r--sound/soc/omap/ams-delta.c2
-rw-r--r--sound/soc/omap/igep0020.c2
-rw-r--r--sound/soc/omap/mcbsp.c1040
-rw-r--r--sound/soc/omap/mcbsp.h346
-rw-r--r--sound/soc/omap/n810.c2
-rw-r--r--sound/soc/omap/omap-mcbsp.c321
-rw-r--r--sound/soc/omap/omap-mcbsp.h2
-rw-r--r--sound/soc/omap/omap-pcm.h2
-rw-r--r--sound/soc/omap/omap3beagle.c2
-rw-r--r--sound/soc/omap/omap3evm.c2
-rw-r--r--sound/soc/omap/omap3pandora.c4
-rw-r--r--sound/soc/omap/osk5912.c2
-rw-r--r--sound/soc/omap/overo.c2
-rw-r--r--sound/soc/omap/rx51.c4
-rw-r--r--sound/soc/omap/sdp3430.c4
-rw-r--r--sound/soc/omap/zoom2.c4
19 files changed, 1579 insertions, 168 deletions
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 47b23fea20c2..e00dd0b1139c 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -7,7 +7,6 @@ config SND_OMAP_SOC_DMIC
7 7
8config SND_OMAP_SOC_MCBSP 8config SND_OMAP_SOC_MCBSP
9 tristate 9 tristate
10 select OMAP_MCBSP
11 10
12config SND_OMAP_SOC_MCPDM 11config SND_OMAP_SOC_MCPDM
13 tristate 12 tristate
@@ -27,7 +26,6 @@ config SND_OMAP_SOC_N810
27config SND_OMAP_SOC_RX51 26config SND_OMAP_SOC_RX51
28 tristate "SoC Audio support for Nokia RX-51" 27 tristate "SoC Audio support for Nokia RX-51"
29 depends on SND_OMAP_SOC && MACH_NOKIA_RX51 28 depends on SND_OMAP_SOC && MACH_NOKIA_RX51
30 select OMAP_MCBSP
31 select SND_OMAP_SOC_MCBSP 29 select SND_OMAP_SOC_MCBSP
32 select SND_SOC_TLV320AIC3X 30 select SND_SOC_TLV320AIC3X
33 select SND_SOC_TPA6130A2 31 select SND_SOC_TPA6130A2
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index 123ac18303e5..1d656bce01d4 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -1,7 +1,7 @@
1# OMAP Platform Support 1# OMAP Platform Support
2snd-soc-omap-objs := omap-pcm.o 2snd-soc-omap-objs := omap-pcm.o
3snd-soc-omap-dmic-objs := omap-dmic.o 3snd-soc-omap-dmic-objs := omap-dmic.o
4snd-soc-omap-mcbsp-objs := omap-mcbsp.o 4snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o
5snd-soc-omap-mcpdm-objs := omap-mcpdm.o 5snd-soc-omap-mcpdm-objs := omap-mcpdm.o
6snd-soc-omap-hdmi-objs := omap-hdmi.o 6snd-soc-omap-hdmi-objs := omap-hdmi.o
7 7
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
index add4866d7e67..009533ab8d18 100644
--- a/sound/soc/omap/am3517evm.c
+++ b/sound/soc/omap/am3517evm.c
@@ -95,7 +95,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
95static struct snd_soc_dai_link am3517evm_dai = { 95static struct snd_soc_dai_link am3517evm_dai = {
96 .name = "TLV320AIC23", 96 .name = "TLV320AIC23",
97 .stream_name = "AIC23", 97 .stream_name = "AIC23",
98 .cpu_dai_name ="omap-mcbsp-dai.0", 98 .cpu_dai_name = "omap-mcbsp.1",
99 .codec_dai_name = "tlv320aic23-hifi", 99 .codec_dai_name = "tlv320aic23-hifi",
100 .platform_name = "omap-pcm-audio", 100 .platform_name = "omap-pcm-audio",
101 .codec_name = "tlv320aic23-codec.2-001a", 101 .codec_name = "tlv320aic23-codec.2-001a",
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 78563bbbbf01..49fe63ce51f7 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -584,7 +584,7 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
584static struct snd_soc_dai_link ams_delta_dai_link = { 584static struct snd_soc_dai_link ams_delta_dai_link = {
585 .name = "CX20442", 585 .name = "CX20442",
586 .stream_name = "CX20442", 586 .stream_name = "CX20442",
587 .cpu_dai_name ="omap-mcbsp-dai.0", 587 .cpu_dai_name = "omap-mcbsp.1",
588 .codec_dai_name = "cx20442-voice", 588 .codec_dai_name = "cx20442-voice",
589 .init = ams_delta_cx20442_init, 589 .init = ams_delta_cx20442_init,
590 .platform_name = "omap-pcm-audio", 590 .platform_name = "omap-pcm-audio",
diff --git a/sound/soc/omap/igep0020.c b/sound/soc/omap/igep0020.c
index ccae58a1339c..e8357819175b 100644
--- a/sound/soc/omap/igep0020.c
+++ b/sound/soc/omap/igep0020.c
@@ -60,7 +60,7 @@ static struct snd_soc_ops igep2_ops = {
60static struct snd_soc_dai_link igep2_dai = { 60static struct snd_soc_dai_link igep2_dai = {
61 .name = "TWL4030", 61 .name = "TWL4030",
62 .stream_name = "TWL4030", 62 .stream_name = "TWL4030",
63 .cpu_dai_name = "omap-mcbsp-dai.1", 63 .cpu_dai_name = "omap-mcbsp.2",
64 .codec_dai_name = "twl4030-hifi", 64 .codec_dai_name = "twl4030-hifi",
65 .platform_name = "omap-pcm-audio", 65 .platform_name = "omap-pcm-audio",
66 .codec_name = "twl4030-codec", 66 .codec_name = "twl4030-codec",
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
new file mode 100644
index 000000000000..e5f44440d1b9
--- /dev/null
+++ b/sound/soc/omap/mcbsp.c
@@ -0,0 +1,1040 @@
1/*
2 * sound/soc/omap/mcbsp.c
3 *
4 * Copyright (C) 2004 Nokia Corporation
5 * Author: Samuel Ortiz <samuel.ortiz@nokia.com>
6 *
7 * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
8 * Peter Ujfalusi <peter.ujfalusi@ti.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * Multichannel mode not supported.
15 */
16
17#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/device.h>
20#include <linux/platform_device.h>
21#include <linux/interrupt.h>
22#include <linux/err.h>
23#include <linux/clk.h>
24#include <linux/delay.h>
25#include <linux/io.h>
26#include <linux/slab.h>
27
28#include <plat/mcbsp.h>
29
30#include "mcbsp.h"
31
32static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
33{
34 void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
35
36 if (mcbsp->pdata->reg_size == 2) {
37 ((u16 *)mcbsp->reg_cache)[reg] = (u16)val;
38 __raw_writew((u16)val, addr);
39 } else {
40 ((u32 *)mcbsp->reg_cache)[reg] = val;
41 __raw_writel(val, addr);
42 }
43}
44
45static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
46{
47 void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
48
49 if (mcbsp->pdata->reg_size == 2) {
50 return !from_cache ? __raw_readw(addr) :
51 ((u16 *)mcbsp->reg_cache)[reg];
52 } else {
53 return !from_cache ? __raw_readl(addr) :
54 ((u32 *)mcbsp->reg_cache)[reg];
55 }
56}
57
58static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
59{
60 __raw_writel(val, mcbsp->st_data->io_base_st + reg);
61}
62
63static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
64{
65 return __raw_readl(mcbsp->st_data->io_base_st + reg);
66}
67
68#define MCBSP_READ(mcbsp, reg) \
69 omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0)
70#define MCBSP_WRITE(mcbsp, reg, val) \
71 omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val)
72#define MCBSP_READ_CACHE(mcbsp, reg) \
73 omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1)
74
75#define MCBSP_ST_READ(mcbsp, reg) \
76 omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
77#define MCBSP_ST_WRITE(mcbsp, reg, val) \
78 omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val)
79
80static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp)
81{
82 dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id);
83 dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n",
84 MCBSP_READ(mcbsp, DRR2));
85 dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n",
86 MCBSP_READ(mcbsp, DRR1));
87 dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n",
88 MCBSP_READ(mcbsp, DXR2));
89 dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n",
90 MCBSP_READ(mcbsp, DXR1));
91 dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n",
92 MCBSP_READ(mcbsp, SPCR2));
93 dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n",
94 MCBSP_READ(mcbsp, SPCR1));
95 dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n",
96 MCBSP_READ(mcbsp, RCR2));
97 dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n",
98 MCBSP_READ(mcbsp, RCR1));
99 dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n",
100 MCBSP_READ(mcbsp, XCR2));
101 dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n",
102 MCBSP_READ(mcbsp, XCR1));
103 dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n",
104 MCBSP_READ(mcbsp, SRGR2));
105 dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n",
106 MCBSP_READ(mcbsp, SRGR1));
107 dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n",
108 MCBSP_READ(mcbsp, PCR0));
109 dev_dbg(mcbsp->dev, "***********************\n");
110}
111
112static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
113{
114 struct omap_mcbsp *mcbsp_tx = dev_id;
115 u16 irqst_spcr2;
116
117 irqst_spcr2 = MCBSP_READ(mcbsp_tx, SPCR2);
118 dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
119
120 if (irqst_spcr2 & XSYNC_ERR) {
121 dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n",
122 irqst_spcr2);
123 /* Writing zero to XSYNC_ERR clears the IRQ */
124 MCBSP_WRITE(mcbsp_tx, SPCR2, MCBSP_READ_CACHE(mcbsp_tx, SPCR2));
125 }
126
127 return IRQ_HANDLED;
128}
129
130static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
131{
132 struct omap_mcbsp *mcbsp_rx = dev_id;
133 u16 irqst_spcr1;
134
135 irqst_spcr1 = MCBSP_READ(mcbsp_rx, SPCR1);
136 dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
137
138 if (irqst_spcr1 & RSYNC_ERR) {
139 dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n",
140 irqst_spcr1);
141 /* Writing zero to RSYNC_ERR clears the IRQ */
142 MCBSP_WRITE(mcbsp_rx, SPCR1, MCBSP_READ_CACHE(mcbsp_rx, SPCR1));
143 }
144
145 return IRQ_HANDLED;
146}
147
148/*
149 * omap_mcbsp_config simply write a config to the
150 * appropriate McBSP.
151 * You either call this function or set the McBSP registers
152 * by yourself before calling omap_mcbsp_start().
153 */
154void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
155 const struct omap_mcbsp_reg_cfg *config)
156{
157 dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n",
158 mcbsp->id, mcbsp->phys_base);
159
160 /* We write the given config */
161 MCBSP_WRITE(mcbsp, SPCR2, config->spcr2);
162 MCBSP_WRITE(mcbsp, SPCR1, config->spcr1);
163 MCBSP_WRITE(mcbsp, RCR2, config->rcr2);
164 MCBSP_WRITE(mcbsp, RCR1, config->rcr1);
165 MCBSP_WRITE(mcbsp, XCR2, config->xcr2);
166 MCBSP_WRITE(mcbsp, XCR1, config->xcr1);
167 MCBSP_WRITE(mcbsp, SRGR2, config->srgr2);
168 MCBSP_WRITE(mcbsp, SRGR1, config->srgr1);
169 MCBSP_WRITE(mcbsp, MCR2, config->mcr2);
170 MCBSP_WRITE(mcbsp, MCR1, config->mcr1);
171 MCBSP_WRITE(mcbsp, PCR0, config->pcr0);
172 if (mcbsp->pdata->has_ccr) {
173 MCBSP_WRITE(mcbsp, XCCR, config->xccr);
174 MCBSP_WRITE(mcbsp, RCCR, config->rccr);
175 }
176 /* Enable wakeup behavior */
177 if (mcbsp->pdata->has_wakeup)
178 MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
179}
180
181/**
182 * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register
183 * @id - mcbsp id
184 * @stream - indicates the direction of data flow (rx or tx)
185 *
186 * Returns the address of mcbsp data transmit register or data receive register
187 * to be used by DMA for transferring/receiving data based on the value of
188 * @stream for the requested mcbsp given by @id
189 */
190static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp,
191 unsigned int stream)
192{
193 int data_reg;
194
195 if (mcbsp->pdata->reg_size == 2) {
196 if (stream)
197 data_reg = OMAP_MCBSP_REG_DRR1;
198 else
199 data_reg = OMAP_MCBSP_REG_DXR1;
200 } else {
201 if (stream)
202 data_reg = OMAP_MCBSP_REG_DRR;
203 else
204 data_reg = OMAP_MCBSP_REG_DXR;
205 }
206
207 return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step;
208}
209
210static void omap_st_on(struct omap_mcbsp *mcbsp)
211{
212 unsigned int w;
213
214 if (mcbsp->pdata->enable_st_clock)
215 mcbsp->pdata->enable_st_clock(mcbsp->id, 1);
216
217 /* Enable McBSP Sidetone */
218 w = MCBSP_READ(mcbsp, SSELCR);
219 MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
220
221 /* Enable Sidetone from Sidetone Core */
222 w = MCBSP_ST_READ(mcbsp, SSELCR);
223 MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
224}
225
226static void omap_st_off(struct omap_mcbsp *mcbsp)
227{
228 unsigned int w;
229
230 w = MCBSP_ST_READ(mcbsp, SSELCR);
231 MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
232
233 w = MCBSP_READ(mcbsp, SSELCR);
234 MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
235
236 if (mcbsp->pdata->enable_st_clock)
237 mcbsp->pdata->enable_st_clock(mcbsp->id, 0);
238}
239
240static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
241{
242 u16 val, i;
243
244 val = MCBSP_ST_READ(mcbsp, SSELCR);
245
246 if (val & ST_COEFFWREN)
247 MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
248
249 MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN);
250
251 for (i = 0; i < 128; i++)
252 MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]);
253
254 i = 0;
255
256 val = MCBSP_ST_READ(mcbsp, SSELCR);
257 while (!(val & ST_COEFFWRDONE) && (++i < 1000))
258 val = MCBSP_ST_READ(mcbsp, SSELCR);
259
260 MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
261
262 if (i == 1000)
263 dev_err(mcbsp->dev, "McBSP FIR load error!\n");
264}
265
266static void omap_st_chgain(struct omap_mcbsp *mcbsp)
267{
268 u16 w;
269 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
270
271 w = MCBSP_ST_READ(mcbsp, SSELCR);
272
273 MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) | \
274 ST_CH1GAIN(st_data->ch1gain));
275}
276
277int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain)
278{
279 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
280 int ret = 0;
281
282 if (!st_data)
283 return -ENOENT;
284
285 spin_lock_irq(&mcbsp->lock);
286 if (channel == 0)
287 st_data->ch0gain = chgain;
288 else if (channel == 1)
289 st_data->ch1gain = chgain;
290 else
291 ret = -EINVAL;
292
293 if (st_data->enabled)
294 omap_st_chgain(mcbsp);
295 spin_unlock_irq(&mcbsp->lock);
296
297 return ret;
298}
299
300int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain)
301{
302 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
303 int ret = 0;
304
305 if (!st_data)
306 return -ENOENT;
307
308 spin_lock_irq(&mcbsp->lock);
309 if (channel == 0)
310 *chgain = st_data->ch0gain;
311 else if (channel == 1)
312 *chgain = st_data->ch1gain;
313 else
314 ret = -EINVAL;
315 spin_unlock_irq(&mcbsp->lock);
316
317 return ret;
318}
319
320static int omap_st_start(struct omap_mcbsp *mcbsp)
321{
322 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
323
324 if (st_data->enabled && !st_data->running) {
325 omap_st_fir_write(mcbsp, st_data->taps);
326 omap_st_chgain(mcbsp);
327
328 if (!mcbsp->free) {
329 omap_st_on(mcbsp);
330 st_data->running = 1;
331 }
332 }
333
334 return 0;
335}
336
337int omap_st_enable(struct omap_mcbsp *mcbsp)
338{
339 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
340
341 if (!st_data)
342 return -ENODEV;
343
344 spin_lock_irq(&mcbsp->lock);
345 st_data->enabled = 1;
346 omap_st_start(mcbsp);
347 spin_unlock_irq(&mcbsp->lock);
348
349 return 0;
350}
351
352static int omap_st_stop(struct omap_mcbsp *mcbsp)
353{
354 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
355
356 if (st_data->running) {
357 if (!mcbsp->free) {
358 omap_st_off(mcbsp);
359 st_data->running = 0;
360 }
361 }
362
363 return 0;
364}
365
366int omap_st_disable(struct omap_mcbsp *mcbsp)
367{
368 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
369 int ret = 0;
370
371 if (!st_data)
372 return -ENODEV;
373
374 spin_lock_irq(&mcbsp->lock);
375 omap_st_stop(mcbsp);
376 st_data->enabled = 0;
377 spin_unlock_irq(&mcbsp->lock);
378
379 return ret;
380}
381
382int omap_st_is_enabled(struct omap_mcbsp *mcbsp)
383{
384 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
385
386 if (!st_data)
387 return -ENODEV;
388
389 return st_data->enabled;
390}
391
392/*
393 * omap_mcbsp_set_rx_threshold configures the transmit threshold in words.
394 * The threshold parameter is 1 based, and it is converted (threshold - 1)
395 * for the THRSH2 register.
396 */
397void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
398{
399 if (mcbsp->pdata->buffer_size == 0)
400 return;
401
402 if (threshold && threshold <= mcbsp->max_tx_thres)
403 MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
404}
405
406/*
407 * omap_mcbsp_set_rx_threshold configures the receive threshold in words.
408 * The threshold parameter is 1 based, and it is converted (threshold - 1)
409 * for the THRSH1 register.
410 */
411void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
412{
413 if (mcbsp->pdata->buffer_size == 0)
414 return;
415
416 if (threshold && threshold <= mcbsp->max_rx_thres)
417 MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
418}
419
420/*
421 * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
422 */
423u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp)
424{
425 u16 buffstat;
426
427 if (mcbsp->pdata->buffer_size == 0)
428 return 0;
429
430 /* Returns the number of free locations in the buffer */
431 buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
432
433 /* Number of slots are different in McBSP ports */
434 return mcbsp->pdata->buffer_size - buffstat;
435}
436
437/*
438 * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO
439 * to reach the threshold value (when the DMA will be triggered to read it)
440 */
441u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp)
442{
443 u16 buffstat, threshold;
444
445 if (mcbsp->pdata->buffer_size == 0)
446 return 0;
447
448 /* Returns the number of used locations in the buffer */
449 buffstat = MCBSP_READ(mcbsp, RBUFFSTAT);
450 /* RX threshold */
451 threshold = MCBSP_READ(mcbsp, THRSH1);
452
453 /* Return the number of location till we reach the threshold limit */
454 if (threshold <= buffstat)
455 return 0;
456 else
457 return threshold - buffstat;
458}
459
460int omap_mcbsp_request(struct omap_mcbsp *mcbsp)
461{
462 void *reg_cache;
463 int err;
464
465 reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL);
466 if (!reg_cache) {
467 return -ENOMEM;
468 }
469
470 spin_lock(&mcbsp->lock);
471 if (!mcbsp->free) {
472 dev_err(mcbsp->dev, "McBSP%d is currently in use\n",
473 mcbsp->id);
474 err = -EBUSY;
475 goto err_kfree;
476 }
477
478 mcbsp->free = false;
479 mcbsp->reg_cache = reg_cache;
480 spin_unlock(&mcbsp->lock);
481
482 if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request)
483 mcbsp->pdata->ops->request(mcbsp->id - 1);
484
485 /*
486 * Make sure that transmitter, receiver and sample-rate generator are
487 * not running before activating IRQs.
488 */
489 MCBSP_WRITE(mcbsp, SPCR1, 0);
490 MCBSP_WRITE(mcbsp, SPCR2, 0);
491
492 err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler,
493 0, "McBSP", (void *)mcbsp);
494 if (err != 0) {
495 dev_err(mcbsp->dev, "Unable to request TX IRQ %d "
496 "for McBSP%d\n", mcbsp->tx_irq,
497 mcbsp->id);
498 goto err_clk_disable;
499 }
500
501 if (mcbsp->rx_irq) {
502 err = request_irq(mcbsp->rx_irq,
503 omap_mcbsp_rx_irq_handler,
504 0, "McBSP", (void *)mcbsp);
505 if (err != 0) {
506 dev_err(mcbsp->dev, "Unable to request RX IRQ %d "
507 "for McBSP%d\n", mcbsp->rx_irq,
508 mcbsp->id);
509 goto err_free_irq;
510 }
511 }
512
513 return 0;
514err_free_irq:
515 free_irq(mcbsp->tx_irq, (void *)mcbsp);
516err_clk_disable:
517 if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
518 mcbsp->pdata->ops->free(mcbsp->id - 1);
519
520 /* Disable wakeup behavior */
521 if (mcbsp->pdata->has_wakeup)
522 MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
523
524 spin_lock(&mcbsp->lock);
525 mcbsp->free = true;
526 mcbsp->reg_cache = NULL;
527err_kfree:
528 spin_unlock(&mcbsp->lock);
529 kfree(reg_cache);
530
531 return err;
532}
533
534void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
535{
536 void *reg_cache;
537
538 if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
539 mcbsp->pdata->ops->free(mcbsp->id - 1);
540
541 /* Disable wakeup behavior */
542 if (mcbsp->pdata->has_wakeup)
543 MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
544
545 if (mcbsp->rx_irq)
546 free_irq(mcbsp->rx_irq, (void *)mcbsp);
547 free_irq(mcbsp->tx_irq, (void *)mcbsp);
548
549 reg_cache = mcbsp->reg_cache;
550
551 /*
552 * Select CLKS source from internal source unconditionally before
553 * marking the McBSP port as free.
554 * If the external clock source via MCBSP_CLKS pin has been selected the
555 * system will refuse to enter idle if the CLKS pin source is not reset
556 * back to internal source.
557 */
558 if (!cpu_class_is_omap1())
559 omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC);
560
561 spin_lock(&mcbsp->lock);
562 if (mcbsp->free)
563 dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id);
564 else
565 mcbsp->free = true;
566 mcbsp->reg_cache = NULL;
567 spin_unlock(&mcbsp->lock);
568
569 if (reg_cache)
570 kfree(reg_cache);
571}
572
573/*
574 * Here we start the McBSP, by enabling transmitter, receiver or both.
575 * If no transmitter or receiver is active prior calling, then sample-rate
576 * generator and frame sync are started.
577 */
578void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int tx, int rx)
579{
580 int enable_srg = 0;
581 u16 w;
582
583 if (mcbsp->st_data)
584 omap_st_start(mcbsp);
585
586 /* Only enable SRG, if McBSP is master */
587 w = MCBSP_READ_CACHE(mcbsp, PCR0);
588 if (w & (FSXM | FSRM | CLKXM | CLKRM))
589 enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
590 MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
591
592 if (enable_srg) {
593 /* Start the sample generator */
594 w = MCBSP_READ_CACHE(mcbsp, SPCR2);
595 MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6));
596 }
597
598 /* Enable transmitter and receiver */
599 tx &= 1;
600 w = MCBSP_READ_CACHE(mcbsp, SPCR2);
601 MCBSP_WRITE(mcbsp, SPCR2, w | tx);
602
603 rx &= 1;
604 w = MCBSP_READ_CACHE(mcbsp, SPCR1);
605 MCBSP_WRITE(mcbsp, SPCR1, w | rx);
606
607 /*
608 * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec
609 * REVISIT: 100us may give enough time for two CLKSRG, however
610 * due to some unknown PM related, clock gating etc. reason it
611 * is now at 500us.
612 */
613 udelay(500);
614
615 if (enable_srg) {
616 /* Start frame sync */
617 w = MCBSP_READ_CACHE(mcbsp, SPCR2);
618 MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
619 }
620
621 if (mcbsp->pdata->has_ccr) {
622 /* Release the transmitter and receiver */
623 w = MCBSP_READ_CACHE(mcbsp, XCCR);
624 w &= ~(tx ? XDISABLE : 0);
625 MCBSP_WRITE(mcbsp, XCCR, w);
626 w = MCBSP_READ_CACHE(mcbsp, RCCR);
627 w &= ~(rx ? RDISABLE : 0);
628 MCBSP_WRITE(mcbsp, RCCR, w);
629 }
630
631 /* Dump McBSP Regs */
632 omap_mcbsp_dump_reg(mcbsp);
633}
634
635void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx)
636{
637 int idle;
638 u16 w;
639
640 /* Reset transmitter */
641 tx &= 1;
642 if (mcbsp->pdata->has_ccr) {
643 w = MCBSP_READ_CACHE(mcbsp, XCCR);
644 w |= (tx ? XDISABLE : 0);
645 MCBSP_WRITE(mcbsp, XCCR, w);
646 }
647 w = MCBSP_READ_CACHE(mcbsp, SPCR2);
648 MCBSP_WRITE(mcbsp, SPCR2, w & ~tx);
649
650 /* Reset receiver */
651 rx &= 1;
652 if (mcbsp->pdata->has_ccr) {
653 w = MCBSP_READ_CACHE(mcbsp, RCCR);
654 w |= (rx ? RDISABLE : 0);
655 MCBSP_WRITE(mcbsp, RCCR, w);
656 }
657 w = MCBSP_READ_CACHE(mcbsp, SPCR1);
658 MCBSP_WRITE(mcbsp, SPCR1, w & ~rx);
659
660 idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
661 MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
662
663 if (idle) {
664 /* Reset the sample rate generator */
665 w = MCBSP_READ_CACHE(mcbsp, SPCR2);
666 MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6));
667 }
668
669 if (mcbsp->st_data)
670 omap_st_stop(mcbsp);
671}
672
673int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id)
674{
675 const char *src;
676
677 if (fck_src_id == MCBSP_CLKS_PAD_SRC)
678 src = "clks_ext";
679 else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
680 src = "clks_fclk";
681 else
682 return -EINVAL;
683
684 if (mcbsp->pdata->set_clk_src)
685 return mcbsp->pdata->set_clk_src(mcbsp->dev, mcbsp->fclk, src);
686 else
687 return -EINVAL;
688}
689
690int omap_mcbsp_6pin_src_mux(struct omap_mcbsp *mcbsp, u8 mux)
691{
692 const char *signal, *src;
693
694 if (mcbsp->pdata->mux_signal)
695 return -EINVAL;
696
697 switch (mux) {
698 case CLKR_SRC_CLKR:
699 signal = "clkr";
700 src = "clkr";
701 break;
702 case CLKR_SRC_CLKX:
703 signal = "clkr";
704 src = "clkx";
705 break;
706 case FSR_SRC_FSR:
707 signal = "fsr";
708 src = "fsr";
709 break;
710 case FSR_SRC_FSX:
711 signal = "fsr";
712 src = "fsx";
713 break;
714 default:
715 return -EINVAL;
716 }
717
718 return mcbsp->pdata->mux_signal(mcbsp->dev, signal, src);
719}
720
721#define max_thres(m) (mcbsp->pdata->buffer_size)
722#define valid_threshold(m, val) ((val) <= max_thres(m))
723#define THRESHOLD_PROP_BUILDER(prop) \
724static ssize_t prop##_show(struct device *dev, \
725 struct device_attribute *attr, char *buf) \
726{ \
727 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
728 \
729 return sprintf(buf, "%u\n", mcbsp->prop); \
730} \
731 \
732static ssize_t prop##_store(struct device *dev, \
733 struct device_attribute *attr, \
734 const char *buf, size_t size) \
735{ \
736 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
737 unsigned long val; \
738 int status; \
739 \
740 status = strict_strtoul(buf, 0, &val); \
741 if (status) \
742 return status; \
743 \
744 if (!valid_threshold(mcbsp, val)) \
745 return -EDOM; \
746 \
747 mcbsp->prop = val; \
748 return size; \
749} \
750 \
751static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store);
752
753THRESHOLD_PROP_BUILDER(max_tx_thres);
754THRESHOLD_PROP_BUILDER(max_rx_thres);
755
756static const char *dma_op_modes[] = {
757 "element", "threshold", "frame",
758};
759
760static ssize_t dma_op_mode_show(struct device *dev,
761 struct device_attribute *attr, char *buf)
762{
763 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
764 int dma_op_mode, i = 0;
765 ssize_t len = 0;
766 const char * const *s;
767
768 dma_op_mode = mcbsp->dma_op_mode;
769
770 for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) {
771 if (dma_op_mode == i)
772 len += sprintf(buf + len, "[%s] ", *s);
773 else
774 len += sprintf(buf + len, "%s ", *s);
775 }
776 len += sprintf(buf + len, "\n");
777
778 return len;
779}
780
781static ssize_t dma_op_mode_store(struct device *dev,
782 struct device_attribute *attr,
783 const char *buf, size_t size)
784{
785 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
786 const char * const *s;
787 int i = 0;
788
789 for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++)
790 if (sysfs_streq(buf, *s))
791 break;
792
793 if (i == ARRAY_SIZE(dma_op_modes))
794 return -EINVAL;
795
796 spin_lock_irq(&mcbsp->lock);
797 if (!mcbsp->free) {
798 size = -EBUSY;
799 goto unlock;
800 }
801 mcbsp->dma_op_mode = i;
802
803unlock:
804 spin_unlock_irq(&mcbsp->lock);
805
806 return size;
807}
808
809static DEVICE_ATTR(dma_op_mode, 0644, dma_op_mode_show, dma_op_mode_store);
810
811static const struct attribute *additional_attrs[] = {
812 &dev_attr_max_tx_thres.attr,
813 &dev_attr_max_rx_thres.attr,
814 &dev_attr_dma_op_mode.attr,
815 NULL,
816};
817
818static const struct attribute_group additional_attr_group = {
819 .attrs = (struct attribute **)additional_attrs,
820};
821
822static ssize_t st_taps_show(struct device *dev,
823 struct device_attribute *attr, char *buf)
824{
825 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
826 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
827 ssize_t status = 0;
828 int i;
829
830 spin_lock_irq(&mcbsp->lock);
831 for (i = 0; i < st_data->nr_taps; i++)
832 status += sprintf(&buf[status], (i ? ", %d" : "%d"),
833 st_data->taps[i]);
834 if (i)
835 status += sprintf(&buf[status], "\n");
836 spin_unlock_irq(&mcbsp->lock);
837
838 return status;
839}
840
841static ssize_t st_taps_store(struct device *dev,
842 struct device_attribute *attr,
843 const char *buf, size_t size)
844{
845 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
846 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
847 int val, tmp, status, i = 0;
848
849 spin_lock_irq(&mcbsp->lock);
850 memset(st_data->taps, 0, sizeof(st_data->taps));
851 st_data->nr_taps = 0;
852
853 do {
854 status = sscanf(buf, "%d%n", &val, &tmp);
855 if (status < 0 || status == 0) {
856 size = -EINVAL;
857 goto out;
858 }
859 if (val < -32768 || val > 32767) {
860 size = -EINVAL;
861 goto out;
862 }
863 st_data->taps[i++] = val;
864 buf += tmp;
865 if (*buf != ',')
866 break;
867 buf++;
868 } while (1);
869
870 st_data->nr_taps = i;
871
872out:
873 spin_unlock_irq(&mcbsp->lock);
874
875 return size;
876}
877
878static DEVICE_ATTR(st_taps, 0644, st_taps_show, st_taps_store);
879
880static const struct attribute *sidetone_attrs[] = {
881 &dev_attr_st_taps.attr,
882 NULL,
883};
884
885static const struct attribute_group sidetone_attr_group = {
886 .attrs = (struct attribute **)sidetone_attrs,
887};
888
889static int __devinit omap_st_add(struct omap_mcbsp *mcbsp,
890 struct resource *res)
891{
892 struct omap_mcbsp_st_data *st_data;
893 int err;
894
895 st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL);
896 if (!st_data)
897 return -ENOMEM;
898
899 st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start,
900 resource_size(res));
901 if (!st_data->io_base_st)
902 return -ENOMEM;
903
904 err = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
905 if (err)
906 return err;
907
908 mcbsp->st_data = st_data;
909 return 0;
910}
911
912/*
913 * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
914 * 730 has only 2 McBSP, and both of them are MPU peripherals.
915 */
916int __devinit omap_mcbsp_init(struct platform_device *pdev)
917{
918 struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
919 struct resource *res;
920 int ret = 0;
921
922 spin_lock_init(&mcbsp->lock);
923 mcbsp->free = true;
924
925 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
926 if (!res) {
927 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
928 if (!res) {
929 dev_err(mcbsp->dev, "invalid memory resource\n");
930 return -ENOMEM;
931 }
932 }
933 if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
934 dev_name(&pdev->dev))) {
935 dev_err(mcbsp->dev, "memory region already claimed\n");
936 return -ENODEV;
937 }
938
939 mcbsp->phys_base = res->start;
940 mcbsp->reg_cache_size = resource_size(res);
941 mcbsp->io_base = devm_ioremap(&pdev->dev, res->start,
942 resource_size(res));
943 if (!mcbsp->io_base)
944 return -ENOMEM;
945
946 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
947 if (!res)
948 mcbsp->phys_dma_base = mcbsp->phys_base;
949 else
950 mcbsp->phys_dma_base = res->start;
951
952 mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
953 mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
954
955 /* From OMAP4 there will be a single irq line */
956 if (mcbsp->tx_irq == -ENXIO) {
957 mcbsp->tx_irq = platform_get_irq(pdev, 0);
958 mcbsp->rx_irq = 0;
959 }
960
961 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
962 if (!res) {
963 dev_err(&pdev->dev, "invalid rx DMA channel\n");
964 return -ENODEV;
965 }
966 /* RX DMA request number, and port address configuration */
967 mcbsp->dma_data[1].name = "Audio Capture";
968 mcbsp->dma_data[1].dma_req = res->start;
969 mcbsp->dma_data[1].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
970
971 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
972 if (!res) {
973 dev_err(&pdev->dev, "invalid tx DMA channel\n");
974 return -ENODEV;
975 }
976 /* TX DMA request number, and port address configuration */
977 mcbsp->dma_data[0].name = "Audio Playback";
978 mcbsp->dma_data[0].dma_req = res->start;
979 mcbsp->dma_data[0].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 0);
980
981 mcbsp->fclk = clk_get(&pdev->dev, "fck");
982 if (IS_ERR(mcbsp->fclk)) {
983 ret = PTR_ERR(mcbsp->fclk);
984 dev_err(mcbsp->dev, "unable to get fck: %d\n", ret);
985 return ret;
986 }
987
988 mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
989 if (mcbsp->pdata->buffer_size) {
990 /*
991 * Initially configure the maximum thresholds to a safe value.
992 * The McBSP FIFO usage with these values should not go under
993 * 16 locations.
994 * If the whole FIFO without safety buffer is used, than there
995 * is a possibility that the DMA will be not able to push the
996 * new data on time, causing channel shifts in runtime.
997 */
998 mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
999 mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
1000
1001 ret = sysfs_create_group(&mcbsp->dev->kobj,
1002 &additional_attr_group);
1003 if (ret) {
1004 dev_err(mcbsp->dev,
1005 "Unable to create additional controls\n");
1006 goto err_thres;
1007 }
1008 } else {
1009 mcbsp->max_tx_thres = -EINVAL;
1010 mcbsp->max_rx_thres = -EINVAL;
1011 }
1012
1013 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
1014 if (res) {
1015 ret = omap_st_add(mcbsp, res);
1016 if (ret) {
1017 dev_err(mcbsp->dev,
1018 "Unable to create sidetone controls\n");
1019 goto err_st;
1020 }
1021 }
1022
1023 return 0;
1024
1025err_st:
1026 if (mcbsp->pdata->buffer_size)
1027 sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
1028err_thres:
1029 clk_put(mcbsp->fclk);
1030 return ret;
1031}
1032
1033void __devexit omap_mcbsp_sysfs_remove(struct omap_mcbsp *mcbsp)
1034{
1035 if (mcbsp->pdata->buffer_size)
1036 sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
1037
1038 if (mcbsp->st_data)
1039 sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
1040}
diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/mcbsp.h
new file mode 100644
index 000000000000..a944fcc9073c
--- /dev/null
+++ b/sound/soc/omap/mcbsp.h
@@ -0,0 +1,346 @@
1/*
2 * sound/soc/omap/mcbsp.h
3 *
4 * OMAP Multi-Channel Buffered Serial Port
5 *
6 * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
7 * Peter Ujfalusi <peter.ujfalusi@ti.com>
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 as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24#ifndef __ASOC_MCBSP_H
25#define __ASOC_MCBSP_H
26
27#include "omap-pcm.h"
28
29/* McBSP register numbers. Register address offset = num * reg_step */
30enum {
31 /* Common registers */
32 OMAP_MCBSP_REG_SPCR2 = 4,
33 OMAP_MCBSP_REG_SPCR1,
34 OMAP_MCBSP_REG_RCR2,
35 OMAP_MCBSP_REG_RCR1,
36 OMAP_MCBSP_REG_XCR2,
37 OMAP_MCBSP_REG_XCR1,
38 OMAP_MCBSP_REG_SRGR2,
39 OMAP_MCBSP_REG_SRGR1,
40 OMAP_MCBSP_REG_MCR2,
41 OMAP_MCBSP_REG_MCR1,
42 OMAP_MCBSP_REG_RCERA,
43 OMAP_MCBSP_REG_RCERB,
44 OMAP_MCBSP_REG_XCERA,
45 OMAP_MCBSP_REG_XCERB,
46 OMAP_MCBSP_REG_PCR0,
47 OMAP_MCBSP_REG_RCERC,
48 OMAP_MCBSP_REG_RCERD,
49 OMAP_MCBSP_REG_XCERC,
50 OMAP_MCBSP_REG_XCERD,
51 OMAP_MCBSP_REG_RCERE,
52 OMAP_MCBSP_REG_RCERF,
53 OMAP_MCBSP_REG_XCERE,
54 OMAP_MCBSP_REG_XCERF,
55 OMAP_MCBSP_REG_RCERG,
56 OMAP_MCBSP_REG_RCERH,
57 OMAP_MCBSP_REG_XCERG,
58 OMAP_MCBSP_REG_XCERH,
59
60 /* OMAP1-OMAP2420 registers */
61 OMAP_MCBSP_REG_DRR2 = 0,
62 OMAP_MCBSP_REG_DRR1,
63 OMAP_MCBSP_REG_DXR2,
64 OMAP_MCBSP_REG_DXR1,
65
66 /* OMAP2430 and onwards */
67 OMAP_MCBSP_REG_DRR = 0,
68 OMAP_MCBSP_REG_DXR = 2,
69 OMAP_MCBSP_REG_SYSCON = 35,
70 OMAP_MCBSP_REG_THRSH2,
71 OMAP_MCBSP_REG_THRSH1,
72 OMAP_MCBSP_REG_IRQST = 40,
73 OMAP_MCBSP_REG_IRQEN,
74 OMAP_MCBSP_REG_WAKEUPEN,
75 OMAP_MCBSP_REG_XCCR,
76 OMAP_MCBSP_REG_RCCR,
77 OMAP_MCBSP_REG_XBUFFSTAT,
78 OMAP_MCBSP_REG_RBUFFSTAT,
79 OMAP_MCBSP_REG_SSELCR,
80};
81
82/* OMAP3 sidetone control registers */
83#define OMAP_ST_REG_REV 0x00
84#define OMAP_ST_REG_SYSCONFIG 0x10
85#define OMAP_ST_REG_IRQSTATUS 0x18
86#define OMAP_ST_REG_IRQENABLE 0x1C
87#define OMAP_ST_REG_SGAINCR 0x24
88#define OMAP_ST_REG_SFIRCR 0x28
89#define OMAP_ST_REG_SSELCR 0x2C
90
91/************************** McBSP SPCR1 bit definitions ***********************/
92#define RRST BIT(0)
93#define RRDY BIT(1)
94#define RFULL BIT(2)
95#define RSYNC_ERR BIT(3)
96#define RINTM(value) (((value) & 0x3) << 4) /* bits 4:5 */
97#define ABIS BIT(6)
98#define DXENA BIT(7)
99#define CLKSTP(value) (((value) & 0x3) << 11) /* bits 11:12 */
100#define RJUST(value) (((value) & 0x3) << 13) /* bits 13:14 */
101#define ALB BIT(15)
102#define DLB BIT(15)
103
104/************************** McBSP SPCR2 bit definitions ***********************/
105#define XRST BIT(0)
106#define XRDY BIT(1)
107#define XEMPTY BIT(2)
108#define XSYNC_ERR BIT(3)
109#define XINTM(value) (((value) & 0x3) << 4) /* bits 4:5 */
110#define GRST BIT(6)
111#define FRST BIT(7)
112#define SOFT BIT(8)
113#define FREE BIT(9)
114
115/************************** McBSP PCR bit definitions *************************/
116#define CLKRP BIT(0)
117#define CLKXP BIT(1)
118#define FSRP BIT(2)
119#define FSXP BIT(3)
120#define DR_STAT BIT(4)
121#define DX_STAT BIT(5)
122#define CLKS_STAT BIT(6)
123#define SCLKME BIT(7)
124#define CLKRM BIT(8)
125#define CLKXM BIT(9)
126#define FSRM BIT(10)
127#define FSXM BIT(11)
128#define RIOEN BIT(12)
129#define XIOEN BIT(13)
130#define IDLE_EN BIT(14)
131
132/************************** McBSP RCR1 bit definitions ************************/
133#define RWDLEN1(value) (((value) & 0x7) << 5) /* Bits 5:7 */
134#define RFRLEN1(value) (((value) & 0x7f) << 8) /* Bits 8:14 */
135
136/************************** McBSP XCR1 bit definitions ************************/
137#define XWDLEN1(value) (((value) & 0x7) << 5) /* Bits 5:7 */
138#define XFRLEN1(value) (((value) & 0x7f) << 8) /* Bits 8:14 */
139
140/*************************** McBSP RCR2 bit definitions ***********************/
141#define RDATDLY(value) ((value) & 0x3) /* Bits 0:1 */
142#define RFIG BIT(2)
143#define RCOMPAND(value) (((value) & 0x3) << 3) /* Bits 3:4 */
144#define RWDLEN2(value) (((value) & 0x7) << 5) /* Bits 5:7 */
145#define RFRLEN2(value) (((value) & 0x7f) << 8) /* Bits 8:14 */
146#define RPHASE BIT(15)
147
148/*************************** McBSP XCR2 bit definitions ***********************/
149#define XDATDLY(value) ((value) & 0x3) /* Bits 0:1 */
150#define XFIG BIT(2)
151#define XCOMPAND(value) (((value) & 0x3) << 3) /* Bits 3:4 */
152#define XWDLEN2(value) (((value) & 0x7) << 5) /* Bits 5:7 */
153#define XFRLEN2(value) (((value) & 0x7f) << 8) /* Bits 8:14 */
154#define XPHASE BIT(15)
155
156/************************* McBSP SRGR1 bit definitions ************************/
157#define CLKGDV(value) ((value) & 0x7f) /* Bits 0:7 */
158#define FWID(value) (((value) & 0xff) << 8) /* Bits 8:15 */
159
160/************************* McBSP SRGR2 bit definitions ************************/
161#define FPER(value) ((value) & 0x0fff) /* Bits 0:11 */
162#define FSGM BIT(12)
163#define CLKSM BIT(13)
164#define CLKSP BIT(14)
165#define GSYNC BIT(15)
166
167/************************* McBSP MCR1 bit definitions *************************/
168#define RMCM BIT(0)
169#define RCBLK(value) (((value) & 0x7) << 2) /* Bits 2:4 */
170#define RPABLK(value) (((value) & 0x3) << 5) /* Bits 5:6 */
171#define RPBBLK(value) (((value) & 0x3) << 7) /* Bits 7:8 */
172
173/************************* McBSP MCR2 bit definitions *************************/
174#define XMCM(value) ((value) & 0x3) /* Bits 0:1 */
175#define XCBLK(value) (((value) & 0x7) << 2) /* Bits 2:4 */
176#define XPABLK(value) (((value) & 0x3) << 5) /* Bits 5:6 */
177#define XPBBLK(value) (((value) & 0x3) << 7) /* Bits 7:8 */
178
179/*********************** McBSP XCCR bit definitions *************************/
180#define XDISABLE BIT(0)
181#define XDMAEN BIT(3)
182#define DILB BIT(5)
183#define XFULL_CYCLE BIT(11)
184#define DXENDLY(value) (((value) & 0x3) << 12) /* Bits 12:13 */
185#define PPCONNECT BIT(14)
186#define EXTCLKGATE BIT(15)
187
188/********************** McBSP RCCR bit definitions *************************/
189#define RDISABLE BIT(0)
190#define RDMAEN BIT(3)
191#define RFULL_CYCLE BIT(11)
192
193/********************** McBSP SYSCONFIG bit definitions ********************/
194#define SOFTRST BIT(1)
195#define ENAWAKEUP BIT(2)
196#define SIDLEMODE(value) (((value) & 0x3) << 3)
197#define CLOCKACTIVITY(value) (((value) & 0x3) << 8)
198
199/********************** McBSP SSELCR bit definitions ***********************/
200#define SIDETONEEN BIT(10)
201
202/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/
203#define ST_AUTOIDLE BIT(0)
204
205/********************** McBSP Sidetone SGAINCR bit definitions *************/
206#define ST_CH0GAIN(value) ((value) & 0xffff) /* Bits 0:15 */
207#define ST_CH1GAIN(value) (((value) & 0xffff) << 16) /* Bits 16:31 */
208
209/********************** McBSP Sidetone SFIRCR bit definitions **************/
210#define ST_FIRCOEFF(value) ((value) & 0xffff) /* Bits 0:15 */
211
212/********************** McBSP Sidetone SSELCR bit definitions **************/
213#define ST_SIDETONEEN BIT(0)
214#define ST_COEFFWREN BIT(1)
215#define ST_COEFFWRDONE BIT(2)
216
217/********************** McBSP DMA operating modes **************************/
218#define MCBSP_DMA_MODE_ELEMENT 0
219#define MCBSP_DMA_MODE_THRESHOLD 1
220#define MCBSP_DMA_MODE_FRAME 2
221
222/********************** McBSP WAKEUPEN bit definitions *********************/
223#define RSYNCERREN BIT(0)
224#define RFSREN BIT(1)
225#define REOFEN BIT(2)
226#define RRDYEN BIT(3)
227#define XSYNCERREN BIT(7)
228#define XFSXEN BIT(8)
229#define XEOFEN BIT(9)
230#define XRDYEN BIT(10)
231#define XEMPTYEOFEN BIT(14)
232
233/* Clock signal muxing options */
234#define CLKR_SRC_CLKR 0 /* CLKR signal is from the CLKR pin */
235#define CLKR_SRC_CLKX 1 /* CLKR signal is from the CLKX pin */
236#define FSR_SRC_FSR 2 /* FSR signal is from the FSR pin */
237#define FSR_SRC_FSX 3 /* FSR signal is from the FSX pin */
238
239/* McBSP functional clock sources */
240#define MCBSP_CLKS_PRCM_SRC 0
241#define MCBSP_CLKS_PAD_SRC 1
242
243/* we don't do multichannel for now */
244struct omap_mcbsp_reg_cfg {
245 u16 spcr2;
246 u16 spcr1;
247 u16 rcr2;
248 u16 rcr1;
249 u16 xcr2;
250 u16 xcr1;
251 u16 srgr2;
252 u16 srgr1;
253 u16 mcr2;
254 u16 mcr1;
255 u16 pcr0;
256 u16 rcerc;
257 u16 rcerd;
258 u16 xcerc;
259 u16 xcerd;
260 u16 rcere;
261 u16 rcerf;
262 u16 xcere;
263 u16 xcerf;
264 u16 rcerg;
265 u16 rcerh;
266 u16 xcerg;
267 u16 xcerh;
268 u16 xccr;
269 u16 rccr;
270};
271
272struct omap_mcbsp_st_data {
273 void __iomem *io_base_st;
274 bool running;
275 bool enabled;
276 s16 taps[128]; /* Sidetone filter coefficients */
277 int nr_taps; /* Number of filter coefficients in use */
278 s16 ch0gain;
279 s16 ch1gain;
280};
281
282struct omap_mcbsp {
283 struct device *dev;
284 struct clk *fclk;
285 spinlock_t lock;
286 unsigned long phys_base;
287 unsigned long phys_dma_base;
288 void __iomem *io_base;
289 u8 id;
290 /*
291 * Flags indicating is the bus already activated and configured by
292 * another substream
293 */
294 int active;
295 int configured;
296 u8 free;
297
298 int rx_irq;
299 int tx_irq;
300
301 /* Protect the field .free, while checking if the mcbsp is in use */
302 struct omap_mcbsp_platform_data *pdata;
303 struct omap_mcbsp_st_data *st_data;
304 struct omap_mcbsp_reg_cfg cfg_regs;
305 struct omap_pcm_dma_data dma_data[2];
306 int dma_op_mode;
307 u16 max_tx_thres;
308 u16 max_rx_thres;
309 void *reg_cache;
310 int reg_cache_size;
311
312 unsigned int fmt;
313 unsigned int in_freq;
314 int clk_div;
315 int wlen;
316};
317
318void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
319 const struct omap_mcbsp_reg_cfg *config);
320void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold);
321void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold);
322u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp);
323u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp);
324int omap_mcbsp_get_dma_op_mode(struct omap_mcbsp *mcbsp);
325int omap_mcbsp_request(struct omap_mcbsp *mcbsp);
326void omap_mcbsp_free(struct omap_mcbsp *mcbsp);
327void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int tx, int rx);
328void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx);
329
330/* McBSP functional clock source changing function */
331int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id);
332
333/* McBSP signal muxing API */
334int omap_mcbsp_6pin_src_mux(struct omap_mcbsp *mcbsp, u8 mux);
335
336/* Sidetone specific API */
337int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain);
338int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain);
339int omap_st_enable(struct omap_mcbsp *mcbsp);
340int omap_st_disable(struct omap_mcbsp *mcbsp);
341int omap_st_is_enabled(struct omap_mcbsp *mcbsp);
342
343int __devinit omap_mcbsp_init(struct platform_device *pdev);
344void __devexit omap_mcbsp_sysfs_remove(struct omap_mcbsp *mcbsp);
345
346#endif /* __ASOC_MCBSP_H */
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index c292bf0fd19c..abac4b690750 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -275,7 +275,7 @@ static int n810_aic33_init(struct snd_soc_pcm_runtime *rtd)
275static struct snd_soc_dai_link n810_dai = { 275static struct snd_soc_dai_link n810_dai = {
276 .name = "TLV320AIC33", 276 .name = "TLV320AIC33",
277 .stream_name = "AIC33", 277 .stream_name = "AIC33",
278 .cpu_dai_name = "omap-mcbsp-dai.1", 278 .cpu_dai_name = "omap-mcbsp.2",
279 .platform_name = "omap-pcm-audio", 279 .platform_name = "omap-pcm-audio",
280 .codec_name = "tlv320aic3x-codec.2-0018", 280 .codec_name = "tlv320aic3x-codec.2-0018",
281 .codec_dai_name = "tlv320aic3x-hifi", 281 .codec_dai_name = "tlv320aic3x-hifi",
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 1287b870f221..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_dai *dai) 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 (dai->id) { 742 switch (cpu_dai->id) {
753 case 1: /* McBSP 2 */ 743 case 2: /* McBSP 2 */
754 return snd_soc_add_dai_controls(dai, 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_dai_controls(dai, 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
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
index 476fe2add703..f877b16f19c9 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -59,6 +59,6 @@ enum omap_mcbsp_div {
59#define NUM_LINKS 5 59#define NUM_LINKS 5
60#endif 60#endif
61 61
62int omap_mcbsp_st_add_controls(struct snd_soc_dai *dai); 62int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd);
63 63
64#endif 64#endif
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
index f95fe3064172..b92248cbd47a 100644
--- a/sound/soc/omap/omap-pcm.h
+++ b/sound/soc/omap/omap-pcm.h
@@ -25,6 +25,8 @@
25#ifndef __OMAP_PCM_H__ 25#ifndef __OMAP_PCM_H__
26#define __OMAP_PCM_H__ 26#define __OMAP_PCM_H__
27 27
28struct snd_pcm_substream;
29
28struct omap_pcm_dma_data { 30struct omap_pcm_dma_data {
29 char *name; /* stream identifier */ 31 char *name; /* stream identifier */
30 int dma_req; /* DMA request line */ 32 int dma_req; /* DMA request line */
diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c
index 3357dcc47ed4..2830dfd05661 100644
--- a/sound/soc/omap/omap3beagle.c
+++ b/sound/soc/omap/omap3beagle.c
@@ -91,7 +91,7 @@ static struct snd_soc_ops omap3beagle_ops = {
91static struct snd_soc_dai_link omap3beagle_dai = { 91static struct snd_soc_dai_link omap3beagle_dai = {
92 .name = "TWL4030", 92 .name = "TWL4030",
93 .stream_name = "TWL4030", 93 .stream_name = "TWL4030",
94 .cpu_dai_name = "omap-mcbsp-dai.1", 94 .cpu_dai_name = "omap-mcbsp.2",
95 .platform_name = "omap-pcm-audio", 95 .platform_name = "omap-pcm-audio",
96 .codec_dai_name = "twl4030-hifi", 96 .codec_dai_name = "twl4030-hifi",
97 .codec_name = "twl4030-codec", 97 .codec_name = "twl4030-codec",
diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c
index 071fcb09b8b2..3d468c9179d7 100644
--- a/sound/soc/omap/omap3evm.c
+++ b/sound/soc/omap/omap3evm.c
@@ -58,7 +58,7 @@ static struct snd_soc_ops omap3evm_ops = {
58static struct snd_soc_dai_link omap3evm_dai = { 58static struct snd_soc_dai_link omap3evm_dai = {
59 .name = "TWL4030", 59 .name = "TWL4030",
60 .stream_name = "TWL4030", 60 .stream_name = "TWL4030",
61 .cpu_dai_name = "omap-mcbsp-dai.1", 61 .cpu_dai_name = "omap-mcbsp.2",
62 .codec_dai_name = "twl4030-hifi", 62 .codec_dai_name = "twl4030-hifi",
63 .platform_name = "omap-pcm-audio", 63 .platform_name = "omap-pcm-audio",
64 .codec_name = "twl4030-codec", 64 .codec_name = "twl4030-codec",
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index 07794bd10952..4c3a0978578a 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -208,7 +208,7 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
208 { 208 {
209 .name = "PCM1773", 209 .name = "PCM1773",
210 .stream_name = "HiFi Out", 210 .stream_name = "HiFi Out",
211 .cpu_dai_name = "omap-mcbsp-dai.1", 211 .cpu_dai_name = "omap-mcbsp.2",
212 .codec_dai_name = "twl4030-hifi", 212 .codec_dai_name = "twl4030-hifi",
213 .platform_name = "omap-pcm-audio", 213 .platform_name = "omap-pcm-audio",
214 .codec_name = "twl4030-codec", 214 .codec_name = "twl4030-codec",
@@ -219,7 +219,7 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
219 }, { 219 }, {
220 .name = "TWL4030", 220 .name = "TWL4030",
221 .stream_name = "Line/Mic In", 221 .stream_name = "Line/Mic In",
222 .cpu_dai_name = "omap-mcbsp-dai.3", 222 .cpu_dai_name = "omap-mcbsp.4",
223 .codec_dai_name = "twl4030-hifi", 223 .codec_dai_name = "twl4030-hifi",
224 .platform_name = "omap-pcm-audio", 224 .platform_name = "omap-pcm-audio",
225 .codec_name = "twl4030-codec", 225 .codec_name = "twl4030-codec",
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
index d859b597e7ec..b1a9d64cbc56 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/omap/osk5912.c
@@ -96,7 +96,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
96static struct snd_soc_dai_link osk_dai = { 96static struct snd_soc_dai_link osk_dai = {
97 .name = "TLV320AIC23", 97 .name = "TLV320AIC23",
98 .stream_name = "AIC23", 98 .stream_name = "AIC23",
99 .cpu_dai_name = "omap-mcbsp-dai.0", 99 .cpu_dai_name = "omap-mcbsp.1",
100 .codec_dai_name = "tlv320aic23-hifi", 100 .codec_dai_name = "tlv320aic23-hifi",
101 .platform_name = "omap-pcm-audio", 101 .platform_name = "omap-pcm-audio",
102 .codec_name = "tlv320aic23-codec", 102 .codec_name = "tlv320aic23-codec",
diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c
index 2ee889c50256..6ac3e0c3c282 100644
--- a/sound/soc/omap/overo.c
+++ b/sound/soc/omap/overo.c
@@ -60,7 +60,7 @@ static struct snd_soc_ops overo_ops = {
60static struct snd_soc_dai_link overo_dai = { 60static struct snd_soc_dai_link overo_dai = {
61 .name = "TWL4030", 61 .name = "TWL4030",
62 .stream_name = "TWL4030", 62 .stream_name = "TWL4030",
63 .cpu_dai_name = "omap-mcbsp-dai.1", 63 .cpu_dai_name = "omap-mcbsp.2",
64 .codec_dai_name = "twl4030-hifi", 64 .codec_dai_name = "twl4030-hifi",
65 .platform_name = "omap-pcm-audio", 65 .platform_name = "omap-pcm-audio",
66 .codec_name = "twl4030-codec", 66 .codec_name = "twl4030-codec",
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 58936c730a87..2712dd232b6d 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -313,7 +313,7 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
313 return err; 313 return err;
314 snd_soc_limit_volume(codec, "TPA6130A2 Headphone Playback Volume", 42); 314 snd_soc_limit_volume(codec, "TPA6130A2 Headphone Playback Volume", 42);
315 315
316 err = omap_mcbsp_st_add_controls(rtd->cpu_dai); 316 err = omap_mcbsp_st_add_controls(rtd);
317 if (err < 0) 317 if (err < 0)
318 return err; 318 return err;
319 319
@@ -353,7 +353,7 @@ static struct snd_soc_dai_link rx51_dai[] = {
353 { 353 {
354 .name = "TLV320AIC34", 354 .name = "TLV320AIC34",
355 .stream_name = "AIC34", 355 .stream_name = "AIC34",
356 .cpu_dai_name = "omap-mcbsp-dai.1", 356 .cpu_dai_name = "omap-mcbsp.2",
357 .codec_dai_name = "tlv320aic3x-hifi", 357 .codec_dai_name = "tlv320aic3x-hifi",
358 .platform_name = "omap-pcm-audio", 358 .platform_name = "omap-pcm-audio",
359 .codec_name = "tlv320aic3x-codec.2-0018", 359 .codec_name = "tlv320aic3x-codec.2-0018",
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 2c850662ea7e..0e283226e2bf 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -187,7 +187,7 @@ static struct snd_soc_dai_link sdp3430_dai[] = {
187 { 187 {
188 .name = "TWL4030 I2S", 188 .name = "TWL4030 I2S",
189 .stream_name = "TWL4030 Audio", 189 .stream_name = "TWL4030 Audio",
190 .cpu_dai_name = "omap-mcbsp-dai.1", 190 .cpu_dai_name = "omap-mcbsp.2",
191 .codec_dai_name = "twl4030-hifi", 191 .codec_dai_name = "twl4030-hifi",
192 .platform_name = "omap-pcm-audio", 192 .platform_name = "omap-pcm-audio",
193 .codec_name = "twl4030-codec", 193 .codec_name = "twl4030-codec",
@@ -199,7 +199,7 @@ static struct snd_soc_dai_link sdp3430_dai[] = {
199 { 199 {
200 .name = "TWL4030 PCM", 200 .name = "TWL4030 PCM",
201 .stream_name = "TWL4030 Voice", 201 .stream_name = "TWL4030 Voice",
202 .cpu_dai_name = "omap-mcbsp-dai.2", 202 .cpu_dai_name = "omap-mcbsp.3",
203 .codec_dai_name = "twl4030-voice", 203 .codec_dai_name = "twl4030-voice",
204 .platform_name = "omap-pcm-audio", 204 .platform_name = "omap-pcm-audio",
205 .codec_name = "twl4030-codec", 205 .codec_name = "twl4030-codec",
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
index 981616d61f67..920e0d9e03db 100644
--- a/sound/soc/omap/zoom2.c
+++ b/sound/soc/omap/zoom2.c
@@ -131,7 +131,7 @@ static struct snd_soc_dai_link zoom2_dai[] = {
131 { 131 {
132 .name = "TWL4030 I2S", 132 .name = "TWL4030 I2S",
133 .stream_name = "TWL4030 Audio", 133 .stream_name = "TWL4030 Audio",
134 .cpu_dai_name = "omap-mcbsp-dai.1", 134 .cpu_dai_name = "omap-mcbsp.2",
135 .codec_dai_name = "twl4030-hifi", 135 .codec_dai_name = "twl4030-hifi",
136 .platform_name = "omap-pcm-audio", 136 .platform_name = "omap-pcm-audio",
137 .codec_name = "twl4030-codec", 137 .codec_name = "twl4030-codec",
@@ -143,7 +143,7 @@ static struct snd_soc_dai_link zoom2_dai[] = {
143 { 143 {
144 .name = "TWL4030 PCM", 144 .name = "TWL4030 PCM",
145 .stream_name = "TWL4030 Voice", 145 .stream_name = "TWL4030 Voice",
146 .cpu_dai_name = "omap-mcbsp-dai.2", 146 .cpu_dai_name = "omap-mcbsp.3",
147 .codec_dai_name = "twl4030-voice", 147 .codec_dai_name = "twl4030-voice",
148 .platform_name = "omap-pcm-audio", 148 .platform_name = "omap-pcm-audio",
149 .codec_name = "twl4030-codec", 149 .codec_name = "twl4030-codec",