aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorEero Nurkkala <ext-eero.nurkkala@nokia.com>2010-02-22 07:21:11 -0500
committerTony Lindgren <tony@atomide.com>2010-02-23 13:57:39 -0500
commitd912fa9255845ffd8029482d408b6139344891c8 (patch)
tree2e11f12cbabe7078a1edf705a4d19c2a9188a694 /arch
parentbce066836644f12b239b86bbfdd475d7b24b9a49 (diff)
McBSP: OMAP3: Add sidetone feature
Add sidetone feature to McBSP instances 2 and 3 on OMAP3 based devices. Signed-off-by: Ilkka Koskinen <ilkka.koskinen@nokia.com> Acked-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Tested-by: Jarkko Nikula <jhnikula@gmail.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-omap2/mcbsp.c2
-rw-r--r--arch/arm/plat-omap/include/plat/mcbsp.h60
-rw-r--r--arch/arm/plat-omap/mcbsp.c402
3 files changed, 463 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c
index d601f9405d11..be8fce395a58 100644
--- a/arch/arm/mach-omap2/mcbsp.c
+++ b/arch/arm/mach-omap2/mcbsp.c
@@ -136,6 +136,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
136 }, 136 },
137 { 137 {
138 .phys_base = OMAP34XX_MCBSP2_BASE, 138 .phys_base = OMAP34XX_MCBSP2_BASE,
139 .phys_base_st = OMAP34XX_MCBSP2_ST_BASE,
139 .dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX, 140 .dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX,
140 .dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX, 141 .dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX,
141 .rx_irq = INT_24XX_MCBSP2_IRQ_RX, 142 .rx_irq = INT_24XX_MCBSP2_IRQ_RX,
@@ -145,6 +146,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
145 }, 146 },
146 { 147 {
147 .phys_base = OMAP34XX_MCBSP3_BASE, 148 .phys_base = OMAP34XX_MCBSP3_BASE,
149 .phys_base_st = OMAP34XX_MCBSP3_ST_BASE,
148 .dma_rx_sync = OMAP24XX_DMA_MCBSP3_RX, 150 .dma_rx_sync = OMAP24XX_DMA_MCBSP3_RX,
149 .dma_tx_sync = OMAP24XX_DMA_MCBSP3_TX, 151 .dma_tx_sync = OMAP24XX_DMA_MCBSP3_TX,
150 .rx_irq = INT_24XX_MCBSP3_IRQ_RX, 152 .rx_irq = INT_24XX_MCBSP3_IRQ_RX,
diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h
index 4df957b1d252..39748354ce45 100644
--- a/arch/arm/plat-omap/include/plat/mcbsp.h
+++ b/arch/arm/plat-omap/include/plat/mcbsp.h
@@ -49,6 +49,9 @@
49 49
50#define OMAP34XX_MCBSP1_BASE 0x48074000 50#define OMAP34XX_MCBSP1_BASE 0x48074000
51#define OMAP34XX_MCBSP2_BASE 0x49022000 51#define OMAP34XX_MCBSP2_BASE 0x49022000
52#define OMAP34XX_MCBSP2_ST_BASE 0x49028000
53#define OMAP34XX_MCBSP3_BASE 0x49024000
54#define OMAP34XX_MCBSP3_ST_BASE 0x4902A000
52#define OMAP34XX_MCBSP3_BASE 0x49024000 55#define OMAP34XX_MCBSP3_BASE 0x49024000
53#define OMAP34XX_MCBSP4_BASE 0x49026000 56#define OMAP34XX_MCBSP4_BASE 0x49026000
54#define OMAP34XX_MCBSP5_BASE 0x48096000 57#define OMAP34XX_MCBSP5_BASE 0x48096000
@@ -146,6 +149,15 @@
146#define OMAP_MCBSP_REG_WAKEUPEN 0xA8 149#define OMAP_MCBSP_REG_WAKEUPEN 0xA8
147#define OMAP_MCBSP_REG_XCCR 0xAC 150#define OMAP_MCBSP_REG_XCCR 0xAC
148#define OMAP_MCBSP_REG_RCCR 0xB0 151#define OMAP_MCBSP_REG_RCCR 0xB0
152#define OMAP_MCBSP_REG_SSELCR 0xBC
153
154#define OMAP_ST_REG_REV 0x00
155#define OMAP_ST_REG_SYSCONFIG 0x10
156#define OMAP_ST_REG_IRQSTATUS 0x18
157#define OMAP_ST_REG_IRQENABLE 0x1C
158#define OMAP_ST_REG_SGAINCR 0x24
159#define OMAP_ST_REG_SFIRCR 0x28
160#define OMAP_ST_REG_SSELCR 0x2C
149 161
150#define AUDIO_MCBSP_DATAWRITE (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1) 162#define AUDIO_MCBSP_DATAWRITE (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1)
151#define AUDIO_MCBSP_DATAREAD (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1) 163#define AUDIO_MCBSP_DATAREAD (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1)
@@ -264,6 +276,24 @@
264#define ENAWAKEUP 0x0004 276#define ENAWAKEUP 0x0004
265#define SOFTRST 0x0002 277#define SOFTRST 0x0002
266 278
279/********************** McBSP SSELCR bit definitions ***********************/
280#define SIDETONEEN 0x0400
281
282/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/
283#define ST_AUTOIDLE 0x0001
284
285/********************** McBSP Sidetone SGAINCR bit definitions *************/
286#define ST_CH1GAIN(value) ((value<<16)) /* Bits 16:31 */
287#define ST_CH0GAIN(value) (value) /* Bits 0:15 */
288
289/********************** McBSP Sidetone SFIRCR bit definitions **************/
290#define ST_FIRCOEFF(value) (value) /* Bits 0:15 */
291
292/********************** McBSP Sidetone SSELCR bit definitions **************/
293#define ST_COEFFWRDONE 0x0004
294#define ST_COEFFWREN 0x0002
295#define ST_SIDETONEEN 0x0001
296
267/********************** McBSP DMA operating modes **************************/ 297/********************** McBSP DMA operating modes **************************/
268#define MCBSP_DMA_MODE_ELEMENT 0 298#define MCBSP_DMA_MODE_ELEMENT 0
269#define MCBSP_DMA_MODE_THRESHOLD 1 299#define MCBSP_DMA_MODE_THRESHOLD 1
@@ -374,10 +404,22 @@ struct omap_mcbsp_platform_data {
374 u16 rx_irq, tx_irq; 404 u16 rx_irq, tx_irq;
375 struct omap_mcbsp_ops *ops; 405 struct omap_mcbsp_ops *ops;
376#ifdef CONFIG_ARCH_OMAP3 406#ifdef CONFIG_ARCH_OMAP3
407 /* Sidetone block for McBSP 2 and 3 */
408 unsigned long phys_base_st;
377 u16 buffer_size; 409 u16 buffer_size;
378#endif 410#endif
379}; 411};
380 412
413struct omap_mcbsp_st_data {
414 void __iomem *io_base_st;
415 bool running;
416 bool enabled;
417 s16 taps[128]; /* Sidetone filter coefficients */
418 int nr_taps; /* Number of filter coefficients in use */
419 s16 ch0gain;
420 s16 ch1gain;
421};
422
381struct omap_mcbsp { 423struct omap_mcbsp {
382 struct device *dev; 424 struct device *dev;
383 unsigned long phys_base; 425 unsigned long phys_base;
@@ -410,6 +452,7 @@ struct omap_mcbsp {
410 struct clk *iclk; 452 struct clk *iclk;
411 struct clk *fclk; 453 struct clk *fclk;
412#ifdef CONFIG_ARCH_OMAP3 454#ifdef CONFIG_ARCH_OMAP3
455 struct omap_mcbsp_st_data *st_data;
413 int dma_op_mode; 456 int dma_op_mode;
414 u16 max_tx_thres; 457 u16 max_tx_thres;
415 u16 max_rx_thres; 458 u16 max_rx_thres;
@@ -459,4 +502,21 @@ int omap_mcbsp_pollread(unsigned int id, u16 * buf);
459int omap_mcbsp_pollwrite(unsigned int id, u16 buf); 502int omap_mcbsp_pollwrite(unsigned int id, u16 buf);
460int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type); 503int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type);
461 504
505#ifdef CONFIG_ARCH_OMAP3
506/* Sidetone specific API */
507int omap_st_set_chgain(unsigned int id, int channel, s16 chgain);
508int omap_st_get_chgain(unsigned int id, int channel, s16 *chgain);
509int omap_st_enable(unsigned int id);
510int omap_st_disable(unsigned int id);
511int omap_st_is_enabled(unsigned int id);
512#else
513static inline int omap_st_set_chgain(unsigned int id, int channel,
514 s16 chgain) { return 0; }
515static inline int omap_st_get_chgain(unsigned int id, int channel,
516 s16 *chgain) { return 0; }
517static inline int omap_st_enable(unsigned int id) { return 0; }
518static inline int omap_st_disable(unsigned int id) { return 0; }
519static inline int omap_st_is_enabled(unsigned int id) { return 0; }
520#endif
521
462#endif 522#endif
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index 473be3dc2cf5..e47686e0a633 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -27,6 +27,8 @@
27#include <plat/dma.h> 27#include <plat/dma.h>
28#include <plat/mcbsp.h> 28#include <plat/mcbsp.h>
29 29
30#include "../mach-omap2/cm-regbits-34xx.h"
31
30struct omap_mcbsp **mcbsp_ptr; 32struct omap_mcbsp **mcbsp_ptr;
31int omap_mcbsp_count, omap_mcbsp_cache_size; 33int omap_mcbsp_count, omap_mcbsp_cache_size;
32 34
@@ -58,6 +60,18 @@ int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
58 } 60 }
59} 61}
60 62
63#ifdef CONFIG_ARCH_OMAP3
64void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
65{
66 __raw_writel(val, mcbsp->st_data->io_base_st + reg);
67}
68
69int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
70{
71 return __raw_readl(mcbsp->st_data->io_base_st + reg);
72}
73#endif
74
61#define MCBSP_READ(mcbsp, reg) \ 75#define MCBSP_READ(mcbsp, reg) \
62 omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0) 76 omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0)
63#define MCBSP_WRITE(mcbsp, reg, val) \ 77#define MCBSP_WRITE(mcbsp, reg, val) \
@@ -68,6 +82,11 @@ int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
68#define omap_mcbsp_check_valid_id(id) (id < omap_mcbsp_count) 82#define omap_mcbsp_check_valid_id(id) (id < omap_mcbsp_count)
69#define id_to_mcbsp_ptr(id) mcbsp_ptr[id]; 83#define id_to_mcbsp_ptr(id) mcbsp_ptr[id];
70 84
85#define MCBSP_ST_READ(mcbsp, reg) \
86 omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
87#define MCBSP_ST_WRITE(mcbsp, reg, val) \
88 omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val)
89
71static void omap_mcbsp_dump_reg(u8 id) 90static void omap_mcbsp_dump_reg(u8 id)
72{ 91{
73 struct omap_mcbsp *mcbsp = id_to_mcbsp_ptr(id); 92 struct omap_mcbsp *mcbsp = id_to_mcbsp_ptr(id);
@@ -211,6 +230,257 @@ void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config)
211EXPORT_SYMBOL(omap_mcbsp_config); 230EXPORT_SYMBOL(omap_mcbsp_config);
212 231
213#ifdef CONFIG_ARCH_OMAP3 232#ifdef CONFIG_ARCH_OMAP3
233static void omap_st_on(struct omap_mcbsp *mcbsp)
234{
235 unsigned int w;
236
237 /*
238 * Sidetone uses McBSP ICLK - which must not idle when sidetones
239 * are enabled or sidetones start sounding ugly.
240 */
241 w = cm_read_mod_reg(OMAP3430_PER_MOD, CM_AUTOIDLE);
242 w &= ~(1 << (mcbsp->id - 2));
243 cm_write_mod_reg(w, OMAP3430_PER_MOD, CM_AUTOIDLE);
244
245 /* Enable McBSP Sidetone */
246 w = MCBSP_READ(mcbsp, SSELCR);
247 MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
248
249 w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
250 MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
251
252 /* Enable Sidetone from Sidetone Core */
253 w = MCBSP_ST_READ(mcbsp, SSELCR);
254 MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
255}
256
257static void omap_st_off(struct omap_mcbsp *mcbsp)
258{
259 unsigned int w;
260
261 w = MCBSP_ST_READ(mcbsp, SSELCR);
262 MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
263
264 w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
265 MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE);
266
267 w = MCBSP_READ(mcbsp, SSELCR);
268 MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
269
270 w = cm_read_mod_reg(OMAP3430_PER_MOD, CM_AUTOIDLE);
271 w |= 1 << (mcbsp->id - 2);
272 cm_write_mod_reg(w, OMAP3430_PER_MOD, CM_AUTOIDLE);
273}
274
275static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
276{
277 u16 val, i;
278
279 val = MCBSP_ST_READ(mcbsp, SYSCONFIG);
280 MCBSP_ST_WRITE(mcbsp, SYSCONFIG, val & ~(ST_AUTOIDLE));
281
282 val = MCBSP_ST_READ(mcbsp, SSELCR);
283
284 if (val & ST_COEFFWREN)
285 MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
286
287 MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN);
288
289 for (i = 0; i < 128; i++)
290 MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]);
291
292 i = 0;
293
294 val = MCBSP_ST_READ(mcbsp, SSELCR);
295 while (!(val & ST_COEFFWRDONE) && (++i < 1000))
296 val = MCBSP_ST_READ(mcbsp, SSELCR);
297
298 MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
299
300 if (i == 1000)
301 dev_err(mcbsp->dev, "McBSP FIR load error!\n");
302}
303
304static void omap_st_chgain(struct omap_mcbsp *mcbsp)
305{
306 u16 w;
307 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
308
309 w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
310 MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
311
312 w = MCBSP_ST_READ(mcbsp, SSELCR);
313
314 MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) | \
315 ST_CH1GAIN(st_data->ch1gain));
316}
317
318int omap_st_set_chgain(unsigned int id, int channel, s16 chgain)
319{
320 struct omap_mcbsp *mcbsp;
321 struct omap_mcbsp_st_data *st_data;
322 int ret = 0;
323
324 if (!omap_mcbsp_check_valid_id(id)) {
325 printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
326 return -ENODEV;
327 }
328
329 mcbsp = id_to_mcbsp_ptr(id);
330 st_data = mcbsp->st_data;
331
332 if (!st_data)
333 return -ENOENT;
334
335 spin_lock_irq(&mcbsp->lock);
336 if (channel == 0)
337 st_data->ch0gain = chgain;
338 else if (channel == 1)
339 st_data->ch1gain = chgain;
340 else
341 ret = -EINVAL;
342
343 if (st_data->enabled)
344 omap_st_chgain(mcbsp);
345 spin_unlock_irq(&mcbsp->lock);
346
347 return ret;
348}
349EXPORT_SYMBOL(omap_st_set_chgain);
350
351int omap_st_get_chgain(unsigned int id, int channel, s16 *chgain)
352{
353 struct omap_mcbsp *mcbsp;
354 struct omap_mcbsp_st_data *st_data;
355 int ret = 0;
356
357 if (!omap_mcbsp_check_valid_id(id)) {
358 printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
359 return -ENODEV;
360 }
361
362 mcbsp = id_to_mcbsp_ptr(id);
363 st_data = mcbsp->st_data;
364
365 if (!st_data)
366 return -ENOENT;
367
368 spin_lock_irq(&mcbsp->lock);
369 if (channel == 0)
370 *chgain = st_data->ch0gain;
371 else if (channel == 1)
372 *chgain = st_data->ch1gain;
373 else
374 ret = -EINVAL;
375 spin_unlock_irq(&mcbsp->lock);
376
377 return ret;
378}
379EXPORT_SYMBOL(omap_st_get_chgain);
380
381static int omap_st_start(struct omap_mcbsp *mcbsp)
382{
383 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
384
385 if (st_data && st_data->enabled && !st_data->running) {
386 omap_st_fir_write(mcbsp, st_data->taps);
387 omap_st_chgain(mcbsp);
388
389 if (!mcbsp->free) {
390 omap_st_on(mcbsp);
391 st_data->running = 1;
392 }
393 }
394
395 return 0;
396}
397
398int omap_st_enable(unsigned int id)
399{
400 struct omap_mcbsp *mcbsp;
401 struct omap_mcbsp_st_data *st_data;
402
403 if (!omap_mcbsp_check_valid_id(id)) {
404 printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
405 return -ENODEV;
406 }
407
408 mcbsp = id_to_mcbsp_ptr(id);
409 st_data = mcbsp->st_data;
410
411 if (!st_data)
412 return -ENODEV;
413
414 spin_lock_irq(&mcbsp->lock);
415 st_data->enabled = 1;
416 omap_st_start(mcbsp);
417 spin_unlock_irq(&mcbsp->lock);
418
419 return 0;
420}
421EXPORT_SYMBOL(omap_st_enable);
422
423static int omap_st_stop(struct omap_mcbsp *mcbsp)
424{
425 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
426
427 if (st_data && st_data->running) {
428 if (!mcbsp->free) {
429 omap_st_off(mcbsp);
430 st_data->running = 0;
431 }
432 }
433
434 return 0;
435}
436
437int omap_st_disable(unsigned int id)
438{
439 struct omap_mcbsp *mcbsp;
440 struct omap_mcbsp_st_data *st_data;
441 int ret = 0;
442
443 if (!omap_mcbsp_check_valid_id(id)) {
444 printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
445 return -ENODEV;
446 }
447
448 mcbsp = id_to_mcbsp_ptr(id);
449 st_data = mcbsp->st_data;
450
451 if (!st_data)
452 return -ENODEV;
453
454 spin_lock_irq(&mcbsp->lock);
455 omap_st_stop(mcbsp);
456 st_data->enabled = 0;
457 spin_unlock_irq(&mcbsp->lock);
458
459 return ret;
460}
461EXPORT_SYMBOL(omap_st_disable);
462
463int omap_st_is_enabled(unsigned int id)
464{
465 struct omap_mcbsp *mcbsp;
466 struct omap_mcbsp_st_data *st_data;
467
468 if (!omap_mcbsp_check_valid_id(id)) {
469 printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
470 return -ENODEV;
471 }
472
473 mcbsp = id_to_mcbsp_ptr(id);
474 st_data = mcbsp->st_data;
475
476 if (!st_data)
477 return -ENODEV;
478
479
480 return st_data->enabled;
481}
482EXPORT_SYMBOL(omap_st_is_enabled);
483
214/* 484/*
215 * omap_mcbsp_set_tx_threshold configures how to deal 485 * omap_mcbsp_set_tx_threshold configures how to deal
216 * with transmit threshold. the threshold value and handler can be 486 * with transmit threshold. the threshold value and handler can be
@@ -363,6 +633,8 @@ static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp)
363#else 633#else
364static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) {} 634static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) {}
365static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) {} 635static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) {}
636static inline void omap_st_start(struct omap_mcbsp *mcbsp) {}
637static inline void omap_st_stop(struct omap_mcbsp *mcbsp) {}
366#endif 638#endif
367 639
368/* 640/*
@@ -546,6 +818,9 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx)
546 } 818 }
547 mcbsp = id_to_mcbsp_ptr(id); 819 mcbsp = id_to_mcbsp_ptr(id);
548 820
821 if (cpu_is_omap34xx())
822 omap_st_start(mcbsp);
823
549 mcbsp->rx_word_length = (MCBSP_READ_CACHE(mcbsp, RCR1) >> 5) & 0x7; 824 mcbsp->rx_word_length = (MCBSP_READ_CACHE(mcbsp, RCR1) >> 5) & 0x7;
550 mcbsp->tx_word_length = (MCBSP_READ_CACHE(mcbsp, XCR1) >> 5) & 0x7; 825 mcbsp->tx_word_length = (MCBSP_READ_CACHE(mcbsp, XCR1) >> 5) & 0x7;
551 826
@@ -637,6 +912,9 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx)
637 w = MCBSP_READ_CACHE(mcbsp, SPCR2); 912 w = MCBSP_READ_CACHE(mcbsp, SPCR2);
638 MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6)); 913 MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6));
639 } 914 }
915
916 if (cpu_is_omap34xx())
917 omap_st_stop(mcbsp);
640} 918}
641EXPORT_SYMBOL(omap_mcbsp_stop); 919EXPORT_SYMBOL(omap_mcbsp_stop);
642 920
@@ -1212,6 +1490,64 @@ unlock:
1212 1490
1213static DEVICE_ATTR(dma_op_mode, 0644, dma_op_mode_show, dma_op_mode_store); 1491static DEVICE_ATTR(dma_op_mode, 0644, dma_op_mode_show, dma_op_mode_store);
1214 1492
1493static ssize_t st_taps_show(struct device *dev,
1494 struct device_attribute *attr, char *buf)
1495{
1496 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
1497 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
1498 ssize_t status = 0;
1499 int i;
1500
1501 spin_lock_irq(&mcbsp->lock);
1502 for (i = 0; i < st_data->nr_taps; i++)
1503 status += sprintf(&buf[status], (i ? ", %d" : "%d"),
1504 st_data->taps[i]);
1505 if (i)
1506 status += sprintf(&buf[status], "\n");
1507 spin_unlock_irq(&mcbsp->lock);
1508
1509 return status;
1510}
1511
1512static ssize_t st_taps_store(struct device *dev,
1513 struct device_attribute *attr,
1514 const char *buf, size_t size)
1515{
1516 struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
1517 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
1518 int val, tmp, status, i = 0;
1519
1520 spin_lock_irq(&mcbsp->lock);
1521 memset(st_data->taps, 0, sizeof(st_data->taps));
1522 st_data->nr_taps = 0;
1523
1524 do {
1525 status = sscanf(buf, "%d%n", &val, &tmp);
1526 if (status < 0 || status == 0) {
1527 size = -EINVAL;
1528 goto out;
1529 }
1530 if (val < -32768 || val > 32767) {
1531 size = -EINVAL;
1532 goto out;
1533 }
1534 st_data->taps[i++] = val;
1535 buf += tmp;
1536 if (*buf != ',')
1537 break;
1538 buf++;
1539 } while (1);
1540
1541 st_data->nr_taps = i;
1542
1543out:
1544 spin_unlock_irq(&mcbsp->lock);
1545
1546 return size;
1547}
1548
1549static DEVICE_ATTR(st_taps, 0644, st_taps_show, st_taps_store);
1550
1215static const struct attribute *additional_attrs[] = { 1551static const struct attribute *additional_attrs[] = {
1216 &dev_attr_max_tx_thres.attr, 1552 &dev_attr_max_tx_thres.attr,
1217 &dev_attr_max_rx_thres.attr, 1553 &dev_attr_max_rx_thres.attr,
@@ -1233,6 +1569,60 @@ static inline void __devexit omap_additional_remove(struct device *dev)
1233 sysfs_remove_group(&dev->kobj, &additional_attr_group); 1569 sysfs_remove_group(&dev->kobj, &additional_attr_group);
1234} 1570}
1235 1571
1572static const struct attribute *sidetone_attrs[] = {
1573 &dev_attr_st_taps.attr,
1574 NULL,
1575};
1576
1577static const struct attribute_group sidetone_attr_group = {
1578 .attrs = (struct attribute **)sidetone_attrs,
1579};
1580
1581int __devinit omap_st_add(struct omap_mcbsp *mcbsp)
1582{
1583 struct omap_mcbsp_platform_data *pdata = mcbsp->pdata;
1584 struct omap_mcbsp_st_data *st_data;
1585 int err;
1586
1587 st_data = kzalloc(sizeof(*mcbsp->st_data), GFP_KERNEL);
1588 if (!st_data) {
1589 err = -ENOMEM;
1590 goto err1;
1591 }
1592
1593 st_data->io_base_st = ioremap(pdata->phys_base_st, SZ_4K);
1594 if (!st_data->io_base_st) {
1595 err = -ENOMEM;
1596 goto err2;
1597 }
1598
1599 err = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
1600 if (err)
1601 goto err3;
1602
1603 mcbsp->st_data = st_data;
1604 return 0;
1605
1606err3:
1607 iounmap(st_data->io_base_st);
1608err2:
1609 kfree(st_data);
1610err1:
1611 return err;
1612
1613}
1614
1615static void __devexit omap_st_remove(struct omap_mcbsp *mcbsp)
1616{
1617 struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
1618
1619 if (st_data) {
1620 sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
1621 iounmap(st_data->io_base_st);
1622 kfree(st_data);
1623 }
1624}
1625
1236static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) 1626static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp)
1237{ 1627{
1238 mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT; 1628 mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
@@ -1246,6 +1636,12 @@ static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp)
1246 if (omap_additional_add(mcbsp->dev)) 1636 if (omap_additional_add(mcbsp->dev))
1247 dev_warn(mcbsp->dev, 1637 dev_warn(mcbsp->dev,
1248 "Unable to create additional controls\n"); 1638 "Unable to create additional controls\n");
1639
1640 if (mcbsp->id == 2 || mcbsp->id == 3)
1641 if (omap_st_add(mcbsp))
1642 dev_warn(mcbsp->dev,
1643 "Unable to create sidetone controls\n");
1644
1249 } else { 1645 } else {
1250 mcbsp->max_tx_thres = -EINVAL; 1646 mcbsp->max_tx_thres = -EINVAL;
1251 mcbsp->max_rx_thres = -EINVAL; 1647 mcbsp->max_rx_thres = -EINVAL;
@@ -1254,8 +1650,12 @@ static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp)
1254 1650
1255static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp) 1651static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp)
1256{ 1652{
1257 if (cpu_is_omap34xx()) 1653 if (cpu_is_omap34xx()) {
1258 omap_additional_remove(mcbsp->dev); 1654 omap_additional_remove(mcbsp->dev);
1655
1656 if (mcbsp->id == 2 || mcbsp->id == 3)
1657 omap_st_remove(mcbsp);
1658 }
1259} 1659}
1260#else 1660#else
1261static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) {} 1661static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) {}