diff options
author | Eero Nurkkala <ext-eero.nurkkala@nokia.com> | 2010-02-22 07:21:11 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2010-02-23 13:57:39 -0500 |
commit | d912fa9255845ffd8029482d408b6139344891c8 (patch) | |
tree | 2e11f12cbabe7078a1edf705a4d19c2a9188a694 /arch | |
parent | bce066836644f12b239b86bbfdd475d7b24b9a49 (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.c | 2 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/mcbsp.h | 60 | ||||
-rw-r--r-- | arch/arm/plat-omap/mcbsp.c | 402 |
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 | ||
413 | struct 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 | |||
381 | struct omap_mcbsp { | 423 | struct 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); | |||
459 | int omap_mcbsp_pollwrite(unsigned int id, u16 buf); | 502 | int omap_mcbsp_pollwrite(unsigned int id, u16 buf); |
460 | int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type); | 503 | int 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 */ | ||
507 | int omap_st_set_chgain(unsigned int id, int channel, s16 chgain); | ||
508 | int omap_st_get_chgain(unsigned int id, int channel, s16 *chgain); | ||
509 | int omap_st_enable(unsigned int id); | ||
510 | int omap_st_disable(unsigned int id); | ||
511 | int omap_st_is_enabled(unsigned int id); | ||
512 | #else | ||
513 | static inline int omap_st_set_chgain(unsigned int id, int channel, | ||
514 | s16 chgain) { return 0; } | ||
515 | static inline int omap_st_get_chgain(unsigned int id, int channel, | ||
516 | s16 *chgain) { return 0; } | ||
517 | static inline int omap_st_enable(unsigned int id) { return 0; } | ||
518 | static inline int omap_st_disable(unsigned int id) { return 0; } | ||
519 | static 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 | |||
30 | struct omap_mcbsp **mcbsp_ptr; | 32 | struct omap_mcbsp **mcbsp_ptr; |
31 | int omap_mcbsp_count, omap_mcbsp_cache_size; | 33 | int 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 | ||
64 | void 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 | |||
69 | int 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 | |||
71 | static void omap_mcbsp_dump_reg(u8 id) | 90 | static 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) | |||
211 | EXPORT_SYMBOL(omap_mcbsp_config); | 230 | EXPORT_SYMBOL(omap_mcbsp_config); |
212 | 231 | ||
213 | #ifdef CONFIG_ARCH_OMAP3 | 232 | #ifdef CONFIG_ARCH_OMAP3 |
233 | static 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 | |||
257 | static 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 | |||
275 | static 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 | |||
304 | static 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 | |||
318 | int 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 | } | ||
349 | EXPORT_SYMBOL(omap_st_set_chgain); | ||
350 | |||
351 | int 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 | } | ||
379 | EXPORT_SYMBOL(omap_st_get_chgain); | ||
380 | |||
381 | static 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 | |||
398 | int 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 | } | ||
421 | EXPORT_SYMBOL(omap_st_enable); | ||
422 | |||
423 | static 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 | |||
437 | int 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 | } | ||
461 | EXPORT_SYMBOL(omap_st_disable); | ||
462 | |||
463 | int 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 | } | ||
482 | EXPORT_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 |
364 | static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) {} | 634 | static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) {} |
365 | static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) {} | 635 | static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) {} |
636 | static inline void omap_st_start(struct omap_mcbsp *mcbsp) {} | ||
637 | static 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 | } |
641 | EXPORT_SYMBOL(omap_mcbsp_stop); | 919 | EXPORT_SYMBOL(omap_mcbsp_stop); |
642 | 920 | ||
@@ -1212,6 +1490,64 @@ unlock: | |||
1212 | 1490 | ||
1213 | static DEVICE_ATTR(dma_op_mode, 0644, dma_op_mode_show, dma_op_mode_store); | 1491 | static DEVICE_ATTR(dma_op_mode, 0644, dma_op_mode_show, dma_op_mode_store); |
1214 | 1492 | ||
1493 | static 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 | |||
1512 | static 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 | |||
1543 | out: | ||
1544 | spin_unlock_irq(&mcbsp->lock); | ||
1545 | |||
1546 | return size; | ||
1547 | } | ||
1548 | |||
1549 | static DEVICE_ATTR(st_taps, 0644, st_taps_show, st_taps_store); | ||
1550 | |||
1215 | static const struct attribute *additional_attrs[] = { | 1551 | static 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 | ||
1572 | static const struct attribute *sidetone_attrs[] = { | ||
1573 | &dev_attr_st_taps.attr, | ||
1574 | NULL, | ||
1575 | }; | ||
1576 | |||
1577 | static const struct attribute_group sidetone_attr_group = { | ||
1578 | .attrs = (struct attribute **)sidetone_attrs, | ||
1579 | }; | ||
1580 | |||
1581 | int __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 | |||
1606 | err3: | ||
1607 | iounmap(st_data->io_base_st); | ||
1608 | err2: | ||
1609 | kfree(st_data); | ||
1610 | err1: | ||
1611 | return err; | ||
1612 | |||
1613 | } | ||
1614 | |||
1615 | static 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 | |||
1236 | static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) | 1626 | static 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 | ||
1255 | static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp) | 1651 | static 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 |
1261 | static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) {} | 1661 | static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) {} |