[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