aboutsummaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-omap2/mcbsp.c5
-rw-r--r--arch/arm/mach-pxa/include/mach/audio.h3
-rw-r--r--arch/arm/plat-omap/dma.c10
-rw-r--r--arch/arm/plat-omap/include/mach/mcbsp.h51
-rw-r--r--arch/arm/plat-omap/mcbsp.c401
-rw-r--r--arch/arm/plat-s3c/include/plat/audio-simtec.h37
-rw-r--r--arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h5
7 files changed, 491 insertions, 21 deletions
diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c
index 99b6e154631..0447d26d454 100644
--- a/arch/arm/mach-omap2/mcbsp.c
+++ b/arch/arm/mach-omap2/mcbsp.c
@@ -128,6 +128,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.rx_irq = INT_24XX_MCBSP1_IRQ_RX,
.tx_irq = INT_24XX_MCBSP1_IRQ_TX,
.ops = &omap2_mcbsp_ops,
+ .buffer_size = 0x6F,
},
{
.phys_base = OMAP34XX_MCBSP2_BASE,
@@ -136,6 +137,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.rx_irq = INT_24XX_MCBSP2_IRQ_RX,
.tx_irq = INT_24XX_MCBSP2_IRQ_TX,
.ops = &omap2_mcbsp_ops,
+ .buffer_size = 0x3FF,
},
{
.phys_base = OMAP34XX_MCBSP3_BASE,
@@ -144,6 +146,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.rx_irq = INT_24XX_MCBSP3_IRQ_RX,
.tx_irq = INT_24XX_MCBSP3_IRQ_TX,
.ops = &omap2_mcbsp_ops,
+ .buffer_size = 0x6F,
},
{
.phys_base = OMAP34XX_MCBSP4_BASE,
@@ -152,6 +155,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.rx_irq = INT_24XX_MCBSP4_IRQ_RX,
.tx_irq = INT_24XX_MCBSP4_IRQ_TX,
.ops = &omap2_mcbsp_ops,
+ .buffer_size = 0x6F,
},
{
.phys_base = OMAP34XX_MCBSP5_BASE,
@@ -160,6 +164,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.rx_irq = INT_24XX_MCBSP5_IRQ_RX,
.tx_irq = INT_24XX_MCBSP5_IRQ_TX,
.ops = &omap2_mcbsp_ops,
+ .buffer_size = 0x6F,
},
};
#define OMAP34XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap34xx_mcbsp_pdata)
diff --git a/arch/arm/mach-pxa/include/mach/audio.h b/arch/arm/mach-pxa/include/mach/audio.h
index 16eb02552d5..a3449e35a6f 100644
--- a/arch/arm/mach-pxa/include/mach/audio.h
+++ b/arch/arm/mach-pxa/include/mach/audio.h
@@ -3,10 +3,12 @@
#include <sound/core.h>
#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
/*
* @reset_gpio: AC97 reset gpio (normally gpio113 or gpio95)
* a -1 value means no gpio will be used for reset
+ * @codec_pdata: AC97 codec platform_data
* reset_gpio should only be specified for pxa27x CPUs where a silicon
* bug prevents correct operation of the reset line. If not specified,
@@ -20,6 +22,7 @@ typedef struct {
void (*resume)(void *);
void *priv;
int reset_gpio;
+ void *codec_pdata[AC97_BUS_MAX_DEVICES];
} pxa2xx_audio_ops_t;
extern void pxa_set_ac97_info(pxa2xx_audio_ops_t *ops);
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index e3ac94f0900..9b00f4cbc90 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -1127,6 +1127,11 @@ int omap_dma_running(void)
void omap_dma_link_lch(int lch_head, int lch_queue)
{
if (omap_dma_in_1510_mode()) {
+ if (lch_head == lch_queue) {
+ dma_write(dma_read(CCR(lch_head)) | (3 << 8),
+ CCR(lch_head));
+ return;
+ }
printk(KERN_ERR "DMA linking is not supported in 1510 mode\n");
BUG();
return;
@@ -1149,6 +1154,11 @@ EXPORT_SYMBOL(omap_dma_link_lch);
void omap_dma_unlink_lch(int lch_head, int lch_queue)
{
if (omap_dma_in_1510_mode()) {
+ if (lch_head == lch_queue) {
+ dma_write(dma_read(CCR(lch_head)) & ~(3 << 8),
+ CCR(lch_head));
+ return;
+ }
printk(KERN_ERR "DMA linking is not supported in 1510 mode\n");
BUG();
return;
diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h
index bb154ea7676..63a3f254af7 100644
--- a/arch/arm/plat-omap/include/mach/mcbsp.h
+++ b/arch/arm/plat-omap/include/mach/mcbsp.h
@@ -134,6 +134,11 @@
#define OMAP_MCBSP_REG_XCERG 0x74
#define OMAP_MCBSP_REG_XCERH 0x78
#define OMAP_MCBSP_REG_SYSCON 0x8C
+#define OMAP_MCBSP_REG_THRSH2 0x90
+#define OMAP_MCBSP_REG_THRSH1 0x94
+#define OMAP_MCBSP_REG_IRQST 0xA0
+#define OMAP_MCBSP_REG_IRQEN 0xA4
+#define OMAP_MCBSP_REG_WAKEUPEN 0xA8
#define OMAP_MCBSP_REG_XCCR 0xAC
#define OMAP_MCBSP_REG_RCCR 0xB0
@@ -249,8 +254,27 @@
#define RDISABLE 0x0001
/********************** McBSP SYSCONFIG bit definitions ********************/
+#define CLOCKACTIVITY(value) ((value)<<8)
+#define SIDLEMODE(value) ((value)<<3)
+#define ENAWAKEUP 0x0004
#define SOFTRST 0x0002
+/********************** McBSP DMA operating modes **************************/
+#define MCBSP_DMA_MODE_ELEMENT 0
+#define MCBSP_DMA_MODE_THRESHOLD 1
+#define MCBSP_DMA_MODE_FRAME 2
+
+/********************** McBSP WAKEUPEN bit definitions *********************/
+#define XEMPTYEOFEN 0x4000
+#define XRDYEN 0x0400
+#define XEOFEN 0x0200
+#define XFSXEN 0x0100
+#define XSYNCERREN 0x0080
+#define RRDYEN 0x0008
+#define REOFEN 0x0004
+#define RFSREN 0x0002
+#define RSYNCERREN 0x0001
+
/* we don't do multichannel for now */
struct omap_mcbsp_reg_cfg {
u16 spcr2;
@@ -344,6 +368,9 @@ struct omap_mcbsp_platform_data {
u8 dma_rx_sync, dma_tx_sync;
u16 rx_irq, tx_irq;
struct omap_mcbsp_ops *ops;
+#ifdef CONFIG_ARCH_OMAP34XX
+ u16 buffer_size;
+#endif
};
struct omap_mcbsp {
@@ -377,6 +404,11 @@ struct omap_mcbsp {
struct omap_mcbsp_platform_data *pdata;
struct clk *iclk;
struct clk *fclk;
+#ifdef CONFIG_ARCH_OMAP34XX
+ int dma_op_mode;
+ u16 max_tx_thres;
+ u16 max_rx_thres;
+#endif
};
extern struct omap_mcbsp **mcbsp_ptr;
extern int omap_mcbsp_count;
@@ -385,10 +417,25 @@ int omap_mcbsp_init(void);
void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config,
int size);
void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config);
+#ifdef CONFIG_ARCH_OMAP34XX
+void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold);
+void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold);
+u16 omap_mcbsp_get_max_tx_threshold(unsigned int id);
+u16 omap_mcbsp_get_max_rx_threshold(unsigned int id);
+int omap_mcbsp_get_dma_op_mode(unsigned int id);
+#else
+static inline void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
+{ }
+static inline void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold)
+{ }
+static inline u16 omap_mcbsp_get_max_tx_threshold(unsigned int id) { return 0; }
+static inline u16 omap_mcbsp_get_max_rx_threshold(unsigned int id) { return 0; }
+static inline int omap_mcbsp_get_dma_op_mode(unsigned int id) { return 0; }
+#endif
int omap_mcbsp_request(unsigned int id);
void omap_mcbsp_free(unsigned int id);
-void omap_mcbsp_start(unsigned int id);
-void omap_mcbsp_stop(unsigned int id);
+void omap_mcbsp_start(unsigned int id, int tx, int rx);
+void omap_mcbsp_stop(unsigned int id, int tx, int rx);
void omap_mcbsp_xmit_word(unsigned int id, u32 word);
u32 omap_mcbsp_recv_word(unsigned int id);
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index efa0e0111f3..8dc7927906f 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -198,6 +198,170 @@ void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config)
}
EXPORT_SYMBOL(omap_mcbsp_config);
+#ifdef CONFIG_ARCH_OMAP34XX
+/*
+ * omap_mcbsp_set_tx_threshold configures how to deal
+ * with transmit threshold. the threshold value and handler can be
+ * configure in here.
+ */
+void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
+{
+ struct omap_mcbsp *mcbsp;
+ void __iomem *io_base;
+
+ if (!cpu_is_omap34xx())
+ return;
+
+ if (!omap_mcbsp_check_valid_id(id)) {
+ printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
+ return;
+ }
+ mcbsp = id_to_mcbsp_ptr(id);
+ io_base = mcbsp->io_base;
+
+ OMAP_MCBSP_WRITE(io_base, THRSH2, threshold);
+}
+EXPORT_SYMBOL(omap_mcbsp_set_tx_threshold);
+
+/*
+ * omap_mcbsp_set_rx_threshold configures how to deal
+ * with receive threshold. the threshold value and handler can be
+ * configure in here.
+ */
+void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold)
+{
+ struct omap_mcbsp *mcbsp;
+ void __iomem *io_base;
+
+ if (!cpu_is_omap34xx())
+ return;
+
+ if (!omap_mcbsp_check_valid_id(id)) {
+ printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
+ return;
+ }
+ mcbsp = id_to_mcbsp_ptr(id);
+ io_base = mcbsp->io_base;
+
+ OMAP_MCBSP_WRITE(io_base, THRSH1, threshold);
+}
+EXPORT_SYMBOL(omap_mcbsp_set_rx_threshold);
+
+/*
+ * omap_mcbsp_get_max_tx_thres just return the current configured
+ * maximum threshold for transmission
+ */
+u16 omap_mcbsp_get_max_tx_threshold(unsigned int id)
+{
+ struct omap_mcbsp *mcbsp;
+
+ 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);
+
+ return mcbsp->max_tx_thres;
+}
+EXPORT_SYMBOL(omap_mcbsp_get_max_tx_threshold);
+
+/*
+ * omap_mcbsp_get_max_rx_thres just return the current configured
+ * maximum threshold for reception
+ */
+u16 omap_mcbsp_get_max_rx_threshold(unsigned int id)
+{
+ struct omap_mcbsp *mcbsp;
+
+ 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);
+
+ return mcbsp->max_rx_thres;
+}
+EXPORT_SYMBOL(omap_mcbsp_get_max_rx_threshold);
+
+/*
+ * omap_mcbsp_get_dma_op_mode just return the current configured
+ * operating mode for the mcbsp channel
+ */
+int omap_mcbsp_get_dma_op_mode(unsigned int id)
+{
+ struct omap_mcbsp *mcbsp;
+ int dma_op_mode;
+
+ if (!omap_mcbsp_check_valid_id(id)) {
+ printk(KERN_ERR "%s: Invalid id (%u)\n", __func__, id + 1);
+ return -ENODEV;
+ }
+ mcbsp = id_to_mcbsp_ptr(id);
+
+ spin_lock_irq(&mcbsp->lock);
+ dma_op_mode = mcbsp->dma_op_mode;
+ spin_unlock_irq(&mcbsp->lock);
+
+ return dma_op_mode;
+}
+EXPORT_SYMBOL(omap_mcbsp_get_dma_op_mode);
+
+static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp)
+{
+ /*
+ * Enable wakup behavior, smart idle and all wakeups
+ * REVISIT: some wakeups may be unnecessary
+ */
+ if (cpu_is_omap34xx()) {
+ u16 syscon;
+
+ syscon = OMAP_MCBSP_READ(mcbsp->io_base, SYSCON);
+ syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03));
+
+ spin_lock_irq(&mcbsp->lock);
+ if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
+ syscon |= (ENAWAKEUP | SIDLEMODE(0x02) |
+ CLOCKACTIVITY(0x02));
+ OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN,
+ XRDYEN | RRDYEN);
+ } else {
+ syscon |= SIDLEMODE(0x01);
+ }
+ spin_unlock_irq(&mcbsp->lock);
+
+ OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon);
+ }
+}
+
+static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp)
+{
+ /*
+ * Disable wakup behavior, smart idle and all wakeups
+ */
+ if (cpu_is_omap34xx()) {
+ u16 syscon;
+
+ syscon = OMAP_MCBSP_READ(mcbsp->io_base, SYSCON);
+ syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03));
+ /*
+ * HW bug workaround - If no_idle mode is taken, we need to
+ * go to smart_idle before going to always_idle, or the
+ * device will not hit retention anymore.
+ */
+ syscon |= SIDLEMODE(0x02);
+ OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon);
+
+ syscon &= ~(SIDLEMODE(0x03));
+ OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon);
+
+ OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, 0);
+ }
+}
+#else
+static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) {}
+static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) {}
+#endif
+
/*
* We can choose between IRQ based or polled IO.
* This needs to be called before omap_mcbsp_request().
@@ -257,6 +421,9 @@ int omap_mcbsp_request(unsigned int id)
clk_enable(mcbsp->iclk);
clk_enable(mcbsp->fclk);
+ /* Do procedure specific to omap34xx arch, if applicable */
+ omap34xx_mcbsp_request(mcbsp);
+
/*
* Make sure that transmitter, receiver and sample-rate generator are
* not running before activating IRQs.
@@ -305,6 +472,9 @@ void omap_mcbsp_free(unsigned int id)
if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
mcbsp->pdata->ops->free(id);
+ /* Do procedure specific to omap34xx arch, if applicable */
+ omap34xx_mcbsp_free(mcbsp);
+
clk_disable(mcbsp->fclk);
clk_disable(mcbsp->iclk);
@@ -328,14 +498,15 @@ void omap_mcbsp_free(unsigned int id)
EXPORT_SYMBOL(omap_mcbsp_free);
/*
- * Here we start the McBSP, by enabling the sample
- * generator, both transmitter and receivers,
- * and the frame sync.
+ * Here we start the McBSP, by enabling transmitter, receiver or both.
+ * If no transmitter or receiver is active prior calling, then sample-rate
+ * generator and frame sync are started.
*/
-void omap_mcbsp_start(unsigned int id)
+void omap_mcbsp_start(unsigned int id, int tx, int rx)
{
struct omap_mcbsp *mcbsp;
void __iomem *io_base;
+ int idle;
u16 w;
if (!omap_mcbsp_check_valid_id(id)) {
@@ -348,32 +519,58 @@ void omap_mcbsp_start(unsigned int id)
mcbsp->rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7;
mcbsp->tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7;
- /* Start the sample generator */
- w = OMAP_MCBSP_READ(io_base, SPCR2);
- OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));
+ idle = !((OMAP_MCBSP_READ(io_base, SPCR2) |
+ OMAP_MCBSP_READ(io_base, SPCR1)) & 1);
+
+ if (idle) {
+ /* Start the sample generator */
+ w = OMAP_MCBSP_READ(io_base, SPCR2);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));
+ }
/* Enable transmitter and receiver */
+ tx &= 1;
w = OMAP_MCBSP_READ(io_base, SPCR2);
- OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, w | tx);
+ rx &= 1;
w = OMAP_MCBSP_READ(io_base, SPCR1);
- OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1);
+ OMAP_MCBSP_WRITE(io_base, SPCR1, w | rx);
- udelay(100);
+ /*
+ * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec
+ * REVISIT: 100us may give enough time for two CLKSRG, however
+ * due to some unknown PM related, clock gating etc. reason it
+ * is now at 500us.
+ */
+ udelay(500);
- /* Start frame sync */
- w = OMAP_MCBSP_READ(io_base, SPCR2);
- OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));
+ if (idle) {
+ /* Start frame sync */
+ w = OMAP_MCBSP_READ(io_base, SPCR2);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));
+ }
+
+ if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+ /* Release the transmitter and receiver */
+ w = OMAP_MCBSP_READ(io_base, XCCR);
+ w &= ~(tx ? XDISABLE : 0);
+ OMAP_MCBSP_WRITE(io_base, XCCR, w);
+ w = OMAP_MCBSP_READ(io_base, RCCR);
+ w &= ~(rx ? RDISABLE : 0);
+ OMAP_MCBSP_WRITE(io_base, RCCR, w);
+ }
/* Dump McBSP Regs */
omap_mcbsp_dump_reg(id);
}
EXPORT_SYMBOL(omap_mcbsp_start);
-void omap_mcbsp_stop(unsigned int id)
+void omap_mcbsp_stop(unsigned int id, int tx, int rx)
{
struct omap_mcbsp *mcbsp;
void __iomem *io_base;
+ int idle;
u16 w;
if (!omap_mcbsp_check_valid_id(id)) {
@@ -385,16 +582,33 @@ void omap_mcbsp_stop(unsigned int id)
io_base = mcbsp->io_base;
/* Reset transmitter */
+ tx &= 1;
+ if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+ w = OMAP_MCBSP_READ(io_base, XCCR);
+ w |= (tx ? XDISABLE : 0);
+ OMAP_MCBSP_WRITE(io_base, XCCR, w);
+ }
w = OMAP_MCBSP_READ(io_base, SPCR2);
- OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1));
+ OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~tx);
/* Reset receiver */
+ rx &= 1;
+ if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+ w = OMAP_MCBSP_READ(io_base, RCCR);
+ w |= (tx ? RDISABLE : 0);
+ OMAP_MCBSP_WRITE(io_base, RCCR, w);
+ }
w = OMAP_MCBSP_READ(io_base, SPCR1);
- OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1));
+ OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~rx);
- /* Reset the sample rate generator */
- w = OMAP_MCBSP_READ(io_base, SPCR2);
- OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));
+ idle = !((OMAP_MCBSP_READ(io_base, SPCR2) |
+ OMAP_MCBSP_READ(io_base, SPCR1)) & 1);
+
+ if (idle) {
+ /* Reset the sample rate generator */
+ w = OMAP_MCBSP_READ(io_base, SPCR2);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));
+ }
}
EXPORT_SYMBOL(omap_mcbsp_stop);
@@ -883,6 +1097,149 @@ void omap_mcbsp_set_spi_mode(unsigned int id,
}
EXPORT_SYMBOL(omap_mcbsp_set_spi_mode);
+#ifdef CONFIG_ARCH_OMAP34XX
+#define max_thres(m) (mcbsp->pdata->buffer_size)
+#define valid_threshold(m, val) ((val) <= max_thres(m))
+#define THRESHOLD_PROP_BUILDER(prop) \
+static ssize_t prop##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
+ \
+ return sprintf(buf, "%u\n", mcbsp->prop); \
+} \
+ \
+static ssize_t prop##_store(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t size) \
+{ \
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
+ unsigned long val; \
+ int status; \
+ \
+ status = strict_strtoul(buf, 0, &val); \
+ if (status) \
+ return status; \
+ \
+ if (!valid_threshold(mcbsp, val)) \
+ return -EDOM; \
+ \
+ mcbsp->prop = val; \
+ return size; \
+} \
+ \
+static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store);
+
+THRESHOLD_PROP_BUILDER(max_tx_thres);
+THRESHOLD_PROP_BUILDER(max_rx_thres);
+
+static const char *dma_op_modes[] = {
+ "element", "threshold", "frame",
+};
+
+static ssize_t dma_op_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+ int dma_op_mode, i = 0;
+ ssize_t len = 0;
+ const char * const *s;
+
+ spin_lock_irq(&mcbsp->lock);
+ dma_op_mode = mcbsp->dma_op_mode;
+ spin_unlock_irq(&mcbsp->lock);
+
+ for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) {
+ if (dma_op_mode == i)
+ len += sprintf(buf + len, "[%s] ", *s);
+ else
+ len += sprintf(buf + len, "%s ", *s);
+ }
+ len += sprintf(buf + len, "\n");
+
+ return len;
+}
+
+static ssize_t dma_op_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+ const char * const *s;
+ int i = 0;
+
+ for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++)
+ if (sysfs_streq(buf, *s))
+ break;
+
+ if (i == ARRAY_SIZE(dma_op_modes))
+ return -EINVAL;
+
+ spin_lock_irq(&mcbsp->lock);
+ if (!mcbsp->free) {
+ size = -EBUSY;
+ goto unlock;
+ }
+ mcbsp->dma_op_mode = i;
+
+unlock:
+ spin_unlock_irq(&mcbsp->lock);
+
+ return size;
+}
+
+static DEVICE_ATTR(dma_op_mode, 0644, dma_op_mode_show, dma_op_mode_store);
+
+static const struct attribute *additional_attrs[] = {
+ &dev_attr_max_tx_thres.attr,
+ &dev_attr_max_rx_thres.attr,
+ &dev_attr_dma_op_mode.attr,
+ NULL,
+};
+
+static const struct attribute_group additional_attr_group = {
+ .attrs = (struct attribute **)additional_attrs,
+};
+
+static inline int __devinit omap_additional_add(struct device *dev)
+{
+ return sysfs_create_group(&dev->kobj, &additional_attr_group);
+}
+
+static inline void __devexit omap_additional_remove(struct device *dev)
+{
+ sysfs_remove_group(&dev->kobj, &additional_attr_group);
+}
+
+static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp)
+{
+ mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
+ if (cpu_is_omap34xx()) {
+ mcbsp->max_tx_thres = max_thres(mcbsp);
+ mcbsp->max_rx_thres = max_thres(mcbsp);
+ /*
+ * REVISIT: Set dmap_op_mode to THRESHOLD as default
+ * for mcbsp2 instances.
+ */
+ if (omap_additional_add(mcbsp->dev))
+ dev_warn(mcbsp->dev,
+ "Unable to create additional controls\n");
+ } else {
+ mcbsp->max_tx_thres = -EINVAL;
+ mcbsp->max_rx_thres = -EINVAL;
+ }
+}
+
+static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp)
+{
+ if (cpu_is_omap34xx())
+ omap_additional_remove(mcbsp->dev);
+}
+#else
+static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) {}
+static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp) {}
+#endif /* CONFIG_ARCH_OMAP34XX */
+
/*
* McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
* 730 has only 2 McBSP, and both of them are MPU peripherals.
@@ -953,6 +1310,10 @@ static int __devinit omap_mcbsp_probe(struct platform_device *pdev)
mcbsp->dev = &pdev->dev;
mcbsp_ptr[id] = mcbsp;
platform_set_drvdata(pdev, mcbsp);
+
+ /* Initialize mcbsp properties for OMAP34XX if needed / applicable */
+ omap34xx_device_init(mcbsp);
+
return 0;
err_fclk:
@@ -976,6 +1337,8 @@ static int __devexit omap_mcbsp_remove(struct platform_device *pdev)
mcbsp->pdata->ops->free)
mcbsp->pdata->ops->free(mcbsp->id);
+ omap34xx_device_exit(mcbsp);
+
clk_disable(mcbsp->fclk);
clk_disable(mcbsp->iclk);
clk_put(mcbsp->fclk);
diff --git a/arch/arm/plat-s3c/include/plat/audio-simtec.h b/arch/arm/plat-s3c/include/plat/audio-simtec.h
new file mode 100644
index 00000000000..0f440b9168d
--- /dev/null
+++ b/arch/arm/plat-s3c/include/plat/audio-simtec.h
@@ -0,0 +1,37 @@
+/* arch/arm/plat-s3c/include/plat/audio-simtec.h
+ *
+ * Copyright 2008 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Simtec Audio support.
+*/
+
+/**
+ * struct s3c24xx_audio_simtec_pdata - platform data for simtec audio
+ * @use_mpllin: Select codec clock from MPLLin
+ * @output_cdclk: Need to output CDCLK to the codec
+ * @have_mic: Set if we have a MIC socket
+ * @have_lout: Set if we have a LineOut socket
+ * @amp_gpio: GPIO pin to enable the AMP
+ * @amp_gain: Option GPIO to control AMP gain
+ */
+struct s3c24xx_audio_simtec_pdata {
+ unsigned int use_mpllin:1;
+ unsigned int output_cdclk:1;
+
+ unsigned int have_mic:1;
+ unsigned int have_lout:1;
+
+ int amp_gpio;
+ int amp_gain[2];
+
+ void (*startup)(void);
+};
+
+extern int simtec_audio_add(const char *codec_name,
+ struct s3c24xx_audio_simtec_pdata *pdata);
diff --git a/arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h b/arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h
index 0fad7571030..07659dad174 100644
--- a/arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h
+++ b/arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h
@@ -33,6 +33,11 @@
#define S3C2412_IISCON_RXDMA_ACTIVE (1 << 1)
#define S3C2412_IISCON_IIS_ACTIVE (1 << 0)
+#define S3C64XX_IISMOD_BLC_16BIT (0 << 13)
+#define S3C64XX_IISMOD_BLC_8BIT (1 << 13)
+#define S3C64XX_IISMOD_BLC_24BIT (2 << 13)
+#define S3C64XX_IISMOD_BLC_MASK (3 << 13)
+
#define S3C64XX_IISMOD_IMS_PCLK (0 << 10)
#define S3C64XX_IISMOD_IMS_SYSMUX (1 << 10)