summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorMarcin Bukat <marcin.bukat@gmail.com>2012-08-27 23:18:31 +0200
committerMarcin Bukat <marcin.bukat@gmail.com>2012-08-27 23:18:31 +0200
commitae27c331e10fbdc4cb5516afce5eeb53eacb3962 (patch)
tree52aea83d39bab492c6aa95e967fc69f8b0e69301 /firmware
parent16335da1cfc90fcf559f9d4ab6843708a3613d1c (diff)
downloadrockbox-ae27c331e10fbdc4cb5516afce5eeb53eacb3962.zip
rockbox-ae27c331e10fbdc4cb5516afce5eeb53eacb3962.tar.gz
rockbox-ae27c331e10fbdc4cb5516afce5eeb53eacb3962.tar.bz2
rockbox-ae27c331e10fbdc4cb5516afce5eeb53eacb3962.tar.xz
rk27xx: Turn off i2c clock when not in use
Change-Id: Ifc6c25a53ace1a5f4d716a33d4979ea0a37fac98
Diffstat (limited to 'firmware')
-rw-r--r--firmware/target/arm/rk27xx/i2c-rk27xx.c309
1 files changed, 164 insertions, 145 deletions
diff --git a/firmware/target/arm/rk27xx/i2c-rk27xx.c b/firmware/target/arm/rk27xx/i2c-rk27xx.c
index 6fddde0..3535c68 100644
--- a/firmware/target/arm/rk27xx/i2c-rk27xx.c
+++ b/firmware/target/arm/rk27xx/i2c-rk27xx.c
@@ -40,7 +40,7 @@ static struct mutex i2c_mtx;
static bool i2c_write_byte(uint8_t data, bool start)
{
- long timeout = current_tick + 50;
+ long timeout = current_tick + HZ/50;
/* START */
I2C_CONR |= (1<<3) | (1<<2); /* master port enable, transmit bit */
@@ -66,34 +66,34 @@ static bool i2c_write_byte(uint8_t data, bool start)
static bool i2c_read_byte(unsigned char *data)
{
- long timeout = current_tick + HZ / 50;
+ long timeout = current_tick + HZ/50;
- I2C_LCMR = (1<<2); /* resume op */
+ I2C_LCMR = (1<<2); /* resume op */
- while (!(I2C_ISR & (1<<1)))
- if (TIME_AFTER(current_tick, timeout))
- return false;
+ while (!(I2C_ISR & (1<<1)))
+ if (TIME_AFTER(current_tick, timeout))
+ return false;
- *data = I2C_MRXR;
+ *data = I2C_MRXR;
- /* clear status bit */
- I2C_ISR &= ~(1<<1);
+ /* clear status bit */
+ I2C_ISR &= ~(1<<1);
- return true;
+ return true;
}
static bool i2c_stop(void)
{
- long timeout = current_tick + HZ / 50;
+ long timeout = current_tick + HZ/50;
- I2C_CONR &= ~(1<<4);
- I2C_LCMR |= (1<<2) | (1<<1); /* resume op, stop */
+ I2C_CONR &= ~(1<<4);
+ I2C_LCMR |= (1<<2) | (1<<1); /* resume op, stop */
- while (I2C_LCMR & (1<<1))
- if (TIME_AFTER(current_tick, timeout))
- return false;
+ while (I2C_LCMR & (1<<1))
+ if (TIME_AFTER(current_tick, timeout))
+ return false;
- return true;
+ return true;
}
/* route i2c bus to internal codec or external bus
@@ -103,154 +103,173 @@ static bool i2c_stop(void)
*/
static void i2c_iomux(unsigned char slave)
{
- unsigned long muxa = SCU_IOMUXA_CON & ~(0x1f<<14);
-
- if ((slave & 0xfe) == (0x27<<1))
- {
- /* internal codec */
- SCU_IOMUXA_CON = (muxa | (1<<16) | (1<<14));
- }
- else
- {
- /* external I2C bus */
- SCU_IOMUXA_CON = (muxa | (1<<18));
- }
+ unsigned long muxa = SCU_IOMUXA_CON & ~(0x1f<<14);
+
+ if ((slave & 0xfe) == (0x27<<1))
+ {
+ /* internal codec */
+ SCU_IOMUXA_CON = (muxa | (1<<16) | (1<<14));
+ }
+ else
+ {
+ /* external I2C bus */
+ SCU_IOMUXA_CON = (muxa | (1<<18));
+ }
}
void i2c_init(void)
{
- mutex_init(&i2c_mtx);
+ mutex_init(&i2c_mtx);
- SCU_CLKCFG &= ~(1<< 20);
- I2C_OPR |= (1<<7); /* reset state machine */
- sleep(HZ/100);
- I2C_OPR &= ~((1<<7) | (1<<6)); /* clear ENABLE bit, deasert reset */
+ /* ungate i2c module clock */
+ SCU_CLKCFG &= ~(1<< 20);
- /* set I2C divider to stay within allowed SCL freq limit
- * APBfreq = 50Mhz
- * SCLfreq = (APBfreq/5*(I2CCDVR[5:3] + 1) * 2^((I2CCDVR[2:0] + 1))
- */
+ I2C_OPR |= (1<<7); /* reset state machine */
+ sleep(HZ/100);
+ I2C_OPR &= ~((1<<7) | (1<<6)); /* clear ENABLE bit, deasert reset */
- /* we are driving this slightly above specs
- * (6<<3) | (1<<0) 416kHz
- * (7<<3) | (1<<0) 357kHz
- * (6<<3) | (2<<0) 208kHz
- */
- I2C_OPR = (I2C_OPR & ~(0x3F)) | (6<<3) | (1<<0);
+ /* set I2C divider to stay within allowed SCL freq limit
+ * APBfreq = 50Mhz
+ * SCLfreq = (APBfreq/5*(I2CCDVR[5:3] + 1) * 2^((I2CCDVR[2:0] + 1))
+ */
- I2C_IER = 0x00;
+ /* we are driving this slightly above specs
+ * (6<<3) | (1<<0) 416kHz
+ * (7<<3) | (1<<0) 357kHz
+ * (6<<3) | (2<<0) 208kHz
+ */
+ I2C_OPR = (I2C_OPR & ~(0x3F)) | (6<<3) | (1<<0);
- I2C_OPR |= (1<<6); /* enable i2c core */
+ I2C_IER = 0x00;
+
+ I2C_OPR |= (1<<6); /* enable i2c core */
+
+ /* turn off i2c module clock until we need to comunicate */
+ SCU_CLKCFG |= (1<< 20);
}
int i2c_write(unsigned char slave, int address, int len,
const unsigned char *data)
{
- mutex_lock(&i2c_mtx);
-
- i2c_iomux(slave);
-
- /* clear all flags */
- I2C_ISR = 0x00;
- I2C_IER = 0x00;
-
- /* START */
- if (! i2c_write_byte(slave & ~1, true))
- {
- mutex_unlock(&i2c_mtx);
- return 1;
- }
-
- if (address >= 0)
- {
- if (! i2c_write_byte(address, false))
- {
- mutex_unlock(&i2c_mtx);
- return 2;
- }
- }
-
- /* write data */
- while (len--)
- {
- if (! i2c_write_byte(*data++, false))
- {
- mutex_unlock(&i2c_mtx);
- return 4;
- }
- }
+ int ret = 0;
- /* STOP */
- if (! i2c_stop())
- {
- mutex_unlock(&i2c_mtx);
- return 5;
- }
-
- mutex_unlock(&i2c_mtx);
- return 0;
+ mutex_lock(&i2c_mtx);
+
+ i2c_iomux(slave);
+
+ /* ungate i2c clock */
+ SCU_CLKCFG &= ~(1<<20);
+
+ /* clear all flags */
+ I2C_ISR = 0x00;
+ I2C_IER = 0x00;
+
+ /* START */
+ if (! i2c_write_byte(slave & ~1, true))
+ {
+ ret = 1;
+ goto end;
+ }
+
+ if (address >= 0)
+ {
+ if (! i2c_write_byte(address, false))
+ {
+ ret = 2;
+ goto end;
+ }
+ }
+
+ /* write data */
+ while (len--)
+ {
+ if (! i2c_write_byte(*data++, false))
+ {
+ ret = 4;
+ goto end;
+ }
+ }
+
+ /* STOP */
+ if (! i2c_stop())
+ {
+ ret = 5;
+ goto end;
+ }
+
+end:
+ mutex_unlock(&i2c_mtx);
+ SCU_CLKCFG |= (1<<20);
+ return ret;
}
int i2c_read(unsigned char slave, int address, int len, unsigned char *data)
{
- mutex_lock(&i2c_mtx);
-
- i2c_iomux(slave);
-
- /* clear all flags */
- I2C_ISR = 0x00;
- I2C_IER = 0x00;
-
- if (address >= 0)
- {
- /* START */
- if (! i2c_write_byte(slave & ~1, true))
- {
- mutex_unlock(&i2c_mtx);
- return 1;
- }
-
- /* write address */
- if (! i2c_write_byte(address, false))
- {
- mutex_unlock(&i2c_mtx);
- return 2;
- }
- }
-
- /* (repeated) START */
- if (! i2c_write_byte(slave | 1, true))
- {
- mutex_unlock(&i2c_mtx);
- return 3;
- }
-
- I2C_CONR &= ~(1<<3); /* clear transmit bit (switch to receive mode) */
-
- while (len)
- {
- if (! i2c_read_byte(data++))
- {
- mutex_unlock(&i2c_mtx);
- return 4;
- }
-
- if (len == 1)
- I2C_CONR |= (1<<4); /* NACK */
- else
- I2C_CONR &= ~(1<<4); /* ACK */
-
- len--;
- }
+ int ret = 0;
+
+ mutex_lock(&i2c_mtx);
+
+ i2c_iomux(slave);
+
+ /* ungate i2c module clock */
+ SCU_CLKCFG &= ~(1<<20);
+
+ /* clear all flags */
+ I2C_ISR = 0x00;
+ I2C_IER = 0x00;
+
+ if (address >= 0)
+ {
+ /* START */
+ if (! i2c_write_byte(slave & ~1, true))
+ {
+ ret = 1;
+ goto end;
+ }
+
+ /* write address */
+ if (! i2c_write_byte(address, false))
+ {
+ ret = 2;
+ goto end;
+ }
+ }
+
+ /* (repeated) START */
+ if (! i2c_write_byte(slave | 1, true))
+ {
+ ret = 3;
+ goto end;
+ }
+
+ I2C_CONR &= ~(1<<3); /* clear transmit bit (switch to receive mode) */
+
+ while (len)
+ {
+ if (! i2c_read_byte(data++))
+ {
+ ret = 4;
+ goto end;
+ }
+
+ if (len == 1)
+ I2C_CONR |= (1<<4); /* NACK */
+ else
+ I2C_CONR &= ~(1<<4); /* ACK */
+
+ len--;
+ }
/* STOP */
- if (! i2c_stop())
- {
- mutex_unlock(&i2c_mtx);
- return 5;
- }
-
- mutex_unlock(&i2c_mtx);
- return 0;
+ if (! i2c_stop())
+ {
+ ret = 5;
+ goto end;
+ }
+
+end:
+ mutex_unlock(&i2c_mtx);
+ SCU_CLKCFG |= (1<<20);
+ return ret;
}