* Ilkka Koskinen ilkka.koskinen@nokia.com [100217 06:41]:
From: Eero Nurkkala ext-eero.nurkkala@nokia.com
Add sidetone feature to McBSP instances 2 and 3 on OMAP3 based devices.
Signed-off-by: Ilkka Koskinen ilkka.koskinen@nokia.com
This one looks good to me and can be merged via Alsa list along with the other patch.
Acked-by: Tony Lindgren tony@atomide.com
arch/arm/mach-omap2/mcbsp.c | 2 + arch/arm/plat-omap/include/plat/mcbsp.h | 63 +++++ arch/arm/plat-omap/mcbsp.c | 396 ++++++++++++++++++++++++++++++- 3 files changed, 460 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index d601f94..be8fce3 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[] = { }, { .phys_base = OMAP34XX_MCBSP2_BASE,
.dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX, .dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX, .rx_irq = INT_24XX_MCBSP2_IRQ_RX,.phys_base_st = OMAP34XX_MCBSP2_ST_BASE,
@@ -145,6 +146,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { }, { .phys_base = OMAP34XX_MCBSP3_BASE,
.dma_rx_sync = OMAP24XX_DMA_MCBSP3_RX, .dma_tx_sync = OMAP24XX_DMA_MCBSP3_TX, .rx_irq = INT_24XX_MCBSP3_IRQ_RX,.phys_base_st = OMAP34XX_MCBSP3_ST_BASE,
diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h index 4df957b..5db1653 100644 --- a/arch/arm/plat-omap/include/plat/mcbsp.h +++ b/arch/arm/plat-omap/include/plat/mcbsp.h @@ -49,6 +49,9 @@
#define OMAP34XX_MCBSP1_BASE 0x48074000 #define OMAP34XX_MCBSP2_BASE 0x49022000 +#define OMAP34XX_MCBSP2_ST_BASE 0x49028000 +#define OMAP34XX_MCBSP3_BASE 0x49024000 +#define OMAP34XX_MCBSP3_ST_BASE 0x4902A000 #define OMAP34XX_MCBSP3_BASE 0x49024000 #define OMAP34XX_MCBSP4_BASE 0x49026000 #define OMAP34XX_MCBSP5_BASE 0x48096000 @@ -146,6 +149,15 @@ #define OMAP_MCBSP_REG_WAKEUPEN 0xA8 #define OMAP_MCBSP_REG_XCCR 0xAC #define OMAP_MCBSP_REG_RCCR 0xB0 +#define OMAP_MCBSP_REG_SSELCR 0xBC
+#define OMAP_ST_REG_REV 0x00 +#define OMAP_ST_REG_SYSCONFIG 0x10 +#define OMAP_ST_REG_IRQSTATUS 0x18 +#define OMAP_ST_REG_IRQENABLE 0x1C +#define OMAP_ST_REG_SGAINCR 0x24 +#define OMAP_ST_REG_SFIRCR 0x28 +#define OMAP_ST_REG_SSELCR 0x2C
#define AUDIO_MCBSP_DATAWRITE (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1) #define AUDIO_MCBSP_DATAREAD (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1) @@ -264,6 +276,24 @@ #define ENAWAKEUP 0x0004 #define SOFTRST 0x0002
+/********************** McBSP SSELCR bit definitions ***********************/ +#define SIDETONEEN 0x0400
+/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/ +#define ST_AUTOIDLE 0x0001
+/********************** McBSP Sidetone SGAINCR bit definitions *************/ +#define ST_CH1GAIN(value) ((value<<16)) /* Bits 16:31 */ +#define ST_CH0GAIN(value) (value) /* Bits 0:15 */
+/********************** McBSP Sidetone SFIRCR bit definitions **************/ +#define ST_FIRCOEFF(value) (value) /* Bits 0:15 */
+/********************** McBSP Sidetone SSELCR bit definitions **************/ +#define ST_COEFFWRDONE 0x0004 +#define ST_COEFFWREN 0x0002 +#define ST_SIDETONEEN 0x0001
/********************** McBSP DMA operating modes **************************/ #define MCBSP_DMA_MODE_ELEMENT 0 #define MCBSP_DMA_MODE_THRESHOLD 1 @@ -374,10 +404,25 @@ struct omap_mcbsp_platform_data { u16 rx_irq, tx_irq; struct omap_mcbsp_ops *ops; #ifdef CONFIG_ARCH_OMAP3
- /* Sidetone block for McBSP 2 and 3 */
- unsigned long phys_base_st; u16 buffer_size;
#endif };
+#define OMAP_MCBSP_ST_CHANNEL_0 (1 << 0) +#define OMAP_MCBSP_ST_CHANNEL_1 (1 << 1)
+struct omap_mcbsp_st_data {
- void __iomem *io_base_st;
- bool running;
- bool enabled;
- s16 taps[128]; /* Sidetone filter coefficients */
- int nr_taps; /* Number of filter coefficients in use */
- s16 ch0gain;
- s16 ch1gain;
+};
struct omap_mcbsp { struct device *dev; unsigned long phys_base; @@ -410,6 +455,7 @@ struct omap_mcbsp { struct clk *iclk; struct clk *fclk; #ifdef CONFIG_ARCH_OMAP3
- struct omap_mcbsp_st_data *st_data; int dma_op_mode; u16 max_tx_thres; u16 max_rx_thres;
@@ -459,4 +505,21 @@ int omap_mcbsp_pollread(unsigned int id, u16 * buf); int omap_mcbsp_pollwrite(unsigned int id, u16 buf); int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type);
+#ifdef CONFIG_ARCH_OMAP3 +/* Sidetone specific API */ +int omap_st_set_chgain(unsigned int id, s16 ch0gain, s16 ch1gain, int channels); +int omap_st_get_chgain(unsigned int id, s16 *ch0gain, s16 *ch1gain); +int omap_st_enable(unsigned int id); +int omap_st_disable(unsigned int id); +int omap_st_is_enabled(unsigned int id); +#else +static inline int omap_st_set_chgain(unsigned int id, s16 ch0gain,
s16 ch1gain, int channels) { return 0; }
+static inline int omap_st_get_chgain(unsigned int id, s16 *ch0gain,
s16 *ch1gain) { return 0; }
+static inline int omap_st_enable(unsigned int id) { return 0; } +static inline int omap_st_disable(unsigned int id) { return 0; } +static inline int omap_st_is_enabled(unsigned int id) { return 0; } +#endif
#endif diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 473be3d..921a5c1 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -27,6 +27,8 @@ #include <plat/dma.h> #include <plat/mcbsp.h>
+#include "../mach-omap2/cm-regbits-34xx.h"
struct omap_mcbsp **mcbsp_ptr; int omap_mcbsp_count, omap_mcbsp_cache_size;
@@ -58,6 +60,18 @@ int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache) } }
+#ifdef CONFIG_ARCH_OMAP3 +void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) +{
- __raw_writel(val, mcbsp->st_data->io_base_st + reg);
+}
+int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg) +{
- return __raw_readl(mcbsp->st_data->io_base_st + reg);
+} +#endif
#define MCBSP_READ(mcbsp, reg) \ omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0) #define MCBSP_WRITE(mcbsp, reg, val) \ @@ -68,6 +82,11 @@ int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache) #define omap_mcbsp_check_valid_id(id) (id < omap_mcbsp_count) #define id_to_mcbsp_ptr(id) mcbsp_ptr[id];
+#define MCBSP_ST_READ(mcbsp, reg) \
omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
+#define MCBSP_ST_WRITE(mcbsp, reg, val) \
omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val)
static void omap_mcbsp_dump_reg(u8 id) { struct omap_mcbsp *mcbsp = id_to_mcbsp_ptr(id); @@ -211,6 +230,251 @@ void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config) EXPORT_SYMBOL(omap_mcbsp_config);
#ifdef CONFIG_ARCH_OMAP3 +static void omap_st_on(struct omap_mcbsp *mcbsp) +{
- unsigned int w;
- /*
* Sidetone uses McBSP ICLK - which must not idle when sidetones
* are enabled or sidetones start sounding ugly.
*/
- w = cm_read_mod_reg(OMAP3430_PER_MOD, CM_AUTOIDLE);
- w &= ~(1 << (mcbsp->id - 2));
- cm_write_mod_reg(w, OMAP3430_PER_MOD, CM_AUTOIDLE);
- /* Enable McBSP Sidetone */
- w = MCBSP_READ(mcbsp, SSELCR);
- MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
- w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
- MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
- /* Enable Sidetone from Sidetone Core */
- w = MCBSP_ST_READ(mcbsp, SSELCR);
- MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
+}
+static void omap_st_off(struct omap_mcbsp *mcbsp) +{
- unsigned int w;
- w = MCBSP_ST_READ(mcbsp, SSELCR);
- MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
- w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
- MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE);
- w = MCBSP_READ(mcbsp, SSELCR);
- MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
- w = cm_read_mod_reg(OMAP3430_PER_MOD, CM_AUTOIDLE);
- w |= 1 << (mcbsp->id - 2);
- cm_write_mod_reg(w, OMAP3430_PER_MOD, CM_AUTOIDLE);
+}
+static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir) +{
- u16 val, i;
- val = MCBSP_ST_READ(mcbsp, SYSCONFIG);
- MCBSP_ST_WRITE(mcbsp, SYSCONFIG, val & ~(ST_AUTOIDLE));
- val = MCBSP_ST_READ(mcbsp, SSELCR);
- if (val & ST_COEFFWREN)
MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
- MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN);
- for (i = 0; i < 128; i++)
MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]);
- i = 0;
- val = MCBSP_ST_READ(mcbsp, SSELCR);
- while (!(val & ST_COEFFWRDONE) && (++i < 1000))
val = MCBSP_ST_READ(mcbsp, SSELCR);
- MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
- if (i == 1000)
dev_err(mcbsp->dev, "McBSP FIR load error!\n");
+}
+static void omap_st_chgain(struct omap_mcbsp *mcbsp) +{
- u16 w;
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
- MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
- w = MCBSP_ST_READ(mcbsp, SSELCR);
- MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) | \
ST_CH1GAIN(st_data->ch1gain));
+}
+int omap_st_set_chgain(unsigned int id, s16 ch0gain, s16 ch1gain,
int channels)
+{
- struct omap_mcbsp *mcbsp;
- struct omap_mcbsp_st_data *st_data;
- if (!omap_mcbsp_check_valid_id(id)) {
printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
return -ENODEV;
- }
- mcbsp = id_to_mcbsp_ptr(id);
- st_data = mcbsp->st_data;
- if (!st_data)
return -ENOENT;
- spin_lock_irq(&mcbsp->lock);
- if (channels & OMAP_MCBSP_ST_CHANNEL_0)
st_data->ch0gain = ch0gain;
- if (channels & OMAP_MCBSP_ST_CHANNEL_1)
st_data->ch1gain = ch1gain;
- if (st_data->enabled)
omap_st_chgain(mcbsp);
- spin_unlock_irq(&mcbsp->lock);
- return 0;
+} +EXPORT_SYMBOL(omap_st_set_chgain);
+int omap_st_get_chgain(unsigned int id, s16 *ch0gain, s16 *ch1gain) +{
- struct omap_mcbsp *mcbsp;
- struct omap_mcbsp_st_data *st_data;
- if (!omap_mcbsp_check_valid_id(id)) {
printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
return -ENODEV;
- }
- mcbsp = id_to_mcbsp_ptr(id);
- st_data = mcbsp->st_data;
- if (!st_data)
return -ENOENT;
- spin_lock_irq(&mcbsp->lock);
- *ch0gain = st_data->ch0gain;
- *ch1gain = st_data->ch1gain;
- spin_unlock_irq(&mcbsp->lock);
- return 0;
+} +EXPORT_SYMBOL(omap_st_get_chgain);
+static int omap_st_start(struct omap_mcbsp *mcbsp) +{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- if (st_data && st_data->enabled && !st_data->running) {
omap_st_fir_write(mcbsp, st_data->taps);
omap_st_chgain(mcbsp);
if (!mcbsp->free) {
omap_st_on(mcbsp);
st_data->running = 1;
}
- }
- return 0;
+}
+int omap_st_enable(unsigned int id) +{
- struct omap_mcbsp *mcbsp;
- struct omap_mcbsp_st_data *st_data;
- if (!omap_mcbsp_check_valid_id(id)) {
printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
return -ENODEV;
- }
- mcbsp = id_to_mcbsp_ptr(id);
- st_data = mcbsp->st_data;
- if (!st_data)
return -ENODEV;
- spin_lock_irq(&mcbsp->lock);
- st_data->enabled = 1;
- omap_st_start(mcbsp);
- spin_unlock_irq(&mcbsp->lock);
- return 0;
+} +EXPORT_SYMBOL(omap_st_enable);
+static int omap_st_stop(struct omap_mcbsp *mcbsp) +{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- if (st_data && st_data->running) {
if (!mcbsp->free) {
omap_st_off(mcbsp);
st_data->running = 0;
}
- }
- return 0;
+}
+int omap_st_disable(unsigned int id) +{
- struct omap_mcbsp *mcbsp;
- struct omap_mcbsp_st_data *st_data;
- int ret = 0;
- if (!omap_mcbsp_check_valid_id(id)) {
printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
return -ENODEV;
- }
- mcbsp = id_to_mcbsp_ptr(id);
- st_data = mcbsp->st_data;
- if (!st_data)
return -ENODEV;
- spin_lock_irq(&mcbsp->lock);
- omap_st_stop(mcbsp);
- st_data->enabled = 0;
- spin_unlock_irq(&mcbsp->lock);
- return ret;
+} +EXPORT_SYMBOL(omap_st_disable);
+int omap_st_is_enabled(unsigned int id) +{
- struct omap_mcbsp *mcbsp;
- struct omap_mcbsp_st_data *st_data;
- if (!omap_mcbsp_check_valid_id(id)) {
printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
return -ENODEV;
- }
- mcbsp = id_to_mcbsp_ptr(id);
- st_data = mcbsp->st_data;
- if (!st_data)
return -ENODEV;
- return st_data->enabled;
+} +EXPORT_SYMBOL(omap_st_is_enabled);
/*
- omap_mcbsp_set_tx_threshold configures how to deal
- with transmit threshold. the threshold value and handler can be
@@ -363,6 +627,8 @@ static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) #else static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) {} static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) {} +static inline void omap_st_start(struct omap_mcbsp *mcbsp) {} +static inline void omap_st_stop(struct omap_mcbsp *mcbsp) {} #endif
/* @@ -546,6 +812,9 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx) } mcbsp = id_to_mcbsp_ptr(id);
- if (cpu_is_omap34xx())
omap_st_start(mcbsp);
- mcbsp->rx_word_length = (MCBSP_READ_CACHE(mcbsp, RCR1) >> 5) & 0x7; mcbsp->tx_word_length = (MCBSP_READ_CACHE(mcbsp, XCR1) >> 5) & 0x7;
@@ -637,6 +906,9 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx) w = MCBSP_READ_CACHE(mcbsp, SPCR2); MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6)); }
- if (cpu_is_omap34xx())
omap_st_stop(mcbsp);
} EXPORT_SYMBOL(omap_mcbsp_stop);
@@ -1212,6 +1484,64 @@ unlock:
static DEVICE_ATTR(dma_op_mode, 0644, dma_op_mode_show, dma_op_mode_store);
+static ssize_t st_taps_show(struct device *dev,
struct device_attribute *attr, char *buf)
+{
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- ssize_t status = 0;
- int i;
- spin_lock_irq(&mcbsp->lock);
- for (i = 0; i < st_data->nr_taps; i++)
status += sprintf(&buf[status], (i ? ", %d" : "%d"),
st_data->taps[i]);
- if (i)
status += sprintf(&buf[status], "\n");
- spin_unlock_irq(&mcbsp->lock);
- return status;
+}
+static ssize_t st_taps_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- int val, tmp, status, i = 0;
- spin_lock_irq(&mcbsp->lock);
- memset(st_data->taps, 0, sizeof(st_data->taps));
- st_data->nr_taps = 0;
- do {
status = sscanf(buf, "%d%n", &val, &tmp);
if (status < 0 || status == 0) {
size = -EINVAL;
goto out;
}
if (val < -32768 || val > 32767) {
size = -EINVAL;
goto out;
}
st_data->taps[i++] = val;
buf += tmp;
if (*buf != ',')
break;
buf++;
- } while (1);
- st_data->nr_taps = i;
+out:
- spin_unlock_irq(&mcbsp->lock);
- return size;
+}
+static DEVICE_ATTR(st_taps, 0644, st_taps_show, st_taps_store);
static const struct attribute *additional_attrs[] = { &dev_attr_max_tx_thres.attr, &dev_attr_max_rx_thres.attr, @@ -1233,6 +1563,60 @@ static inline void __devexit omap_additional_remove(struct device *dev) sysfs_remove_group(&dev->kobj, &additional_attr_group); }
+static const struct attribute *sidetone_attrs[] = {
- &dev_attr_st_taps.attr,
- NULL,
+};
+static const struct attribute_group sidetone_attr_group = {
- .attrs = (struct attribute **)sidetone_attrs,
+};
+int __devinit omap_st_add(struct omap_mcbsp *mcbsp) +{
- struct omap_mcbsp_platform_data *pdata = mcbsp->pdata;
- struct omap_mcbsp_st_data *st_data;
- int err;
- st_data = kzalloc(sizeof(*mcbsp->st_data), GFP_KERNEL);
- if (!st_data) {
err = -ENOMEM;
goto err1;
- }
- st_data->io_base_st = ioremap(pdata->phys_base_st, SZ_4K);
- if (!st_data->io_base_st) {
err = -ENOMEM;
goto err2;
- }
- err = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
- if (err)
goto err3;
- mcbsp->st_data = st_data;
- return 0;
+err3:
- iounmap(st_data->io_base_st);
+err2:
- kfree(st_data);
+err1:
- return err;
+}
+static void __devexit omap_st_remove(struct omap_mcbsp *mcbsp) +{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- if (st_data) {
sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
iounmap(st_data->io_base_st);
kfree(st_data);
- }
+}
static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) { mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT; @@ -1246,6 +1630,12 @@ static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) if (omap_additional_add(mcbsp->dev)) dev_warn(mcbsp->dev, "Unable to create additional controls\n");
if (mcbsp->id == 2 || mcbsp->id == 3)
if (omap_st_add(mcbsp))
dev_warn(mcbsp->dev,
"Unable to create sidetone controls\n");
- } else { mcbsp->max_tx_thres = -EINVAL; mcbsp->max_rx_thres = -EINVAL;
@@ -1254,8 +1644,12 @@ static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp)
static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp) {
- if (cpu_is_omap34xx())
- if (cpu_is_omap34xx()) { omap_additional_remove(mcbsp->dev);
if (mcbsp->id == 2 || mcbsp->id == 3)
omap_st_remove(mcbsp);
- }
} #else static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) {} -- 1.6.0.4