summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@ti.com>2018-11-08 02:29:58 -0500
committerMark Brown <broonie@kernel.org>2018-11-13 12:50:24 -0500
commit9c34d023dc35a4b3d005d94db512742dfcdc8f82 (patch)
treef99b065aff9521ad4614c94f31c1752cf2d53f8a
parentbe51c576e8495fd2cffbababad6de7e0a0a562ba (diff)
ASoC: omap-mcbsp: Re-arrange files for core McBSP and Sidetone function split
The mcbsp.c was copied a while back from arch/arm/plat-omap/mcbsp.c and it contained a mix of McBSP and McBSP sidetone functions. Create new file structure with the following split: omap-mcbsp.c - McBSP related functions omap-mcbsp-st.c - McBSP sidetone functionality omap-mcbsp-priv.h - Private header for internal use omap-mcbsp.h - Header for user drivers I have tried to do the code move with minimal code change, cleanup patches can be based on the new structure. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Acked-by: Jarkko Nikula <jarkko.nikula@bitmer.com> Tested-by: Jarkko Nikula <jarkko.nikula@bitmer.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/omap/Makefile2
-rw-r--r--sound/soc/omap/mcbsp.c1094
-rw-r--r--sound/soc/omap/omap-mcbsp-priv.h (renamed from sound/soc/omap/mcbsp.h)126
-rw-r--r--sound/soc/omap/omap-mcbsp-st.c516
-rw-r--r--sound/soc/omap/omap-mcbsp.c838
-rw-r--r--sound/soc/omap/omap-mcbsp.h8
6 files changed, 1269 insertions, 1315 deletions
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index af50cdd6eea9..d005338dd13c 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -2,7 +2,7 @@
2# OMAP Platform Support 2# OMAP Platform Support
3snd-soc-sdma-objs := sdma-pcm.o 3snd-soc-sdma-objs := sdma-pcm.o
4snd-soc-omap-dmic-objs := omap-dmic.o 4snd-soc-omap-dmic-objs := omap-dmic.o
5snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o 5snd-soc-omap-mcbsp-objs := omap-mcbsp.o omap-mcbsp-st.o
6snd-soc-omap-mcpdm-objs := omap-mcpdm.o 6snd-soc-omap-mcpdm-objs := omap-mcpdm.o
7snd-soc-omap-hdmi-audio-objs := omap-hdmi-audio.o 7snd-soc-omap-hdmi-audio-objs := omap-hdmi-audio.o
8 8
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
deleted file mode 100644
index b19168f5c110..000000000000
--- a/sound/soc/omap/mcbsp.c
+++ /dev/null
@@ -1,1094 +0,0 @@
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#include <linux/pm_runtime.h>
28
29#include <linux/platform_data/asoc-ti-mcbsp.h>
30
31#include "mcbsp.h"
32
33static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
34{
35 void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
36
37 if (mcbsp->pdata->reg_size == 2) {
38 ((u16 *)mcbsp->reg_cache)[reg] = (u16)val;
39 writew_relaxed((u16)val, addr);
40 } else {
41 ((u32 *)mcbsp->reg_cache)[reg] = val;
42 writel_relaxed(val, addr);
43 }
44}
45
46static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
47{
48 void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
49
50 if (mcbsp->pdata->reg_size == 2) {
51 return !from_cache ? readw_relaxed(addr) :
52 ((u16 *)mcbsp->reg_cache)[reg];
53 } else {
54 return !from_cache ? readl_relaxed(addr) :
55 ((u32 *)mcbsp->reg_cache)[reg];
56 }
57}
58
59static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
60{
61 writel_relaxed(val, mcbsp->st_data->io_base_st + reg);
62}
63
64static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
65{
66 return readl_relaxed(mcbsp->st_data->io_base_st + reg);
67}
68
69#define MCBSP_READ(mcbsp, reg) \
70 omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0)
71#define MCBSP_WRITE(mcbsp, reg, val) \
72 omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val)
73#define MCBSP_READ_CACHE(mcbsp, reg) \
74 omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1)
75
76#define MCBSP_ST_READ(mcbsp, reg) \
77 omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
78#define MCBSP_ST_WRITE(mcbsp, reg, val) \
79 omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val)
80
81static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp)
82{
83 dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id);
84 dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n",
85 MCBSP_READ(mcbsp, DRR2));
86 dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n",
87 MCBSP_READ(mcbsp, DRR1));
88 dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n",
89 MCBSP_READ(mcbsp, DXR2));
90 dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n",
91 MCBSP_READ(mcbsp, DXR1));
92 dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n",
93 MCBSP_READ(mcbsp, SPCR2));
94 dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n",
95 MCBSP_READ(mcbsp, SPCR1));
96 dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n",
97 MCBSP_READ(mcbsp, RCR2));
98 dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n",
99 MCBSP_READ(mcbsp, RCR1));
100 dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n",
101 MCBSP_READ(mcbsp, XCR2));
102 dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n",
103 MCBSP_READ(mcbsp, XCR1));
104 dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n",
105 MCBSP_READ(mcbsp, SRGR2));
106 dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n",
107 MCBSP_READ(mcbsp, SRGR1));
108 dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n",
109 MCBSP_READ(mcbsp, PCR0));
110 dev_dbg(mcbsp->dev, "***********************\n");
111}
112
113static irqreturn_t omap_mcbsp_irq_handler(int irq, void *data)
114{
115 struct omap_mcbsp *mcbsp = data;
116 u16 irqst;
117
118 irqst = MCBSP_READ(mcbsp, IRQST);
119 dev_dbg(mcbsp->dev, "IRQ callback : 0x%x\n", irqst);
120
121 if (irqst & RSYNCERREN)
122 dev_err(mcbsp->dev, "RX Frame Sync Error!\n");
123 if (irqst & RFSREN)
124 dev_dbg(mcbsp->dev, "RX Frame Sync\n");
125 if (irqst & REOFEN)
126 dev_dbg(mcbsp->dev, "RX End Of Frame\n");
127 if (irqst & RRDYEN)
128 dev_dbg(mcbsp->dev, "RX Buffer Threshold Reached\n");
129 if (irqst & RUNDFLEN)
130 dev_err(mcbsp->dev, "RX Buffer Underflow!\n");
131 if (irqst & ROVFLEN)
132 dev_err(mcbsp->dev, "RX Buffer Overflow!\n");
133
134 if (irqst & XSYNCERREN)
135 dev_err(mcbsp->dev, "TX Frame Sync Error!\n");
136 if (irqst & XFSXEN)
137 dev_dbg(mcbsp->dev, "TX Frame Sync\n");
138 if (irqst & XEOFEN)
139 dev_dbg(mcbsp->dev, "TX End Of Frame\n");
140 if (irqst & XRDYEN)
141 dev_dbg(mcbsp->dev, "TX Buffer threshold Reached\n");
142 if (irqst & XUNDFLEN)
143 dev_err(mcbsp->dev, "TX Buffer Underflow!\n");
144 if (irqst & XOVFLEN)
145 dev_err(mcbsp->dev, "TX Buffer Overflow!\n");
146 if (irqst & XEMPTYEOFEN)
147 dev_dbg(mcbsp->dev, "TX Buffer empty at end of frame\n");
148
149 MCBSP_WRITE(mcbsp, IRQST, irqst);
150
151 return IRQ_HANDLED;
152}
153
154static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *data)
155{
156 struct omap_mcbsp *mcbsp = data;
157 u16 irqst_spcr2;
158
159 irqst_spcr2 = MCBSP_READ(mcbsp, SPCR2);
160 dev_dbg(mcbsp->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
161
162 if (irqst_spcr2 & XSYNC_ERR) {
163 dev_err(mcbsp->dev, "TX Frame Sync Error! : 0x%x\n",
164 irqst_spcr2);
165 /* Writing zero to XSYNC_ERR clears the IRQ */
166 MCBSP_WRITE(mcbsp, SPCR2, MCBSP_READ_CACHE(mcbsp, SPCR2));
167 }
168
169 return IRQ_HANDLED;
170}
171
172static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *data)
173{
174 struct omap_mcbsp *mcbsp = data;
175 u16 irqst_spcr1;
176
177 irqst_spcr1 = MCBSP_READ(mcbsp, SPCR1);
178 dev_dbg(mcbsp->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
179
180 if (irqst_spcr1 & RSYNC_ERR) {
181 dev_err(mcbsp->dev, "RX Frame Sync Error! : 0x%x\n",
182 irqst_spcr1);
183 /* Writing zero to RSYNC_ERR clears the IRQ */
184 MCBSP_WRITE(mcbsp, SPCR1, MCBSP_READ_CACHE(mcbsp, SPCR1));
185 }
186
187 return IRQ_HANDLED;
188}
189
190/*
191 * omap_mcbsp_config simply write a config to the
192 * appropriate McBSP.
193 * You either call this function or set the McBSP registers
194 * by yourself before calling omap_mcbsp_start().
195 */
196void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
197 const struct omap_mcbsp_reg_cfg *config)
198{
199 dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n",
200 mcbsp->id, mcbsp->phys_base);
201
202 /* We write the given config */
203 MCBSP_WRITE(mcbsp, SPCR2, config->spcr2);
204 MCBSP_WRITE(mcbsp, SPCR1, config->spcr1);
205 MCBSP_WRITE(mcbsp, RCR2, config->rcr2);
206 MCBSP_WRITE(mcbsp, RCR1, config->rcr1);
207 MCBSP_WRITE(mcbsp, XCR2, config->xcr2);
208 MCBSP_WRITE(mcbsp, XCR1, config->xcr1);
209 MCBSP_WRITE(mcbsp, SRGR2, config->srgr2);
210 MCBSP_WRITE(mcbsp, SRGR1, config->srgr1);
211 MCBSP_WRITE(mcbsp, MCR2, config->mcr2);
212 MCBSP_WRITE(mcbsp, MCR1, config->mcr1);
213 MCBSP_WRITE(mcbsp, PCR0, config->pcr0);
214 if (mcbsp->pdata->has_ccr) {
215 MCBSP_WRITE(mcbsp, XCCR, config->xccr);
216 MCBSP_WRITE(mcbsp, RCCR, config->rccr);
217 }
218 /* Enable wakeup behavior */
219 if (mcbsp->pdata->has_wakeup)
220 MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
221
222 /* Enable TX/RX sync error interrupts by default */
223 if (mcbsp->irq)
224 MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN |
225 RUNDFLEN | ROVFLEN | XUNDFLEN | XOVFLEN);
226}
227
228/**
229 * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register
230 * @mcbsp: omap_mcbsp struct for the McBSP instance
231 * @stream: Stream direction (playback/capture)
232 *
233 * Returns the address of mcbsp data transmit register or data receive register
234 * to be used by DMA for transferring/receiving data
235 */
236static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp,
237 unsigned int stream)
238{
239 int data_reg;
240
241 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
242 if (mcbsp->pdata->reg_size == 2)
243 data_reg = OMAP_MCBSP_REG_DXR1;
244 else
245 data_reg = OMAP_MCBSP_REG_DXR;
246 } else {
247 if (mcbsp->pdata->reg_size == 2)
248 data_reg = OMAP_MCBSP_REG_DRR1;
249 else
250 data_reg = OMAP_MCBSP_REG_DRR;
251 }
252
253 return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step;
254}
255
256static void omap_st_on(struct omap_mcbsp *mcbsp)
257{
258 unsigned int w;
259
260 if (mcbsp->pdata->force_ick_on)
261 mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, true);
262
263 /* Disable Sidetone clock auto-gating for normal operation */
264 w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
265 MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
266
267 /* Enable McBSP Sidetone */
268 w = MCBSP_READ(mcbsp, SSELCR);
269 MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
270
271 /* Enable Sidetone from Sidetone Core */
272 w = MCBSP_ST_READ(mcbsp, SSELCR);
273 MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
274}
275
276static void omap_st_off(struct omap_mcbsp *mcbsp)
277{
278 unsigned int w;
279
280 w = MCBSP_ST_READ(mcbsp, SSELCR);
281 MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
282
283 w = MCBSP_READ(mcbsp, SSELCR);
284 MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
285
286 /* Enable Sidetone clock auto-gating to reduce power consumption */
287 w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
288 MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE);
289
290 if (mcbsp->pdata->force_ick_on)
291 mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, false);
292}
293
294static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
295{
296 u16 val, i;
297
298 val = MCBSP_ST_READ(mcbsp, SSELCR);
299
300 if (val & ST_COEFFWREN)
301 MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
302
303 MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN);
304
305 for (i = 0; i < 128; i++)
306 MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]);
307
308 i = 0;
309
310 val = MCBSP_ST_READ(mcbsp, SSELCR);
311 while (!(val & ST_COEFFWRDONE) && (++i < 1000))
312 val = MCBSP_ST_READ(mcbsp, SSELCR);
313
314 MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
315
316 if (i == 1000)
317 dev_err(mcbsp->dev, "McBSP FIR load error!\n");
318}
319
320static void omap_st_chgain(struct omap_mcbsp *mcbsp)
321{
322 u16 w;
323 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
324
325 w = MCBSP_ST_READ(mcbsp, SSELCR);
326
327 MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) | \
328 ST_CH1GAIN(st_data->ch1gain));
329}
330
331int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain)
332{
333 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
334 int ret = 0;
335
336 if (!st_data)
337 return -ENOENT;
338
339 spin_lock_irq(&mcbsp->lock);
340 if (channel == 0)
341 st_data->ch0gain = chgain;
342 else if (channel == 1)
343 st_data->ch1gain = chgain;
344 else
345 ret = -EINVAL;
346
347 if (st_data->enabled)
348 omap_st_chgain(mcbsp);
349 spin_unlock_irq(&mcbsp->lock);
350
351 return ret;
352}
353
354int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain)
355{
356 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
357 int ret = 0;
358
359 if (!st_data)
360 return -ENOENT;
361
362 spin_lock_irq(&mcbsp->lock);
363 if (channel == 0)
364 *chgain = st_data->ch0gain;
365 else if (channel == 1)
366 *chgain = st_data->ch1gain;
367 else
368 ret = -EINVAL;
369 spin_unlock_irq(&mcbsp->lock);
370
371 return ret;
372}
373
374static int omap_st_start(struct omap_mcbsp *mcbsp)
375{
376 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
377
378 if (st_data->enabled && !st_data->running) {
379 omap_st_fir_write(mcbsp, st_data->taps);
380 omap_st_chgain(mcbsp);
381
382 if (!mcbsp->free) {
383 omap_st_on(mcbsp);
384 st_data->running = 1;
385 }
386 }
387
388 return 0;
389}
390
391int omap_st_enable(struct omap_mcbsp *mcbsp)
392{
393 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
394
395 if (!st_data)
396 return -ENODEV;
397
398 spin_lock_irq(&mcbsp->lock);
399 st_data->enabled = 1;
400 omap_st_start(mcbsp);
401 spin_unlock_irq(&mcbsp->lock);
402
403 return 0;
404}
405
406static int omap_st_stop(struct omap_mcbsp *mcbsp)
407{
408 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
409
410 if (st_data->running) {
411 if (!mcbsp->free) {
412 omap_st_off(mcbsp);
413 st_data->running = 0;
414 }
415 }
416
417 return 0;
418}
419
420int omap_st_disable(struct omap_mcbsp *mcbsp)
421{
422 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
423 int ret = 0;
424
425 if (!st_data)
426 return -ENODEV;
427
428 spin_lock_irq(&mcbsp->lock);
429 omap_st_stop(mcbsp);
430 st_data->enabled = 0;
431 spin_unlock_irq(&mcbsp->lock);
432
433 return ret;
434}
435
436int omap_st_is_enabled(struct omap_mcbsp *mcbsp)
437{
438 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
439
440 if (!st_data)
441 return -ENODEV;
442
443 return st_data->enabled;
444}
445
446/*
447 * omap_mcbsp_set_rx_threshold configures the transmit threshold in words.
448 * The threshold parameter is 1 based, and it is converted (threshold - 1)
449 * for the THRSH2 register.
450 */
451void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
452{
453 if (threshold && threshold <= mcbsp->max_tx_thres)
454 MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
455}
456
457/*
458 * omap_mcbsp_set_rx_threshold configures the receive threshold in words.
459 * The threshold parameter is 1 based, and it is converted (threshold - 1)
460 * for the THRSH1 register.
461 */
462void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
463{
464 if (threshold && threshold <= mcbsp->max_rx_thres)
465 MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
466}
467
468/*
469 * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
470 */
471u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp)
472{
473 u16 buffstat;
474
475 /* Returns the number of free locations in the buffer */
476 buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
477
478 /* Number of slots are different in McBSP ports */
479 return mcbsp->pdata->buffer_size - buffstat;
480}
481
482/*
483 * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO
484 * to reach the threshold value (when the DMA will be triggered to read it)
485 */
486u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp)
487{
488 u16 buffstat, threshold;
489
490 /* Returns the number of used locations in the buffer */
491 buffstat = MCBSP_READ(mcbsp, RBUFFSTAT);
492 /* RX threshold */
493 threshold = MCBSP_READ(mcbsp, THRSH1);
494
495 /* Return the number of location till we reach the threshold limit */
496 if (threshold <= buffstat)
497 return 0;
498 else
499 return threshold - buffstat;
500}
501
502int omap_mcbsp_request(struct omap_mcbsp *mcbsp)
503{
504 void *reg_cache;
505 int err;
506
507 reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL);
508 if (!reg_cache) {
509 return -ENOMEM;
510 }
511
512 spin_lock(&mcbsp->lock);
513 if (!mcbsp->free) {
514 dev_err(mcbsp->dev, "McBSP%d is currently in use\n",
515 mcbsp->id);
516 err = -EBUSY;
517 goto err_kfree;
518 }
519
520 mcbsp->free = false;
521 mcbsp->reg_cache = reg_cache;
522 spin_unlock(&mcbsp->lock);
523
524 if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request)
525 mcbsp->pdata->ops->request(mcbsp->id - 1);
526
527 /*
528 * Make sure that transmitter, receiver and sample-rate generator are
529 * not running before activating IRQs.
530 */
531 MCBSP_WRITE(mcbsp, SPCR1, 0);
532 MCBSP_WRITE(mcbsp, SPCR2, 0);
533
534 if (mcbsp->irq) {
535 err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0,
536 "McBSP", (void *)mcbsp);
537 if (err != 0) {
538 dev_err(mcbsp->dev, "Unable to request IRQ\n");
539 goto err_clk_disable;
540 }
541 } else {
542 err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0,
543 "McBSP TX", (void *)mcbsp);
544 if (err != 0) {
545 dev_err(mcbsp->dev, "Unable to request TX IRQ\n");
546 goto err_clk_disable;
547 }
548
549 err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0,
550 "McBSP RX", (void *)mcbsp);
551 if (err != 0) {
552 dev_err(mcbsp->dev, "Unable to request RX IRQ\n");
553 goto err_free_irq;
554 }
555 }
556
557 return 0;
558err_free_irq:
559 free_irq(mcbsp->tx_irq, (void *)mcbsp);
560err_clk_disable:
561 if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
562 mcbsp->pdata->ops->free(mcbsp->id - 1);
563
564 /* Disable wakeup behavior */
565 if (mcbsp->pdata->has_wakeup)
566 MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
567
568 spin_lock(&mcbsp->lock);
569 mcbsp->free = true;
570 mcbsp->reg_cache = NULL;
571err_kfree:
572 spin_unlock(&mcbsp->lock);
573 kfree(reg_cache);
574
575 return err;
576}
577
578void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
579{
580 void *reg_cache;
581
582 if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
583 mcbsp->pdata->ops->free(mcbsp->id - 1);
584
585 /* Disable wakeup behavior */
586 if (mcbsp->pdata->has_wakeup)
587 MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
588
589 /* Disable interrupt requests */
590 if (mcbsp->irq)
591 MCBSP_WRITE(mcbsp, IRQEN, 0);
592
593 if (mcbsp->irq) {
594 free_irq(mcbsp->irq, (void *)mcbsp);
595 } else {
596 free_irq(mcbsp->rx_irq, (void *)mcbsp);
597 free_irq(mcbsp->tx_irq, (void *)mcbsp);
598 }
599
600 reg_cache = mcbsp->reg_cache;
601
602 /*
603 * Select CLKS source from internal source unconditionally before
604 * marking the McBSP port as free.
605 * If the external clock source via MCBSP_CLKS pin has been selected the
606 * system will refuse to enter idle if the CLKS pin source is not reset
607 * back to internal source.
608 */
609 if (!mcbsp_omap1())
610 omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC);
611
612 spin_lock(&mcbsp->lock);
613 if (mcbsp->free)
614 dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id);
615 else
616 mcbsp->free = true;
617 mcbsp->reg_cache = NULL;
618 spin_unlock(&mcbsp->lock);
619
620 kfree(reg_cache);
621}
622
623/*
624 * Here we start the McBSP, by enabling transmitter, receiver or both.
625 * If no transmitter or receiver is active prior calling, then sample-rate
626 * generator and frame sync are started.
627 */
628void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int stream)
629{
630 int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);
631 int rx = !tx;
632 int enable_srg = 0;
633 u16 w;
634
635 if (mcbsp->st_data)
636 omap_st_start(mcbsp);
637
638 /* Only enable SRG, if McBSP is master */
639 w = MCBSP_READ_CACHE(mcbsp, PCR0);
640 if (w & (FSXM | FSRM | CLKXM | CLKRM))
641 enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
642 MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
643
644 if (enable_srg) {
645 /* Start the sample generator */
646 w = MCBSP_READ_CACHE(mcbsp, SPCR2);
647 MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6));
648 }
649
650 /* Enable transmitter and receiver */
651 tx &= 1;
652 w = MCBSP_READ_CACHE(mcbsp, SPCR2);
653 MCBSP_WRITE(mcbsp, SPCR2, w | tx);
654
655 rx &= 1;
656 w = MCBSP_READ_CACHE(mcbsp, SPCR1);
657 MCBSP_WRITE(mcbsp, SPCR1, w | rx);
658
659 /*
660 * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec
661 * REVISIT: 100us may give enough time for two CLKSRG, however
662 * due to some unknown PM related, clock gating etc. reason it
663 * is now at 500us.
664 */
665 udelay(500);
666
667 if (enable_srg) {
668 /* Start frame sync */
669 w = MCBSP_READ_CACHE(mcbsp, SPCR2);
670 MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
671 }
672
673 if (mcbsp->pdata->has_ccr) {
674 /* Release the transmitter and receiver */
675 w = MCBSP_READ_CACHE(mcbsp, XCCR);
676 w &= ~(tx ? XDISABLE : 0);
677 MCBSP_WRITE(mcbsp, XCCR, w);
678 w = MCBSP_READ_CACHE(mcbsp, RCCR);
679 w &= ~(rx ? RDISABLE : 0);
680 MCBSP_WRITE(mcbsp, RCCR, w);
681 }
682
683 /* Dump McBSP Regs */
684 omap_mcbsp_dump_reg(mcbsp);
685}
686
687void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int stream)
688{
689 int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);
690 int rx = !tx;
691 int idle;
692 u16 w;
693
694 /* Reset transmitter */
695 tx &= 1;
696 if (mcbsp->pdata->has_ccr) {
697 w = MCBSP_READ_CACHE(mcbsp, XCCR);
698 w |= (tx ? XDISABLE : 0);
699 MCBSP_WRITE(mcbsp, XCCR, w);
700 }
701 w = MCBSP_READ_CACHE(mcbsp, SPCR2);
702 MCBSP_WRITE(mcbsp, SPCR2, w & ~tx);
703
704 /* Reset receiver */
705 rx &= 1;
706 if (mcbsp->pdata->has_ccr) {
707 w = MCBSP_READ_CACHE(mcbsp, RCCR);
708 w |= (rx ? RDISABLE : 0);
709 MCBSP_WRITE(mcbsp, RCCR, w);
710 }
711 w = MCBSP_READ_CACHE(mcbsp, SPCR1);
712 MCBSP_WRITE(mcbsp, SPCR1, w & ~rx);
713
714 idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
715 MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
716
717 if (idle) {
718 /* Reset the sample rate generator */
719 w = MCBSP_READ_CACHE(mcbsp, SPCR2);
720 MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6));
721 }
722
723 if (mcbsp->st_data)
724 omap_st_stop(mcbsp);
725}
726
727int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id)
728{
729 struct clk *fck_src;
730 const char *src;
731 int r;
732
733 if (fck_src_id == MCBSP_CLKS_PAD_SRC)
734 src = "pad_fck";
735 else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
736 src = "prcm_fck";
737 else
738 return -EINVAL;
739
740 fck_src = clk_get(mcbsp->dev, src);
741 if (IS_ERR(fck_src)) {
742 dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src);
743 return -EINVAL;
744 }
745
746 pm_runtime_put_sync(mcbsp->dev);
747
748 r = clk_set_parent(mcbsp->fclk, fck_src);
749 if (r) {
750 dev_err(mcbsp->dev, "CLKS: could not clk_set_parent() to %s\n",
751 src);
752 clk_put(fck_src);
753 return r;
754 }
755
756 pm_runtime_get_sync(mcbsp->dev);
757
758 clk_put(fck_src);
759
760 return 0;
761
762}
763
764#define max_thres(m) (mcbsp->pdata->buffer_size)
765#define valid_threshold(m, val) ((val) <= max_thres(m))
766#define THRESHOLD_PROP_BUILDER(prop) \
767static ssize_t prop##_show(struct device *dev, \
768 struct device_attribute *attr, char *buf) \
769{ \
770 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
771 \
772 return sprintf(buf, "%u\n", mcbsp->prop); \
773} \
774 \
775static ssize_t prop##_store(struct device *dev, \
776 struct device_attribute *attr, \
777 const char *buf, size_t size) \
778{ \
779 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
780 unsigned long val; \
781 int status; \
782 \
783 status = kstrtoul(buf, 0, &val); \
784 if (status) \
785 return status; \
786 \
787 if (!valid_threshold(mcbsp, val)) \
788 return -EDOM; \
789 \
790 mcbsp->prop = val; \
791 return size; \
792} \
793 \
794static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store);
795
796THRESHOLD_PROP_BUILDER(max_tx_thres);
797THRESHOLD_PROP_BUILDER(max_rx_thres);
798
799static const char *dma_op_modes[] = {
800 "element", "threshold",
801};
802
803static ssize_t dma_op_mode_show(struct device *dev,
804 struct device_attribute *attr, char *buf)
805{
806 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
807 int dma_op_mode, i = 0;
808 ssize_t len = 0;
809 const char * const *s;
810
811 dma_op_mode = mcbsp->dma_op_mode;
812
813 for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) {
814 if (dma_op_mode == i)
815 len += sprintf(buf + len, "[%s] ", *s);
816 else
817 len += sprintf(buf + len, "%s ", *s);
818 }
819 len += sprintf(buf + len, "\n");
820
821 return len;
822}
823
824static ssize_t dma_op_mode_store(struct device *dev,
825 struct device_attribute *attr,
826 const char *buf, size_t size)
827{
828 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
829 int i;
830
831 i = sysfs_match_string(dma_op_modes, buf);
832 if (i < 0)
833 return i;
834
835 spin_lock_irq(&mcbsp->lock);
836 if (!mcbsp->free) {
837 size = -EBUSY;
838 goto unlock;
839 }
840 mcbsp->dma_op_mode = i;
841
842unlock:
843 spin_unlock_irq(&mcbsp->lock);
844
845 return size;
846}
847
848static DEVICE_ATTR_RW(dma_op_mode);
849
850static const struct attribute *additional_attrs[] = {
851 &dev_attr_max_tx_thres.attr,
852 &dev_attr_max_rx_thres.attr,
853 &dev_attr_dma_op_mode.attr,
854 NULL,
855};
856
857static const struct attribute_group additional_attr_group = {
858 .attrs = (struct attribute **)additional_attrs,
859};
860
861static ssize_t st_taps_show(struct device *dev,
862 struct device_attribute *attr, char *buf)
863{
864 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
865 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
866 ssize_t status = 0;
867 int i;
868
869 spin_lock_irq(&mcbsp->lock);
870 for (i = 0; i < st_data->nr_taps; i++)
871 status += sprintf(&buf[status], (i ? ", %d" : "%d"),
872 st_data->taps[i]);
873 if (i)
874 status += sprintf(&buf[status], "\n");
875 spin_unlock_irq(&mcbsp->lock);
876
877 return status;
878}
879
880static ssize_t st_taps_store(struct device *dev,
881 struct device_attribute *attr,
882 const char *buf, size_t size)
883{
884 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
885 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
886 int val, tmp, status, i = 0;
887
888 spin_lock_irq(&mcbsp->lock);
889 memset(st_data->taps, 0, sizeof(st_data->taps));
890 st_data->nr_taps = 0;
891
892 do {
893 status = sscanf(buf, "%d%n", &val, &tmp);
894 if (status < 0 || status == 0) {
895 size = -EINVAL;
896 goto out;
897 }
898 if (val < -32768 || val > 32767) {
899 size = -EINVAL;
900 goto out;
901 }
902 st_data->taps[i++] = val;
903 buf += tmp;
904 if (*buf != ',')
905 break;
906 buf++;
907 } while (1);
908
909 st_data->nr_taps = i;
910
911out:
912 spin_unlock_irq(&mcbsp->lock);
913
914 return size;
915}
916
917static DEVICE_ATTR_RW(st_taps);
918
919static const struct attribute *sidetone_attrs[] = {
920 &dev_attr_st_taps.attr,
921 NULL,
922};
923
924static const struct attribute_group sidetone_attr_group = {
925 .attrs = (struct attribute **)sidetone_attrs,
926};
927
928static int omap_st_add(struct omap_mcbsp *mcbsp, struct resource *res)
929{
930 struct omap_mcbsp_st_data *st_data;
931 int err;
932
933 st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL);
934 if (!st_data)
935 return -ENOMEM;
936
937 st_data->mcbsp_iclk = clk_get(mcbsp->dev, "ick");
938 if (IS_ERR(st_data->mcbsp_iclk)) {
939 dev_warn(mcbsp->dev,
940 "Failed to get ick, sidetone might be broken\n");
941 st_data->mcbsp_iclk = NULL;
942 }
943
944 st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start,
945 resource_size(res));
946 if (!st_data->io_base_st)
947 return -ENOMEM;
948
949 err = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
950 if (err)
951 return err;
952
953 mcbsp->st_data = st_data;
954 return 0;
955}
956
957/*
958 * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
959 * 730 has only 2 McBSP, and both of them are MPU peripherals.
960 */
961int omap_mcbsp_init(struct platform_device *pdev)
962{
963 struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
964 struct resource *res;
965 int ret = 0;
966
967 spin_lock_init(&mcbsp->lock);
968 mcbsp->free = true;
969
970 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
971 if (!res)
972 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
973
974 mcbsp->io_base = devm_ioremap_resource(&pdev->dev, res);
975 if (IS_ERR(mcbsp->io_base))
976 return PTR_ERR(mcbsp->io_base);
977
978 mcbsp->phys_base = res->start;
979 mcbsp->reg_cache_size = resource_size(res);
980
981 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
982 if (!res)
983 mcbsp->phys_dma_base = mcbsp->phys_base;
984 else
985 mcbsp->phys_dma_base = res->start;
986
987 /*
988 * OMAP1, 2 uses two interrupt lines: TX, RX
989 * OMAP2430, OMAP3 SoC have combined IRQ line as well.
990 * OMAP4 and newer SoC only have the combined IRQ line.
991 * Use the combined IRQ if available since it gives better debugging
992 * possibilities.
993 */
994 mcbsp->irq = platform_get_irq_byname(pdev, "common");
995 if (mcbsp->irq == -ENXIO) {
996 mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
997
998 if (mcbsp->tx_irq == -ENXIO) {
999 mcbsp->irq = platform_get_irq(pdev, 0);
1000 mcbsp->tx_irq = 0;
1001 } else {
1002 mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
1003 mcbsp->irq = 0;
1004 }
1005 }
1006
1007 if (!pdev->dev.of_node) {
1008 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
1009 if (!res) {
1010 dev_err(&pdev->dev, "invalid tx DMA channel\n");
1011 return -ENODEV;
1012 }
1013 mcbsp->dma_req[0] = res->start;
1014 mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
1015
1016 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
1017 if (!res) {
1018 dev_err(&pdev->dev, "invalid rx DMA channel\n");
1019 return -ENODEV;
1020 }
1021 mcbsp->dma_req[1] = res->start;
1022 mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
1023 } else {
1024 mcbsp->dma_data[0].filter_data = "tx";
1025 mcbsp->dma_data[1].filter_data = "rx";
1026 }
1027
1028 mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp,
1029 SNDRV_PCM_STREAM_PLAYBACK);
1030 mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp,
1031 SNDRV_PCM_STREAM_CAPTURE);
1032
1033 mcbsp->fclk = clk_get(&pdev->dev, "fck");
1034 if (IS_ERR(mcbsp->fclk)) {
1035 ret = PTR_ERR(mcbsp->fclk);
1036 dev_err(mcbsp->dev, "unable to get fck: %d\n", ret);
1037 return ret;
1038 }
1039
1040 mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
1041 if (mcbsp->pdata->buffer_size) {
1042 /*
1043 * Initially configure the maximum thresholds to a safe value.
1044 * The McBSP FIFO usage with these values should not go under
1045 * 16 locations.
1046 * If the whole FIFO without safety buffer is used, than there
1047 * is a possibility that the DMA will be not able to push the
1048 * new data on time, causing channel shifts in runtime.
1049 */
1050 mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
1051 mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
1052
1053 ret = sysfs_create_group(&mcbsp->dev->kobj,
1054 &additional_attr_group);
1055 if (ret) {
1056 dev_err(mcbsp->dev,
1057 "Unable to create additional controls\n");
1058 goto err_thres;
1059 }
1060 } else {
1061 mcbsp->max_tx_thres = -EINVAL;
1062 mcbsp->max_rx_thres = -EINVAL;
1063 }
1064
1065 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
1066 if (res) {
1067 ret = omap_st_add(mcbsp, res);
1068 if (ret) {
1069 dev_err(mcbsp->dev,
1070 "Unable to create sidetone controls\n");
1071 goto err_st;
1072 }
1073 }
1074
1075 return 0;
1076
1077err_st:
1078 if (mcbsp->pdata->buffer_size)
1079 sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
1080err_thres:
1081 clk_put(mcbsp->fclk);
1082 return ret;
1083}
1084
1085void omap_mcbsp_cleanup(struct omap_mcbsp *mcbsp)
1086{
1087 if (mcbsp->pdata->buffer_size)
1088 sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
1089
1090 if (mcbsp->st_data) {
1091 sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
1092 clk_put(mcbsp->st_data->mcbsp_iclk);
1093 }
1094}
diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/omap-mcbsp-priv.h
index 92472c6ef358..7865cda4bf0a 100644
--- a/sound/soc/omap/mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp-priv.h
@@ -1,28 +1,15 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * sound/soc/omap/mcbsp.h
3 *
4 * OMAP Multi-Channel Buffered Serial Port 3 * OMAP Multi-Channel Buffered Serial Port
5 * 4 *
6 * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com> 5 * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
7 * Peter Ujfalusi <peter.ujfalusi@ti.com> 6 * 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 */ 7 */
24#ifndef __ASOC_MCBSP_H 8
25#define __ASOC_MCBSP_H 9#ifndef __OMAP_MCBSP_PRIV_H__
10#define __OMAP_MCBSP_PRIV_H__
11
12#include <linux/platform_data/asoc-ti-mcbsp.h>
26 13
27#ifdef CONFIG_ARCH_OMAP1 14#ifdef CONFIG_ARCH_OMAP1
28#define mcbsp_omap1() 1 15#define mcbsp_omap1() 1
@@ -30,8 +17,6 @@
30#define mcbsp_omap1() 0 17#define mcbsp_omap1() 0
31#endif 18#endif
32 19
33#include <sound/dmaengine_pcm.h>
34
35/* McBSP register numbers. Register address offset = num * reg_step */ 20/* McBSP register numbers. Register address offset = num * reg_step */
36enum { 21enum {
37 /* Common registers */ 22 /* Common registers */
@@ -85,15 +70,6 @@ enum {
85 OMAP_MCBSP_REG_SSELCR, 70 OMAP_MCBSP_REG_SSELCR,
86}; 71};
87 72
88/* OMAP3 sidetone control registers */
89#define OMAP_ST_REG_REV 0x00
90#define OMAP_ST_REG_SYSCONFIG 0x10
91#define OMAP_ST_REG_IRQSTATUS 0x18
92#define OMAP_ST_REG_IRQENABLE 0x1C
93#define OMAP_ST_REG_SGAINCR 0x24
94#define OMAP_ST_REG_SFIRCR 0x28
95#define OMAP_ST_REG_SSELCR 0x2C
96
97/************************** McBSP SPCR1 bit definitions ***********************/ 73/************************** McBSP SPCR1 bit definitions ***********************/
98#define RRST BIT(0) 74#define RRST BIT(0)
99#define RRDY BIT(1) 75#define RRDY BIT(1)
@@ -202,24 +178,6 @@ enum {
202#define SIDLEMODE(value) (((value) & 0x3) << 3) 178#define SIDLEMODE(value) (((value) & 0x3) << 3)
203#define CLOCKACTIVITY(value) (((value) & 0x3) << 8) 179#define CLOCKACTIVITY(value) (((value) & 0x3) << 8)
204 180
205/********************** McBSP SSELCR bit definitions ***********************/
206#define SIDETONEEN BIT(10)
207
208/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/
209#define ST_AUTOIDLE BIT(0)
210
211/********************** McBSP Sidetone SGAINCR bit definitions *************/
212#define ST_CH0GAIN(value) ((value) & 0xffff) /* Bits 0:15 */
213#define ST_CH1GAIN(value) (((value) & 0xffff) << 16) /* Bits 16:31 */
214
215/********************** McBSP Sidetone SFIRCR bit definitions **************/
216#define ST_FIRCOEFF(value) ((value) & 0xffff) /* Bits 0:15 */
217
218/********************** McBSP Sidetone SSELCR bit definitions **************/
219#define ST_SIDETONEEN BIT(0)
220#define ST_COEFFWREN BIT(1)
221#define ST_COEFFWRDONE BIT(2)
222
223/********************** McBSP DMA operating modes **************************/ 181/********************** McBSP DMA operating modes **************************/
224#define MCBSP_DMA_MODE_ELEMENT 0 182#define MCBSP_DMA_MODE_ELEMENT 0
225#define MCBSP_DMA_MODE_THRESHOLD 1 183#define MCBSP_DMA_MODE_THRESHOLD 1
@@ -278,16 +236,7 @@ struct omap_mcbsp_reg_cfg {
278 u16 rccr; 236 u16 rccr;
279}; 237};
280 238
281struct omap_mcbsp_st_data { 239struct omap_mcbsp_st_data;
282 void __iomem *io_base_st;
283 struct clk *mcbsp_iclk;
284 bool running;
285 bool enabled;
286 s16 taps[128]; /* Sidetone filter coefficients */
287 int nr_taps; /* Number of filter coefficients in use */
288 s16 ch0gain;
289 s16 ch1gain;
290};
291 240
292struct omap_mcbsp { 241struct omap_mcbsp {
293 struct device *dev; 242 struct device *dev;
@@ -330,29 +279,46 @@ struct omap_mcbsp {
330 struct pm_qos_request pm_qos_req; 279 struct pm_qos_request pm_qos_req;
331}; 280};
332 281
333void omap_mcbsp_config(struct omap_mcbsp *mcbsp, 282static inline void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
334 const struct omap_mcbsp_reg_cfg *config); 283{
335void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold); 284 void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
336void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold); 285
337u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp); 286 if (mcbsp->pdata->reg_size == 2) {
338u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp); 287 ((u16 *)mcbsp->reg_cache)[reg] = (u16)val;
339int omap_mcbsp_get_dma_op_mode(struct omap_mcbsp *mcbsp); 288 writew_relaxed((u16)val, addr);
340int omap_mcbsp_request(struct omap_mcbsp *mcbsp); 289 } else {
341void omap_mcbsp_free(struct omap_mcbsp *mcbsp); 290 ((u32 *)mcbsp->reg_cache)[reg] = val;
342void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int stream); 291 writel_relaxed(val, addr);
343void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int stream); 292 }
344 293}
345/* McBSP functional clock source changing function */ 294
346int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id); 295static inline int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg,
296 bool from_cache)
297{
298 void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
299
300 if (mcbsp->pdata->reg_size == 2) {
301 return !from_cache ? readw_relaxed(addr) :
302 ((u16 *)mcbsp->reg_cache)[reg];
303 } else {
304 return !from_cache ? readl_relaxed(addr) :
305 ((u32 *)mcbsp->reg_cache)[reg];
306 }
307}
308
309#define MCBSP_READ(mcbsp, reg) \
310 omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0)
311#define MCBSP_WRITE(mcbsp, reg, val) \
312 omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val)
313#define MCBSP_READ_CACHE(mcbsp, reg) \
314 omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1)
315
347 316
348/* Sidetone specific API */ 317/* Sidetone specific API */
349int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain); 318int omap_mcbsp_st_init(struct platform_device *pdev);
350int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain); 319void omap_mcbsp_st_cleanup(struct platform_device *pdev);
351int omap_st_enable(struct omap_mcbsp *mcbsp);
352int omap_st_disable(struct omap_mcbsp *mcbsp);
353int omap_st_is_enabled(struct omap_mcbsp *mcbsp);
354 320
355int omap_mcbsp_init(struct platform_device *pdev); 321int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp);
356void omap_mcbsp_cleanup(struct omap_mcbsp *mcbsp); 322int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp);
357 323
358#endif /* __ASOC_MCBSP_H */ 324#endif /* __OMAP_MCBSP_PRIV_H__ */
diff --git a/sound/soc/omap/omap-mcbsp-st.c b/sound/soc/omap/omap-mcbsp-st.c
new file mode 100644
index 000000000000..1a3fe854e856
--- /dev/null
+++ b/sound/soc/omap/omap-mcbsp-st.c
@@ -0,0 +1,516 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * McBSP Sidetone support
4 *
5 * Copyright (C) 2004 Nokia Corporation
6 * Author: Samuel Ortiz <samuel.ortiz@nokia.com>
7 *
8 * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
9 * Peter Ujfalusi <peter.ujfalusi@ti.com>
10 */
11
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/device.h>
15#include <linux/platform_device.h>
16#include <linux/interrupt.h>
17#include <linux/err.h>
18#include <linux/clk.h>
19#include <linux/delay.h>
20#include <linux/io.h>
21#include <linux/slab.h>
22#include <linux/pm_runtime.h>
23
24#include "omap-mcbsp.h"
25#include "omap-mcbsp-priv.h"
26
27/* OMAP3 sidetone control registers */
28#define OMAP_ST_REG_REV 0x00
29#define OMAP_ST_REG_SYSCONFIG 0x10
30#define OMAP_ST_REG_IRQSTATUS 0x18
31#define OMAP_ST_REG_IRQENABLE 0x1C
32#define OMAP_ST_REG_SGAINCR 0x24
33#define OMAP_ST_REG_SFIRCR 0x28
34#define OMAP_ST_REG_SSELCR 0x2C
35
36/********************** McBSP SSELCR bit definitions ***********************/
37#define SIDETONEEN BIT(10)
38
39/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/
40#define ST_AUTOIDLE BIT(0)
41
42/********************** McBSP Sidetone SGAINCR bit definitions *************/
43#define ST_CH0GAIN(value) ((value) & 0xffff) /* Bits 0:15 */
44#define ST_CH1GAIN(value) (((value) & 0xffff) << 16) /* Bits 16:31 */
45
46/********************** McBSP Sidetone SFIRCR bit definitions **************/
47#define ST_FIRCOEFF(value) ((value) & 0xffff) /* Bits 0:15 */
48
49/********************** McBSP Sidetone SSELCR bit definitions **************/
50#define ST_SIDETONEEN BIT(0)
51#define ST_COEFFWREN BIT(1)
52#define ST_COEFFWRDONE BIT(2)
53
54struct omap_mcbsp_st_data {
55 void __iomem *io_base_st;
56 struct clk *mcbsp_iclk;
57 bool running;
58 bool enabled;
59 s16 taps[128]; /* Sidetone filter coefficients */
60 int nr_taps; /* Number of filter coefficients in use */
61 s16 ch0gain;
62 s16 ch1gain;
63};
64
65static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
66{
67 writel_relaxed(val, mcbsp->st_data->io_base_st + reg);
68}
69
70static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
71{
72 return readl_relaxed(mcbsp->st_data->io_base_st + reg);
73}
74
75#define MCBSP_ST_READ(mcbsp, reg) omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
76#define MCBSP_ST_WRITE(mcbsp, reg, val) \
77 omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val)
78
79static void omap_mcbsp_st_on(struct omap_mcbsp *mcbsp)
80{
81 unsigned int w;
82
83 if (mcbsp->pdata->force_ick_on)
84 mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, true);
85
86 /* Disable Sidetone clock auto-gating for normal operation */
87 w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
88 MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
89
90 /* Enable McBSP Sidetone */
91 w = MCBSP_READ(mcbsp, SSELCR);
92 MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
93
94 /* Enable Sidetone from Sidetone Core */
95 w = MCBSP_ST_READ(mcbsp, SSELCR);
96 MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
97}
98
99static void omap_mcbsp_st_off(struct omap_mcbsp *mcbsp)
100{
101 unsigned int w;
102
103 w = MCBSP_ST_READ(mcbsp, SSELCR);
104 MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
105
106 w = MCBSP_READ(mcbsp, SSELCR);
107 MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
108
109 /* Enable Sidetone clock auto-gating to reduce power consumption */
110 w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
111 MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE);
112
113 if (mcbsp->pdata->force_ick_on)
114 mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, false);
115}
116
117static void omap_mcbsp_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
118{
119 u16 val, i;
120
121 val = MCBSP_ST_READ(mcbsp, SSELCR);
122
123 if (val & ST_COEFFWREN)
124 MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
125
126 MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN);
127
128 for (i = 0; i < 128; i++)
129 MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]);
130
131 i = 0;
132
133 val = MCBSP_ST_READ(mcbsp, SSELCR);
134 while (!(val & ST_COEFFWRDONE) && (++i < 1000))
135 val = MCBSP_ST_READ(mcbsp, SSELCR);
136
137 MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
138
139 if (i == 1000)
140 dev_err(mcbsp->dev, "McBSP FIR load error!\n");
141}
142
143static void omap_mcbsp_st_chgain(struct omap_mcbsp *mcbsp)
144{
145 u16 w;
146 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
147
148 w = MCBSP_ST_READ(mcbsp, SSELCR);
149
150 MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) |
151 ST_CH1GAIN(st_data->ch1gain));
152}
153
154static int omap_mcbsp_st_set_chgain(struct omap_mcbsp *mcbsp, int channel,
155 s16 chgain)
156{
157 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
158 int ret = 0;
159
160 if (!st_data)
161 return -ENOENT;
162
163 spin_lock_irq(&mcbsp->lock);
164 if (channel == 0)
165 st_data->ch0gain = chgain;
166 else if (channel == 1)
167 st_data->ch1gain = chgain;
168 else
169 ret = -EINVAL;
170
171 if (st_data->enabled)
172 omap_mcbsp_st_chgain(mcbsp);
173 spin_unlock_irq(&mcbsp->lock);
174
175 return ret;
176}
177
178static int omap_mcbsp_st_get_chgain(struct omap_mcbsp *mcbsp, int channel,
179 s16 *chgain)
180{
181 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
182 int ret = 0;
183
184 if (!st_data)
185 return -ENOENT;
186
187 spin_lock_irq(&mcbsp->lock);
188 if (channel == 0)
189 *chgain = st_data->ch0gain;
190 else if (channel == 1)
191 *chgain = st_data->ch1gain;
192 else
193 ret = -EINVAL;
194 spin_unlock_irq(&mcbsp->lock);
195
196 return ret;
197}
198
199static int omap_mcbsp_st_enable(struct omap_mcbsp *mcbsp)
200{
201 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
202
203 if (!st_data)
204 return -ENODEV;
205
206 spin_lock_irq(&mcbsp->lock);
207 st_data->enabled = 1;
208 omap_mcbsp_st_start(mcbsp);
209 spin_unlock_irq(&mcbsp->lock);
210
211 return 0;
212}
213
214static int omap_mcbsp_st_disable(struct omap_mcbsp *mcbsp)
215{
216 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
217 int ret = 0;
218
219 if (!st_data)
220 return -ENODEV;
221
222 spin_lock_irq(&mcbsp->lock);
223 omap_mcbsp_st_stop(mcbsp);
224 st_data->enabled = 0;
225 spin_unlock_irq(&mcbsp->lock);
226
227 return ret;
228}
229
230static int omap_mcbsp_st_is_enabled(struct omap_mcbsp *mcbsp)
231{
232 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
233
234 if (!st_data)
235 return -ENODEV;
236
237 return st_data->enabled;
238}
239
240static ssize_t st_taps_show(struct device *dev,
241 struct device_attribute *attr, char *buf)
242{
243 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
244 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
245 ssize_t status = 0;
246 int i;
247
248 spin_lock_irq(&mcbsp->lock);
249 for (i = 0; i < st_data->nr_taps; i++)
250 status += sprintf(&buf[status], (i ? ", %d" : "%d"),
251 st_data->taps[i]);
252 if (i)
253 status += sprintf(&buf[status], "\n");
254 spin_unlock_irq(&mcbsp->lock);
255
256 return status;
257}
258
259static ssize_t st_taps_store(struct device *dev,
260 struct device_attribute *attr,
261 const char *buf, size_t size)
262{
263 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
264 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
265 int val, tmp, status, i = 0;
266
267 spin_lock_irq(&mcbsp->lock);
268 memset(st_data->taps, 0, sizeof(st_data->taps));
269 st_data->nr_taps = 0;
270
271 do {
272 status = sscanf(buf, "%d%n", &val, &tmp);
273 if (status < 0 || status == 0) {
274 size = -EINVAL;
275 goto out;
276 }
277 if (val < -32768 || val > 32767) {
278 size = -EINVAL;
279 goto out;
280 }
281 st_data->taps[i++] = val;
282 buf += tmp;
283 if (*buf != ',')
284 break;
285 buf++;
286 } while (1);
287
288 st_data->nr_taps = i;
289
290out:
291 spin_unlock_irq(&mcbsp->lock);
292
293 return size;
294}
295
296static DEVICE_ATTR_RW(st_taps);
297
298static const struct attribute *sidetone_attrs[] = {
299 &dev_attr_st_taps.attr,
300 NULL,
301};
302
303static const struct attribute_group sidetone_attr_group = {
304 .attrs = (struct attribute **)sidetone_attrs,
305};
306
307int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp)
308{
309 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
310
311 if (st_data->enabled && !st_data->running) {
312 omap_mcbsp_st_fir_write(mcbsp, st_data->taps);
313 omap_mcbsp_st_chgain(mcbsp);
314
315 if (!mcbsp->free) {
316 omap_mcbsp_st_on(mcbsp);
317 st_data->running = 1;
318 }
319 }
320
321 return 0;
322}
323
324int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp)
325{
326 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
327
328 if (st_data->running) {
329 if (!mcbsp->free) {
330 omap_mcbsp_st_off(mcbsp);
331 st_data->running = 0;
332 }
333 }
334
335 return 0;
336}
337
338int omap_mcbsp_st_init(struct platform_device *pdev)
339{
340 struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
341 struct omap_mcbsp_st_data *st_data;
342 struct resource *res;
343 int ret;
344
345 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
346 if (!res)
347 return 0;
348
349 st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL);
350 if (!st_data)
351 return -ENOMEM;
352
353 st_data->mcbsp_iclk = clk_get(mcbsp->dev, "ick");
354 if (IS_ERR(st_data->mcbsp_iclk)) {
355 dev_warn(mcbsp->dev,
356 "Failed to get ick, sidetone might be broken\n");
357 st_data->mcbsp_iclk = NULL;
358 }
359
360 st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start,
361 resource_size(res));
362 if (!st_data->io_base_st)
363 return -ENOMEM;
364
365 ret = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
366 if (ret)
367 return ret;
368
369 mcbsp->st_data = st_data;
370
371 return 0;
372}
373
374void omap_mcbsp_st_cleanup(struct platform_device *pdev)
375{
376 struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
377
378 if (mcbsp->st_data) {
379 sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
380 clk_put(mcbsp->st_data->mcbsp_iclk);
381 }
382}
383
384static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
385 struct snd_ctl_elem_info *uinfo)
386{
387 struct soc_mixer_control *mc =
388 (struct soc_mixer_control *)kcontrol->private_value;
389 int max = mc->max;
390 int min = mc->min;
391
392 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
393 uinfo->count = 1;
394 uinfo->value.integer.min = min;
395 uinfo->value.integer.max = max;
396 return 0;
397}
398
399#define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel) \
400static int \
401omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \
402 struct snd_ctl_elem_value *uc) \
403{ \
404 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
405 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
406 struct soc_mixer_control *mc = \
407 (struct soc_mixer_control *)kc->private_value; \
408 int max = mc->max; \
409 int min = mc->min; \
410 int val = uc->value.integer.value[0]; \
411 \
412 if (val < min || val > max) \
413 return -EINVAL; \
414 \
415 /* OMAP McBSP implementation uses index values 0..4 */ \
416 return omap_mcbsp_st_set_chgain(mcbsp, channel, val); \
417} \
418 \
419static int \
420omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \
421 struct snd_ctl_elem_value *uc) \
422{ \
423 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
424 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
425 s16 chgain; \
426 \
427 if (omap_mcbsp_st_get_chgain(mcbsp, channel, &chgain)) \
428 return -EAGAIN; \
429 \
430 uc->value.integer.value[0] = chgain; \
431 return 0; \
432}
433
434OMAP_MCBSP_ST_CHANNEL_VOLUME(0)
435OMAP_MCBSP_ST_CHANNEL_VOLUME(1)
436
437static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
438 struct snd_ctl_elem_value *ucontrol)
439{
440 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
441 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
442 u8 value = ucontrol->value.integer.value[0];
443
444 if (value == omap_mcbsp_st_is_enabled(mcbsp))
445 return 0;
446
447 if (value)
448 omap_mcbsp_st_enable(mcbsp);
449 else
450 omap_mcbsp_st_disable(mcbsp);
451
452 return 1;
453}
454
455static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
456 struct snd_ctl_elem_value *ucontrol)
457{
458 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
459 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
460
461 ucontrol->value.integer.value[0] = omap_mcbsp_st_is_enabled(mcbsp);
462 return 0;
463}
464
465#define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \
466 xhandler_get, xhandler_put) \
467{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
468 .info = omap_mcbsp_st_info_volsw, \
469 .get = xhandler_get, .put = xhandler_put, \
470 .private_value = (unsigned long)&(struct soc_mixer_control) \
471 {.min = xmin, .max = xmax} }
472
473#define OMAP_MCBSP_ST_CONTROLS(port) \
474static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \
475SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0, \
476 omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), \
477OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \
478 -32768, 32767, \
479 omap_mcbsp_get_st_ch0_volume, \
480 omap_mcbsp_set_st_ch0_volume), \
481OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \
482 -32768, 32767, \
483 omap_mcbsp_get_st_ch1_volume, \
484 omap_mcbsp_set_st_ch1_volume), \
485}
486
487OMAP_MCBSP_ST_CONTROLS(2);
488OMAP_MCBSP_ST_CONTROLS(3);
489
490int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id)
491{
492 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
493 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
494
495 if (!mcbsp->st_data) {
496 dev_warn(mcbsp->dev, "No sidetone data for port\n");
497 return 0;
498 }
499
500 switch (port_id) {
501 case 2: /* McBSP 2 */
502 return snd_soc_add_dai_controls(cpu_dai,
503 omap_mcbsp2_st_controls,
504 ARRAY_SIZE(omap_mcbsp2_st_controls));
505 case 3: /* McBSP 3 */
506 return snd_soc_add_dai_controls(cpu_dai,
507 omap_mcbsp3_st_controls,
508 ARRAY_SIZE(omap_mcbsp3_st_controls));
509 default:
510 dev_err(mcbsp->dev, "Port %d not supported\n", port_id);
511 break;
512 }
513
514 return -EINVAL;
515}
516EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 69a6b8ad6d42..e48fad11a0cc 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -35,21 +35,12 @@
35#include <sound/soc.h> 35#include <sound/soc.h>
36#include <sound/dmaengine_pcm.h> 36#include <sound/dmaengine_pcm.h>
37 37
38#include <linux/platform_data/asoc-ti-mcbsp.h> 38#include "omap-mcbsp-priv.h"
39#include "mcbsp.h"
40#include "omap-mcbsp.h" 39#include "omap-mcbsp.h"
41#include "sdma-pcm.h" 40#include "sdma-pcm.h"
42 41
43#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000) 42#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000)
44 43
45#define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \
46 xhandler_get, xhandler_put) \
47{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
48 .info = omap_mcbsp_st_info_volsw, \
49 .get = xhandler_get, .put = xhandler_put, \
50 .private_value = (unsigned long) &(struct soc_mixer_control) \
51 {.min = xmin, .max = xmax} }
52
53enum { 44enum {
54 OMAP_MCBSP_WORD_8 = 0, 45 OMAP_MCBSP_WORD_8 = 0,
55 OMAP_MCBSP_WORD_12, 46 OMAP_MCBSP_WORD_12,
@@ -59,6 +50,702 @@ enum {
59 OMAP_MCBSP_WORD_32, 50 OMAP_MCBSP_WORD_32,
60}; 51};
61 52
53static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp)
54{
55 dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id);
56 dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n", MCBSP_READ(mcbsp, DRR2));
57 dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n", MCBSP_READ(mcbsp, DRR1));
58 dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n", MCBSP_READ(mcbsp, DXR2));
59 dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n", MCBSP_READ(mcbsp, DXR1));
60 dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n", MCBSP_READ(mcbsp, SPCR2));
61 dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n", MCBSP_READ(mcbsp, SPCR1));
62 dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n", MCBSP_READ(mcbsp, RCR2));
63 dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n", MCBSP_READ(mcbsp, RCR1));
64 dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n", MCBSP_READ(mcbsp, XCR2));
65 dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n", MCBSP_READ(mcbsp, XCR1));
66 dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n", MCBSP_READ(mcbsp, SRGR2));
67 dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n", MCBSP_READ(mcbsp, SRGR1));
68 dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n", MCBSP_READ(mcbsp, PCR0));
69 dev_dbg(mcbsp->dev, "***********************\n");
70}
71
72static int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id)
73{
74 struct clk *fck_src;
75 const char *src;
76 int r;
77
78 if (fck_src_id == MCBSP_CLKS_PAD_SRC)
79 src = "pad_fck";
80 else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
81 src = "prcm_fck";
82 else
83 return -EINVAL;
84
85 fck_src = clk_get(mcbsp->dev, src);
86 if (IS_ERR(fck_src)) {
87 dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src);
88 return -EINVAL;
89 }
90
91 pm_runtime_put_sync(mcbsp->dev);
92
93 r = clk_set_parent(mcbsp->fclk, fck_src);
94 if (r) {
95 dev_err(mcbsp->dev, "CLKS: could not clk_set_parent() to %s\n",
96 src);
97 clk_put(fck_src);
98 return r;
99 }
100
101 pm_runtime_get_sync(mcbsp->dev);
102
103 clk_put(fck_src);
104
105 return 0;
106}
107
108static irqreturn_t omap_mcbsp_irq_handler(int irq, void *data)
109{
110 struct omap_mcbsp *mcbsp = data;
111 u16 irqst;
112
113 irqst = MCBSP_READ(mcbsp, IRQST);
114 dev_dbg(mcbsp->dev, "IRQ callback : 0x%x\n", irqst);
115
116 if (irqst & RSYNCERREN)
117 dev_err(mcbsp->dev, "RX Frame Sync Error!\n");
118 if (irqst & RFSREN)
119 dev_dbg(mcbsp->dev, "RX Frame Sync\n");
120 if (irqst & REOFEN)
121 dev_dbg(mcbsp->dev, "RX End Of Frame\n");
122 if (irqst & RRDYEN)
123 dev_dbg(mcbsp->dev, "RX Buffer Threshold Reached\n");
124 if (irqst & RUNDFLEN)
125 dev_err(mcbsp->dev, "RX Buffer Underflow!\n");
126 if (irqst & ROVFLEN)
127 dev_err(mcbsp->dev, "RX Buffer Overflow!\n");
128
129 if (irqst & XSYNCERREN)
130 dev_err(mcbsp->dev, "TX Frame Sync Error!\n");
131 if (irqst & XFSXEN)
132 dev_dbg(mcbsp->dev, "TX Frame Sync\n");
133 if (irqst & XEOFEN)
134 dev_dbg(mcbsp->dev, "TX End Of Frame\n");
135 if (irqst & XRDYEN)
136 dev_dbg(mcbsp->dev, "TX Buffer threshold Reached\n");
137 if (irqst & XUNDFLEN)
138 dev_err(mcbsp->dev, "TX Buffer Underflow!\n");
139 if (irqst & XOVFLEN)
140 dev_err(mcbsp->dev, "TX Buffer Overflow!\n");
141 if (irqst & XEMPTYEOFEN)
142 dev_dbg(mcbsp->dev, "TX Buffer empty at end of frame\n");
143
144 MCBSP_WRITE(mcbsp, IRQST, irqst);
145
146 return IRQ_HANDLED;
147}
148
149static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *data)
150{
151 struct omap_mcbsp *mcbsp = data;
152 u16 irqst_spcr2;
153
154 irqst_spcr2 = MCBSP_READ(mcbsp, SPCR2);
155 dev_dbg(mcbsp->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
156
157 if (irqst_spcr2 & XSYNC_ERR) {
158 dev_err(mcbsp->dev, "TX Frame Sync Error! : 0x%x\n",
159 irqst_spcr2);
160 /* Writing zero to XSYNC_ERR clears the IRQ */
161 MCBSP_WRITE(mcbsp, SPCR2, MCBSP_READ_CACHE(mcbsp, SPCR2));
162 }
163
164 return IRQ_HANDLED;
165}
166
167static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *data)
168{
169 struct omap_mcbsp *mcbsp = data;
170 u16 irqst_spcr1;
171
172 irqst_spcr1 = MCBSP_READ(mcbsp, SPCR1);
173 dev_dbg(mcbsp->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
174
175 if (irqst_spcr1 & RSYNC_ERR) {
176 dev_err(mcbsp->dev, "RX Frame Sync Error! : 0x%x\n",
177 irqst_spcr1);
178 /* Writing zero to RSYNC_ERR clears the IRQ */
179 MCBSP_WRITE(mcbsp, SPCR1, MCBSP_READ_CACHE(mcbsp, SPCR1));
180 }
181
182 return IRQ_HANDLED;
183}
184
185/*
186 * omap_mcbsp_config simply write a config to the
187 * appropriate McBSP.
188 * You either call this function or set the McBSP registers
189 * by yourself before calling omap_mcbsp_start().
190 */
191static void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
192 const struct omap_mcbsp_reg_cfg *config)
193{
194 dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n",
195 mcbsp->id, mcbsp->phys_base);
196
197 /* We write the given config */
198 MCBSP_WRITE(mcbsp, SPCR2, config->spcr2);
199 MCBSP_WRITE(mcbsp, SPCR1, config->spcr1);
200 MCBSP_WRITE(mcbsp, RCR2, config->rcr2);
201 MCBSP_WRITE(mcbsp, RCR1, config->rcr1);
202 MCBSP_WRITE(mcbsp, XCR2, config->xcr2);
203 MCBSP_WRITE(mcbsp, XCR1, config->xcr1);
204 MCBSP_WRITE(mcbsp, SRGR2, config->srgr2);
205 MCBSP_WRITE(mcbsp, SRGR1, config->srgr1);
206 MCBSP_WRITE(mcbsp, MCR2, config->mcr2);
207 MCBSP_WRITE(mcbsp, MCR1, config->mcr1);
208 MCBSP_WRITE(mcbsp, PCR0, config->pcr0);
209 if (mcbsp->pdata->has_ccr) {
210 MCBSP_WRITE(mcbsp, XCCR, config->xccr);
211 MCBSP_WRITE(mcbsp, RCCR, config->rccr);
212 }
213 /* Enable wakeup behavior */
214 if (mcbsp->pdata->has_wakeup)
215 MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
216
217 /* Enable TX/RX sync error interrupts by default */
218 if (mcbsp->irq)
219 MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN |
220 RUNDFLEN | ROVFLEN | XUNDFLEN | XOVFLEN);
221}
222
223/**
224 * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register
225 * @mcbsp: omap_mcbsp struct for the McBSP instance
226 * @stream: Stream direction (playback/capture)
227 *
228 * Returns the address of mcbsp data transmit register or data receive register
229 * to be used by DMA for transferring/receiving data
230 */
231static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp,
232 unsigned int stream)
233{
234 int data_reg;
235
236 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
237 if (mcbsp->pdata->reg_size == 2)
238 data_reg = OMAP_MCBSP_REG_DXR1;
239 else
240 data_reg = OMAP_MCBSP_REG_DXR;
241 } else {
242 if (mcbsp->pdata->reg_size == 2)
243 data_reg = OMAP_MCBSP_REG_DRR1;
244 else
245 data_reg = OMAP_MCBSP_REG_DRR;
246 }
247
248 return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step;
249}
250
251/*
252 * omap_mcbsp_set_rx_threshold configures the transmit threshold in words.
253 * The threshold parameter is 1 based, and it is converted (threshold - 1)
254 * for the THRSH2 register.
255 */
256static void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
257{
258 if (threshold && threshold <= mcbsp->max_tx_thres)
259 MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
260}
261
262/*
263 * omap_mcbsp_set_rx_threshold configures the receive threshold in words.
264 * The threshold parameter is 1 based, and it is converted (threshold - 1)
265 * for the THRSH1 register.
266 */
267static void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
268{
269 if (threshold && threshold <= mcbsp->max_rx_thres)
270 MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
271}
272
273/*
274 * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
275 */
276static u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp)
277{
278 u16 buffstat;
279
280 /* Returns the number of free locations in the buffer */
281 buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
282
283 /* Number of slots are different in McBSP ports */
284 return mcbsp->pdata->buffer_size - buffstat;
285}
286
287/*
288 * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO
289 * to reach the threshold value (when the DMA will be triggered to read it)
290 */
291static u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp)
292{
293 u16 buffstat, threshold;
294
295 /* Returns the number of used locations in the buffer */
296 buffstat = MCBSP_READ(mcbsp, RBUFFSTAT);
297 /* RX threshold */
298 threshold = MCBSP_READ(mcbsp, THRSH1);
299
300 /* Return the number of location till we reach the threshold limit */
301 if (threshold <= buffstat)
302 return 0;
303 else
304 return threshold - buffstat;
305}
306
307static int omap_mcbsp_request(struct omap_mcbsp *mcbsp)
308{
309 void *reg_cache;
310 int err;
311
312 reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL);
313 if (!reg_cache)
314 return -ENOMEM;
315
316 spin_lock(&mcbsp->lock);
317 if (!mcbsp->free) {
318 dev_err(mcbsp->dev, "McBSP%d is currently in use\n", mcbsp->id);
319 err = -EBUSY;
320 goto err_kfree;
321 }
322
323 mcbsp->free = false;
324 mcbsp->reg_cache = reg_cache;
325 spin_unlock(&mcbsp->lock);
326
327 if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request)
328 mcbsp->pdata->ops->request(mcbsp->id - 1);
329
330 /*
331 * Make sure that transmitter, receiver and sample-rate generator are
332 * not running before activating IRQs.
333 */
334 MCBSP_WRITE(mcbsp, SPCR1, 0);
335 MCBSP_WRITE(mcbsp, SPCR2, 0);
336
337 if (mcbsp->irq) {
338 err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0,
339 "McBSP", (void *)mcbsp);
340 if (err != 0) {
341 dev_err(mcbsp->dev, "Unable to request IRQ\n");
342 goto err_clk_disable;
343 }
344 } else {
345 err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0,
346 "McBSP TX", (void *)mcbsp);
347 if (err != 0) {
348 dev_err(mcbsp->dev, "Unable to request TX IRQ\n");
349 goto err_clk_disable;
350 }
351
352 err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0,
353 "McBSP RX", (void *)mcbsp);
354 if (err != 0) {
355 dev_err(mcbsp->dev, "Unable to request RX IRQ\n");
356 goto err_free_irq;
357 }
358 }
359
360 return 0;
361err_free_irq:
362 free_irq(mcbsp->tx_irq, (void *)mcbsp);
363err_clk_disable:
364 if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
365 mcbsp->pdata->ops->free(mcbsp->id - 1);
366
367 /* Disable wakeup behavior */
368 if (mcbsp->pdata->has_wakeup)
369 MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
370
371 spin_lock(&mcbsp->lock);
372 mcbsp->free = true;
373 mcbsp->reg_cache = NULL;
374err_kfree:
375 spin_unlock(&mcbsp->lock);
376 kfree(reg_cache);
377
378 return err;
379}
380
381static void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
382{
383 void *reg_cache;
384
385 if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
386 mcbsp->pdata->ops->free(mcbsp->id - 1);
387
388 /* Disable wakeup behavior */
389 if (mcbsp->pdata->has_wakeup)
390 MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
391
392 /* Disable interrupt requests */
393 if (mcbsp->irq)
394 MCBSP_WRITE(mcbsp, IRQEN, 0);
395
396 if (mcbsp->irq) {
397 free_irq(mcbsp->irq, (void *)mcbsp);
398 } else {
399 free_irq(mcbsp->rx_irq, (void *)mcbsp);
400 free_irq(mcbsp->tx_irq, (void *)mcbsp);
401 }
402
403 reg_cache = mcbsp->reg_cache;
404
405 /*
406 * Select CLKS source from internal source unconditionally before
407 * marking the McBSP port as free.
408 * If the external clock source via MCBSP_CLKS pin has been selected the
409 * system will refuse to enter idle if the CLKS pin source is not reset
410 * back to internal source.
411 */
412 if (!mcbsp_omap1())
413 omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC);
414
415 spin_lock(&mcbsp->lock);
416 if (mcbsp->free)
417 dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id);
418 else
419 mcbsp->free = true;
420 mcbsp->reg_cache = NULL;
421 spin_unlock(&mcbsp->lock);
422
423 kfree(reg_cache);
424}
425
426/*
427 * Here we start the McBSP, by enabling transmitter, receiver or both.
428 * If no transmitter or receiver is active prior calling, then sample-rate
429 * generator and frame sync are started.
430 */
431static void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int stream)
432{
433 int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);
434 int rx = !tx;
435 int enable_srg = 0;
436 u16 w;
437
438 if (mcbsp->st_data)
439 omap_mcbsp_st_start(mcbsp);
440
441 /* Only enable SRG, if McBSP is master */
442 w = MCBSP_READ_CACHE(mcbsp, PCR0);
443 if (w & (FSXM | FSRM | CLKXM | CLKRM))
444 enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
445 MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
446
447 if (enable_srg) {
448 /* Start the sample generator */
449 w = MCBSP_READ_CACHE(mcbsp, SPCR2);
450 MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6));
451 }
452
453 /* Enable transmitter and receiver */
454 tx &= 1;
455 w = MCBSP_READ_CACHE(mcbsp, SPCR2);
456 MCBSP_WRITE(mcbsp, SPCR2, w | tx);
457
458 rx &= 1;
459 w = MCBSP_READ_CACHE(mcbsp, SPCR1);
460 MCBSP_WRITE(mcbsp, SPCR1, w | rx);
461
462 /*
463 * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec
464 * REVISIT: 100us may give enough time for two CLKSRG, however
465 * due to some unknown PM related, clock gating etc. reason it
466 * is now at 500us.
467 */
468 udelay(500);
469
470 if (enable_srg) {
471 /* Start frame sync */
472 w = MCBSP_READ_CACHE(mcbsp, SPCR2);
473 MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
474 }
475
476 if (mcbsp->pdata->has_ccr) {
477 /* Release the transmitter and receiver */
478 w = MCBSP_READ_CACHE(mcbsp, XCCR);
479 w &= ~(tx ? XDISABLE : 0);
480 MCBSP_WRITE(mcbsp, XCCR, w);
481 w = MCBSP_READ_CACHE(mcbsp, RCCR);
482 w &= ~(rx ? RDISABLE : 0);
483 MCBSP_WRITE(mcbsp, RCCR, w);
484 }
485
486 /* Dump McBSP Regs */
487 omap_mcbsp_dump_reg(mcbsp);
488}
489
490static void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int stream)
491{
492 int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);
493 int rx = !tx;
494 int idle;
495 u16 w;
496
497 /* Reset transmitter */
498 tx &= 1;
499 if (mcbsp->pdata->has_ccr) {
500 w = MCBSP_READ_CACHE(mcbsp, XCCR);
501 w |= (tx ? XDISABLE : 0);
502 MCBSP_WRITE(mcbsp, XCCR, w);
503 }
504 w = MCBSP_READ_CACHE(mcbsp, SPCR2);
505 MCBSP_WRITE(mcbsp, SPCR2, w & ~tx);
506
507 /* Reset receiver */
508 rx &= 1;
509 if (mcbsp->pdata->has_ccr) {
510 w = MCBSP_READ_CACHE(mcbsp, RCCR);
511 w |= (rx ? RDISABLE : 0);
512 MCBSP_WRITE(mcbsp, RCCR, w);
513 }
514 w = MCBSP_READ_CACHE(mcbsp, SPCR1);
515 MCBSP_WRITE(mcbsp, SPCR1, w & ~rx);
516
517 idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
518 MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
519
520 if (idle) {
521 /* Reset the sample rate generator */
522 w = MCBSP_READ_CACHE(mcbsp, SPCR2);
523 MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6));
524 }
525
526 if (mcbsp->st_data)
527 omap_mcbsp_st_stop(mcbsp);
528}
529
530#define max_thres(m) (mcbsp->pdata->buffer_size)
531#define valid_threshold(m, val) ((val) <= max_thres(m))
532#define THRESHOLD_PROP_BUILDER(prop) \
533static ssize_t prop##_show(struct device *dev, \
534 struct device_attribute *attr, char *buf) \
535{ \
536 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
537 \
538 return sprintf(buf, "%u\n", mcbsp->prop); \
539} \
540 \
541static ssize_t prop##_store(struct device *dev, \
542 struct device_attribute *attr, \
543 const char *buf, size_t size) \
544{ \
545 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
546 unsigned long val; \
547 int status; \
548 \
549 status = kstrtoul(buf, 0, &val); \
550 if (status) \
551 return status; \
552 \
553 if (!valid_threshold(mcbsp, val)) \
554 return -EDOM; \
555 \
556 mcbsp->prop = val; \
557 return size; \
558} \
559 \
560static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store)
561
562THRESHOLD_PROP_BUILDER(max_tx_thres);
563THRESHOLD_PROP_BUILDER(max_rx_thres);
564
565static const char * const dma_op_modes[] = {
566 "element", "threshold",
567};
568
569static ssize_t dma_op_mode_show(struct device *dev,
570 struct device_attribute *attr, char *buf)
571{
572 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
573 int dma_op_mode, i = 0;
574 ssize_t len = 0;
575 const char * const *s;
576
577 dma_op_mode = mcbsp->dma_op_mode;
578
579 for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) {
580 if (dma_op_mode == i)
581 len += sprintf(buf + len, "[%s] ", *s);
582 else
583 len += sprintf(buf + len, "%s ", *s);
584 }
585 len += sprintf(buf + len, "\n");
586
587 return len;
588}
589
590static ssize_t dma_op_mode_store(struct device *dev,
591 struct device_attribute *attr, const char *buf,
592 size_t size)
593{
594 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
595 int i;
596
597 i = sysfs_match_string(dma_op_modes, buf);
598 if (i < 0)
599 return i;
600
601 spin_lock_irq(&mcbsp->lock);
602 if (!mcbsp->free) {
603 size = -EBUSY;
604 goto unlock;
605 }
606 mcbsp->dma_op_mode = i;
607
608unlock:
609 spin_unlock_irq(&mcbsp->lock);
610
611 return size;
612}
613
614static DEVICE_ATTR_RW(dma_op_mode);
615
616static const struct attribute *additional_attrs[] = {
617 &dev_attr_max_tx_thres.attr,
618 &dev_attr_max_rx_thres.attr,
619 &dev_attr_dma_op_mode.attr,
620 NULL,
621};
622
623static const struct attribute_group additional_attr_group = {
624 .attrs = (struct attribute **)additional_attrs,
625};
626
627/*
628 * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
629 * 730 has only 2 McBSP, and both of them are MPU peripherals.
630 */
631static int omap_mcbsp_init(struct platform_device *pdev)
632{
633 struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
634 struct resource *res;
635 int ret = 0;
636
637 spin_lock_init(&mcbsp->lock);
638 mcbsp->free = true;
639
640 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
641 if (!res)
642 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
643
644 mcbsp->io_base = devm_ioremap_resource(&pdev->dev, res);
645 if (IS_ERR(mcbsp->io_base))
646 return PTR_ERR(mcbsp->io_base);
647
648 mcbsp->phys_base = res->start;
649 mcbsp->reg_cache_size = resource_size(res);
650
651 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
652 if (!res)
653 mcbsp->phys_dma_base = mcbsp->phys_base;
654 else
655 mcbsp->phys_dma_base = res->start;
656
657 /*
658 * OMAP1, 2 uses two interrupt lines: TX, RX
659 * OMAP2430, OMAP3 SoC have combined IRQ line as well.
660 * OMAP4 and newer SoC only have the combined IRQ line.
661 * Use the combined IRQ if available since it gives better debugging
662 * possibilities.
663 */
664 mcbsp->irq = platform_get_irq_byname(pdev, "common");
665 if (mcbsp->irq == -ENXIO) {
666 mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
667
668 if (mcbsp->tx_irq == -ENXIO) {
669 mcbsp->irq = platform_get_irq(pdev, 0);
670 mcbsp->tx_irq = 0;
671 } else {
672 mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
673 mcbsp->irq = 0;
674 }
675 }
676
677 if (!pdev->dev.of_node) {
678 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
679 if (!res) {
680 dev_err(&pdev->dev, "invalid tx DMA channel\n");
681 return -ENODEV;
682 }
683 mcbsp->dma_req[0] = res->start;
684 mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
685
686 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
687 if (!res) {
688 dev_err(&pdev->dev, "invalid rx DMA channel\n");
689 return -ENODEV;
690 }
691 mcbsp->dma_req[1] = res->start;
692 mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
693 } else {
694 mcbsp->dma_data[0].filter_data = "tx";
695 mcbsp->dma_data[1].filter_data = "rx";
696 }
697
698 mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp,
699 SNDRV_PCM_STREAM_PLAYBACK);
700 mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp,
701 SNDRV_PCM_STREAM_CAPTURE);
702
703 mcbsp->fclk = clk_get(&pdev->dev, "fck");
704 if (IS_ERR(mcbsp->fclk)) {
705 ret = PTR_ERR(mcbsp->fclk);
706 dev_err(mcbsp->dev, "unable to get fck: %d\n", ret);
707 return ret;
708 }
709
710 mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
711 if (mcbsp->pdata->buffer_size) {
712 /*
713 * Initially configure the maximum thresholds to a safe value.
714 * The McBSP FIFO usage with these values should not go under
715 * 16 locations.
716 * If the whole FIFO without safety buffer is used, than there
717 * is a possibility that the DMA will be not able to push the
718 * new data on time, causing channel shifts in runtime.
719 */
720 mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
721 mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
722
723 ret = sysfs_create_group(&mcbsp->dev->kobj,
724 &additional_attr_group);
725 if (ret) {
726 dev_err(mcbsp->dev,
727 "Unable to create additional controls\n");
728 goto err_thres;
729 }
730 } else {
731 mcbsp->max_tx_thres = -EINVAL;
732 mcbsp->max_rx_thres = -EINVAL;
733 }
734
735 ret = omap_mcbsp_st_init(pdev);
736 if (ret)
737 goto err_st;
738
739 return 0;
740
741err_st:
742 if (mcbsp->pdata->buffer_size)
743 sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
744err_thres:
745 clk_put(mcbsp->fclk);
746 return ret;
747}
748
62/* 749/*
63 * Stream DMA parameters. DMA request line and port address are set runtime 750 * Stream DMA parameters. DMA request line and port address are set runtime
64 * since they are different between OMAP1 and later OMAPs 751 * since they are different between OMAP1 and later OMAPs
@@ -656,132 +1343,6 @@ static const struct snd_soc_component_driver omap_mcbsp_component = {
656 .name = "omap-mcbsp", 1343 .name = "omap-mcbsp",
657}; 1344};
658 1345
659static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
660 struct snd_ctl_elem_info *uinfo)
661{
662 struct soc_mixer_control *mc =
663 (struct soc_mixer_control *)kcontrol->private_value;
664 int max = mc->max;
665 int min = mc->min;
666
667 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
668 uinfo->count = 1;
669 uinfo->value.integer.min = min;
670 uinfo->value.integer.max = max;
671 return 0;
672}
673
674#define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel) \
675static int \
676omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \
677 struct snd_ctl_elem_value *uc) \
678{ \
679 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
680 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
681 struct soc_mixer_control *mc = \
682 (struct soc_mixer_control *)kc->private_value; \
683 int max = mc->max; \
684 int min = mc->min; \
685 int val = uc->value.integer.value[0]; \
686 \
687 if (val < min || val > max) \
688 return -EINVAL; \
689 \
690 /* OMAP McBSP implementation uses index values 0..4 */ \
691 return omap_st_set_chgain(mcbsp, channel, val); \
692} \
693 \
694static int \
695omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \
696 struct snd_ctl_elem_value *uc) \
697{ \
698 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
699 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
700 s16 chgain; \
701 \
702 if (omap_st_get_chgain(mcbsp, channel, &chgain)) \
703 return -EAGAIN; \
704 \
705 uc->value.integer.value[0] = chgain; \
706 return 0; \
707}
708
709OMAP_MCBSP_ST_CHANNEL_VOLUME(0)
710OMAP_MCBSP_ST_CHANNEL_VOLUME(1)
711
712static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
713 struct snd_ctl_elem_value *ucontrol)
714{
715 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
716 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
717 u8 value = ucontrol->value.integer.value[0];
718
719 if (value == omap_st_is_enabled(mcbsp))
720 return 0;
721
722 if (value)
723 omap_st_enable(mcbsp);
724 else
725 omap_st_disable(mcbsp);
726
727 return 1;
728}
729
730static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
731 struct snd_ctl_elem_value *ucontrol)
732{
733 struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
734 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
735
736 ucontrol->value.integer.value[0] = omap_st_is_enabled(mcbsp);
737 return 0;
738}
739
740#define OMAP_MCBSP_ST_CONTROLS(port) \
741static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \
742SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0, \
743 omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), \
744OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \
745 -32768, 32767, \
746 omap_mcbsp_get_st_ch0_volume, \
747 omap_mcbsp_set_st_ch0_volume), \
748OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \
749 -32768, 32767, \
750 omap_mcbsp_get_st_ch1_volume, \
751 omap_mcbsp_set_st_ch1_volume), \
752}
753
754OMAP_MCBSP_ST_CONTROLS(2);
755OMAP_MCBSP_ST_CONTROLS(3);
756
757int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id)
758{
759 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
760 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
761
762 if (!mcbsp->st_data) {
763 dev_warn(mcbsp->dev, "No sidetone data for port\n");
764 return 0;
765 }
766
767 switch (port_id) {
768 case 2: /* McBSP 2 */
769 return snd_soc_add_dai_controls(cpu_dai,
770 omap_mcbsp2_st_controls,
771 ARRAY_SIZE(omap_mcbsp2_st_controls));
772 case 3: /* McBSP 3 */
773 return snd_soc_add_dai_controls(cpu_dai,
774 omap_mcbsp3_st_controls,
775 ARRAY_SIZE(omap_mcbsp3_st_controls));
776 default:
777 dev_err(mcbsp->dev, "Port %d not supported\n", port_id);
778 break;
779 }
780
781 return -EINVAL;
782}
783EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
784
785static struct omap_mcbsp_platform_data omap2420_pdata = { 1346static struct omap_mcbsp_platform_data omap2420_pdata = {
786 .reg_step = 4, 1347 .reg_step = 4,
787 .reg_size = 2, 1348 .reg_size = 2,
@@ -893,7 +1454,10 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
893 if (pm_qos_request_active(&mcbsp->pm_qos_req)) 1454 if (pm_qos_request_active(&mcbsp->pm_qos_req))
894 pm_qos_remove_request(&mcbsp->pm_qos_req); 1455 pm_qos_remove_request(&mcbsp->pm_qos_req);
895 1456
896 omap_mcbsp_cleanup(mcbsp); 1457 if (mcbsp->pdata->buffer_size)
1458 sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
1459
1460 omap_mcbsp_st_cleanup(pdev);
897 1461
898 clk_put(mcbsp->fclk); 1462 clk_put(mcbsp->fclk);
899 1463
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
index 2e3369c27be3..7911d24898c9 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -22,8 +22,10 @@
22 * 22 *
23 */ 23 */
24 24
25#ifndef __OMAP_I2S_H__ 25#ifndef __OMAP_MCBSP_H__
26#define __OMAP_I2S_H__ 26#define __OMAP_MCBSP_H__
27
28#include <sound/dmaengine_pcm.h>
27 29
28/* Source clocks for McBSP sample rate generator */ 30/* Source clocks for McBSP sample rate generator */
29enum omap_mcbsp_clksrg_clk { 31enum omap_mcbsp_clksrg_clk {
@@ -41,4 +43,4 @@ enum omap_mcbsp_div {
41 43
42int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id); 44int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id);
43 45
44#endif 46#endif /* __OMAP_MCBSP_H__ */