mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-11-10 05:32:40 -05:00
rk27xx: Turn off i2c clock when not in use
Change-Id: Ifc6c25a53ace1a5f4d716a33d4979ea0a37fac98
This commit is contained in:
parent
16335da1cf
commit
ae27c331e1
1 changed files with 147 additions and 128 deletions
|
|
@ -40,7 +40,7 @@ static struct mutex i2c_mtx;
|
||||||
|
|
||||||
static bool i2c_write_byte(uint8_t data, bool start)
|
static bool i2c_write_byte(uint8_t data, bool start)
|
||||||
{
|
{
|
||||||
long timeout = current_tick + 50;
|
long timeout = current_tick + HZ/50;
|
||||||
|
|
||||||
/* START */
|
/* START */
|
||||||
I2C_CONR |= (1<<3) | (1<<2); /* master port enable, transmit bit */
|
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)
|
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)))
|
while (!(I2C_ISR & (1<<1)))
|
||||||
if (TIME_AFTER(current_tick, timeout))
|
if (TIME_AFTER(current_tick, timeout))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*data = I2C_MRXR;
|
*data = I2C_MRXR;
|
||||||
|
|
||||||
/* clear status bit */
|
/* clear status bit */
|
||||||
I2C_ISR &= ~(1<<1);
|
I2C_ISR &= ~(1<<1);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool i2c_stop(void)
|
static bool i2c_stop(void)
|
||||||
{
|
{
|
||||||
long timeout = current_tick + HZ / 50;
|
long timeout = current_tick + HZ/50;
|
||||||
|
|
||||||
I2C_CONR &= ~(1<<4);
|
I2C_CONR &= ~(1<<4);
|
||||||
I2C_LCMR |= (1<<2) | (1<<1); /* resume op, stop */
|
I2C_LCMR |= (1<<2) | (1<<1); /* resume op, stop */
|
||||||
|
|
||||||
while (I2C_LCMR & (1<<1))
|
while (I2C_LCMR & (1<<1))
|
||||||
if (TIME_AFTER(current_tick, timeout))
|
if (TIME_AFTER(current_tick, timeout))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* route i2c bus to internal codec or external bus
|
/* 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)
|
static void i2c_iomux(unsigned char slave)
|
||||||
{
|
{
|
||||||
unsigned long muxa = SCU_IOMUXA_CON & ~(0x1f<<14);
|
unsigned long muxa = SCU_IOMUXA_CON & ~(0x1f<<14);
|
||||||
|
|
||||||
if ((slave & 0xfe) == (0x27<<1))
|
if ((slave & 0xfe) == (0x27<<1))
|
||||||
{
|
{
|
||||||
/* internal codec */
|
/* internal codec */
|
||||||
SCU_IOMUXA_CON = (muxa | (1<<16) | (1<<14));
|
SCU_IOMUXA_CON = (muxa | (1<<16) | (1<<14));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* external I2C bus */
|
/* external I2C bus */
|
||||||
SCU_IOMUXA_CON = (muxa | (1<<18));
|
SCU_IOMUXA_CON = (muxa | (1<<18));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void i2c_init(void)
|
void i2c_init(void)
|
||||||
{
|
{
|
||||||
mutex_init(&i2c_mtx);
|
mutex_init(&i2c_mtx);
|
||||||
|
|
||||||
SCU_CLKCFG &= ~(1<< 20);
|
|
||||||
|
|
||||||
I2C_OPR |= (1<<7); /* reset state machine */
|
/* ungate i2c module clock */
|
||||||
sleep(HZ/100);
|
SCU_CLKCFG &= ~(1<< 20);
|
||||||
I2C_OPR &= ~((1<<7) | (1<<6)); /* clear ENABLE bit, deasert reset */
|
|
||||||
|
|
||||||
/* set I2C divider to stay within allowed SCL freq limit
|
I2C_OPR |= (1<<7); /* reset state machine */
|
||||||
* APBfreq = 50Mhz
|
sleep(HZ/100);
|
||||||
* SCLfreq = (APBfreq/5*(I2CCDVR[5:3] + 1) * 2^((I2CCDVR[2:0] + 1))
|
I2C_OPR &= ~((1<<7) | (1<<6)); /* clear ENABLE bit, deasert reset */
|
||||||
*/
|
|
||||||
|
|
||||||
/* we are driving this slightly above specs
|
/* set I2C divider to stay within allowed SCL freq limit
|
||||||
* (6<<3) | (1<<0) 416kHz
|
* APBfreq = 50Mhz
|
||||||
* (7<<3) | (1<<0) 357kHz
|
* SCLfreq = (APBfreq/5*(I2CCDVR[5:3] + 1) * 2^((I2CCDVR[2:0] + 1))
|
||||||
* (6<<3) | (2<<0) 208kHz
|
*/
|
||||||
*/
|
|
||||||
I2C_OPR = (I2C_OPR & ~(0x3F)) | (6<<3) | (1<<0);
|
|
||||||
|
|
||||||
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,
|
int i2c_write(unsigned char slave, int address, int len,
|
||||||
const unsigned char *data)
|
const unsigned char *data)
|
||||||
{
|
{
|
||||||
mutex_lock(&i2c_mtx);
|
int ret = 0;
|
||||||
|
|
||||||
i2c_iomux(slave);
|
mutex_lock(&i2c_mtx);
|
||||||
|
|
||||||
/* clear all flags */
|
i2c_iomux(slave);
|
||||||
I2C_ISR = 0x00;
|
|
||||||
I2C_IER = 0x00;
|
|
||||||
|
|
||||||
/* START */
|
/* ungate i2c clock */
|
||||||
if (! i2c_write_byte(slave & ~1, true))
|
SCU_CLKCFG &= ~(1<<20);
|
||||||
{
|
|
||||||
mutex_unlock(&i2c_mtx);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (address >= 0)
|
/* clear all flags */
|
||||||
{
|
I2C_ISR = 0x00;
|
||||||
if (! i2c_write_byte(address, false))
|
I2C_IER = 0x00;
|
||||||
{
|
|
||||||
mutex_unlock(&i2c_mtx);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write data */
|
/* START */
|
||||||
while (len--)
|
if (! i2c_write_byte(slave & ~1, true))
|
||||||
{
|
{
|
||||||
if (! i2c_write_byte(*data++, false))
|
ret = 1;
|
||||||
{
|
goto end;
|
||||||
mutex_unlock(&i2c_mtx);
|
}
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* STOP */
|
if (address >= 0)
|
||||||
if (! i2c_stop())
|
{
|
||||||
{
|
if (! i2c_write_byte(address, false))
|
||||||
mutex_unlock(&i2c_mtx);
|
{
|
||||||
return 5;
|
ret = 2;
|
||||||
}
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mutex_unlock(&i2c_mtx);
|
/* write data */
|
||||||
return 0;
|
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)
|
int i2c_read(unsigned char slave, int address, int len, unsigned char *data)
|
||||||
{
|
{
|
||||||
mutex_lock(&i2c_mtx);
|
int ret = 0;
|
||||||
|
|
||||||
i2c_iomux(slave);
|
mutex_lock(&i2c_mtx);
|
||||||
|
|
||||||
/* clear all flags */
|
i2c_iomux(slave);
|
||||||
I2C_ISR = 0x00;
|
|
||||||
I2C_IER = 0x00;
|
|
||||||
|
|
||||||
if (address >= 0)
|
/* ungate i2c module clock */
|
||||||
{
|
SCU_CLKCFG &= ~(1<<20);
|
||||||
/* START */
|
|
||||||
if (! i2c_write_byte(slave & ~1, true))
|
|
||||||
{
|
|
||||||
mutex_unlock(&i2c_mtx);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write address */
|
/* clear all flags */
|
||||||
if (! i2c_write_byte(address, false))
|
I2C_ISR = 0x00;
|
||||||
{
|
I2C_IER = 0x00;
|
||||||
mutex_unlock(&i2c_mtx);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (repeated) START */
|
if (address >= 0)
|
||||||
if (! i2c_write_byte(slave | 1, true))
|
{
|
||||||
{
|
/* START */
|
||||||
mutex_unlock(&i2c_mtx);
|
if (! i2c_write_byte(slave & ~1, true))
|
||||||
return 3;
|
{
|
||||||
}
|
ret = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
I2C_CONR &= ~(1<<3); /* clear transmit bit (switch to receive mode) */
|
/* write address */
|
||||||
|
if (! i2c_write_byte(address, false))
|
||||||
|
{
|
||||||
|
ret = 2;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (len)
|
/* (repeated) START */
|
||||||
{
|
if (! i2c_write_byte(slave | 1, true))
|
||||||
if (! i2c_read_byte(data++))
|
{
|
||||||
{
|
ret = 3;
|
||||||
mutex_unlock(&i2c_mtx);
|
goto end;
|
||||||
return 4;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (len == 1)
|
I2C_CONR &= ~(1<<3); /* clear transmit bit (switch to receive mode) */
|
||||||
I2C_CONR |= (1<<4); /* NACK */
|
|
||||||
else
|
|
||||||
I2C_CONR &= ~(1<<4); /* ACK */
|
|
||||||
|
|
||||||
len--;
|
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 */
|
/* STOP */
|
||||||
if (! i2c_stop())
|
if (! i2c_stop())
|
||||||
{
|
{
|
||||||
mutex_unlock(&i2c_mtx);
|
ret = 5;
|
||||||
return 5;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&i2c_mtx);
|
end:
|
||||||
return 0;
|
mutex_unlock(&i2c_mtx);
|
||||||
|
SCU_CLKCFG |= (1<<20);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue