[alsa-devel] [PATCH 2/4] OMAP: mcbsp - add smart idle configuration API

Liam Girdwood lrg at slimlogic.co.uk
Tue May 18 22:13:12 CEST 2010


Add a small API to configure McBSP smart idle modes
to conserve power.

Signed-off-by: Liam Girdwood <lrg at slimlogic.co.uk>
---
 arch/arm/plat-omap/include/plat/mcbsp.h |   15 ++++
 arch/arm/plat-omap/mcbsp.c              |  122 +++++++++++++++++++++++++++++++
 2 files changed, 137 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h
index f8823f4..3f9fb71 100644
--- a/arch/arm/plat-omap/include/plat/mcbsp.h
+++ b/arch/arm/plat-omap/include/plat/mcbsp.h
@@ -278,6 +278,15 @@
 #define ENAWAKEUP		0x0004
 #define SOFTRST			0x0002
 
+#define MCBSP_CLK_ACT_IOFF_POFF		0
+#define MCBSP_CLK_ACT_ION_POFF		1
+#define MCBSP_CLK_ACT_IOFF_PON		2
+#define MCBSP_CLK_ACT_ION_PON			3
+
+#define MCBSP_IDLE_FORCE	0
+#define MCBSP_IDLE_NONE		1
+#define MCBSP_IDLE_SMART	2
+
 /********************** McBSP SSELCR bit definitions ***********************/
 #define SIDETONEEN		0x0400
 
@@ -456,6 +465,7 @@ struct omap_mcbsp {
 #ifdef CONFIG_ARCH_OMAP3
 	struct omap_mcbsp_st_data *st_data;
 	int dma_op_mode;
+	int idle_mode;
 	u16 max_tx_thres;
 	u16 max_rx_thres;
 #endif
@@ -477,6 +487,11 @@ u16 omap_mcbsp_get_tx_delay(unsigned int id);
 u16 omap_mcbsp_get_rx_delay(unsigned int id);
 int omap_mcbsp_get_dma_op_mode(unsigned int id);
 int omap_mcbsp_set_dma_op_mode(unsigned int id, unsigned int mode);
+int omap_mcbsp_set_idle_smart(unsigned int id, unsigned int clk_activity,
+		unsigned int wake);
+int omap_mcbsp_set_idle_none(unsigned int id);
+int omap_mcbsp_set_idle_force(unsigned int id);
+int omap_mcbsp_get_idle_mode(unsigned int id);
 #else
 static inline void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
 { }
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index cc2b73c..7785050 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -1743,6 +1743,128 @@ static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp)
 			omap_st_remove(mcbsp);
 	}
 }
+
+/* assert standby requests when idle */
+int omap_mcbsp_set_idle_smart(unsigned int id, unsigned int clk_activity,
+		u32 wakeup)
+{
+	struct omap_mcbsp *mcbsp;
+	u16 syscon;
+	int ret = 0;
+
+	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);
+	if (!mcbsp->free) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	syscon = MCBSP_READ(mcbsp, SYSCON) &
+			~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03));
+	MCBSP_WRITE(mcbsp, WAKEUPEN, wakeup);
+	MCBSP_WRITE(mcbsp, SYSCON,
+			syscon | SIDLEMODE(MCBSP_IDLE_SMART) |
+			CLOCKACTIVITY(clk_activity) | ENAWAKEUP);
+	mcbsp->idle_mode = MCBSP_IDLE_SMART;
+
+unlock:
+	spin_unlock_irq(&mcbsp->lock);
+	return ret;
+}
+EXPORT_SYMBOL(omap_mcbsp_set_idle_smart);
+
+/* never assert standby requests */
+int omap_mcbsp_set_idle_none(unsigned int id)
+{
+	struct omap_mcbsp *mcbsp;
+	u16 syscon;
+	int ret = 0;
+
+	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);
+	if (!mcbsp->free) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	syscon = MCBSP_READ(mcbsp, SYSCON) &
+			~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03));
+
+	MCBSP_WRITE(mcbsp, SYSCON, syscon | SIDLEMODE(MCBSP_IDLE_NONE));
+	MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
+	mcbsp->idle_mode = MCBSP_IDLE_NONE;
+
+unlock:
+	spin_unlock_irq(&mcbsp->lock);
+	return ret;
+}
+EXPORT_SYMBOL(omap_mcbsp_set_idle_none);
+
+/* unconditionally assert standby requests */
+int omap_mcbsp_set_idle_force(unsigned int id)
+{
+	struct omap_mcbsp *mcbsp;
+	u16 syscon;
+	int ret = 0;
+
+	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);
+	if (!mcbsp->free) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	syscon = MCBSP_READ(mcbsp, 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(MCBSP_IDLE_SMART);
+	MCBSP_WRITE(mcbsp, SYSCON, syscon);
+	syscon &= ~(SIDLEMODE(0x03));
+
+	MCBSP_WRITE(mcbsp, SYSCON, syscon | SIDLEMODE(MCBSP_IDLE_FORCE));
+	MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
+	mcbsp->idle_mode = MCBSP_IDLE_FORCE;
+
+unlock:
+	spin_unlock_irq(&mcbsp->lock);
+	return ret;
+}
+EXPORT_SYMBOL(omap_mcbsp_set_idle_force);
+
+int omap_mcbsp_get_idle_mode(unsigned int id)
+{
+	struct omap_mcbsp *mcbsp;
+
+	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);
+
+	return mcbsp->idle_mode;
+}
+EXPORT_SYMBOL(omap_mcbsp_get_idle_mode);
+
+
 #else
 static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) {}
 static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp) {}
-- 
1.7.0.4



More information about the Alsa-devel mailing list