Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e0b3032b authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'topic/asoc' into for-linus

* topic/asoc: (226 commits)
  ASoC: au1x: PSC-AC97 bugfixes
  ASoC: Fix WM835x Out4 capture enumeration
  ASoC: Remove unuused hw_read_t
  ASoC: fix pxa2xx-ac97.c breakage
  ASoC: Fully specify DC servo bits to update in wm_hubs
  ASoC: Debugged improper setting of PLL fields in WM8580 driver
  ASoC: new board driver to connect bfin-5xx with ad1836 codec
  ASoC: OMAP: Add functionality to set CLKR and FSR sources in McBSP DAI
  ASoC: davinci: i2c device creation moved into board files
  ASoC: Don't reconfigure WM8350 FLL if not needed
  ASoC: Fix s3c-i2s-v2 build
  ASoC: Make platform data optional for TLV320AIC3x
  ASoC: Add S3C24xx dependencies for Simtec machines
  ASoC: SDP3430: Fix TWL GPIO6 pin mux request
  ASoC: S3C platform: Fix s3c2410_dma_started() called at improper time
  ARM: OMAP: McBSP: Merge two functions into omap_mcbsp_start/_stop
  ASoC: OMAP: Fix setup of XCCR and RCCR registers in McBSP DAI
  OMAP: McBSP: Use textual values in DMA operating mode sysfs files
  ARM: OMAP: DMA: Add support for DMA channel self linking on OMAP1510
  ASoC: Select core DMA when building for S3C64xx
  ...
parents 45fae5c7 cdc65fbe
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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)
+3 −0
Original line number Diff line number Diff line
@@ -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);
+10 −0
Original line number Diff line number Diff line
@@ -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;
+49 −2
Original line number Diff line number Diff line
@@ -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);

+382 −19
Original line number Diff line number Diff line
@@ -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;

	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);

	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,17 +582,34 @@ 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);

	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);

/* polled mcbsp i/o operations */
@@ -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);
Loading