mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-09 21:25:19 -05:00
Have meg-fx i2c driver use the wakeup functionality by making it interrupt-based (and serves as a simple usage example).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16886 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
bc192c953e
commit
5f1590bf4a
1 changed files with 74 additions and 57 deletions
|
|
@ -19,79 +19,55 @@
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "i2c-meg-fx.h"
|
#include "i2c-meg-fx.h"
|
||||||
|
|
||||||
/* Only implements sending bytes for now. Adding receiving bytes should be
|
static struct wakeup i2c_wake; /* Transfer completion signal */
|
||||||
straightforward if needed. No yielding is present since the calls only
|
static struct mutex i2c_mtx; /* Mutual exclusion */
|
||||||
involve setting audio codec registers - a very rare event. */
|
static unsigned char *buf_ptr; /* Next byte to transfer */
|
||||||
|
static int buf_count; /* Number of bytes remaining to transfer */
|
||||||
/* Wait for a condition on the bus, optionally returning it */
|
|
||||||
#define COND_RET _c;
|
|
||||||
#define COND_VOID
|
|
||||||
#define WAIT_COND(cond, ret) \
|
|
||||||
({ \
|
|
||||||
int _t = current_tick + 2; \
|
|
||||||
bool _c; \
|
|
||||||
while (1) { \
|
|
||||||
_c = !!(cond); \
|
|
||||||
if (_c || TIME_AFTER(current_tick, _t)) \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
ret \
|
|
||||||
})
|
|
||||||
|
|
||||||
static int i2c_getack(void)
|
|
||||||
{
|
|
||||||
/* Wait for ACK: 0 = ack received, 1 = ack not received */
|
|
||||||
WAIT_COND(IICCON & I2C_TXRX_INTPND, COND_VOID);
|
|
||||||
return IICSTAT & I2C_ACK_L;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int i2c_start(void)
|
|
||||||
{
|
|
||||||
/* Generate START */
|
|
||||||
IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_START | I2C_RXTX_ENB;
|
|
||||||
return i2c_getack();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void i2c_stop(void)
|
static void i2c_stop(void)
|
||||||
{
|
{
|
||||||
/* Generate STOP */
|
/* Generate STOP */
|
||||||
IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
|
IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
|
||||||
/* Clear pending interrupt to continue */
|
|
||||||
IICCON &= ~I2C_TXRX_INTPND;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int i2c_outb(unsigned char byte)
|
/* No more interrupts, clear pending interrupt to continue */
|
||||||
{
|
IICCON &= ~(I2C_TXRX_INTPND | I2C_TXRX_INTENB);
|
||||||
/* Write byte to shift register */
|
|
||||||
IICDS = byte;
|
|
||||||
/* Clear pending interrupt to continue */
|
|
||||||
IICCON &= ~I2C_TXRX_INTPND;
|
|
||||||
return i2c_getack();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void i2c_write(int addr, const unsigned char *buf, int count)
|
void i2c_write(int addr, const unsigned char *buf, int count)
|
||||||
{
|
{
|
||||||
|
if (count <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mutex_lock(&i2c_mtx);
|
||||||
|
|
||||||
/* Turn on I2C clock */
|
/* Turn on I2C clock */
|
||||||
CLKCON |= (1 << 16);
|
CLKCON |= (1 << 16);
|
||||||
|
|
||||||
/* Set mode to master transmitter and enable lines */
|
/* Set mode to master transmitter and enable lines */
|
||||||
IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
|
IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
|
||||||
|
|
||||||
/* Wait for bus to be available */
|
/* Set buffer start and count */
|
||||||
if (WAIT_COND(!(IICSTAT & I2C_BUSY), COND_RET))
|
buf_ptr = (unsigned char *)buf;
|
||||||
|
buf_count = count;
|
||||||
|
|
||||||
|
/* Send slave address and then data */
|
||||||
|
SRCPND = IIC_MASK;
|
||||||
|
INTPND = IIC_MASK;
|
||||||
|
|
||||||
|
IICCON |= I2C_TXRX_INTENB;
|
||||||
|
|
||||||
|
/* Load slave address into shift register */
|
||||||
|
IICDS = addr & 0xfe;
|
||||||
|
|
||||||
|
/* Generate START */
|
||||||
|
IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_START | I2C_RXTX_ENB;
|
||||||
|
|
||||||
|
if (wakeup_wait(&i2c_wake, HZ) != WAIT_SUCCEEDED)
|
||||||
{
|
{
|
||||||
/* Send slave address and then data */
|
/* Something went wrong - stop transmission */
|
||||||
IICCON &= ~I2C_TXRX_INTPND;
|
int oldlevel = disable_irq_save();
|
||||||
IICCON |= I2C_TXRX_INTENB;
|
|
||||||
|
|
||||||
IICDS = addr & 0xfe;
|
|
||||||
|
|
||||||
if (i2c_start() == 0)
|
|
||||||
while (count-- > 0 && i2c_outb(*buf++) == 0);
|
|
||||||
|
|
||||||
i2c_stop();
|
i2c_stop();
|
||||||
|
restore_irq(oldlevel);
|
||||||
IICCON &= ~I2C_TXRX_INTENB;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Go back to slave receive mode and disable lines */
|
/* Go back to slave receive mode and disable lines */
|
||||||
|
|
@ -99,12 +75,23 @@ void i2c_write(int addr, const unsigned char *buf, int count)
|
||||||
|
|
||||||
/* Turn off I2C clock */
|
/* Turn off I2C clock */
|
||||||
CLKCON &= ~(1 << 16);
|
CLKCON &= ~(1 << 16);
|
||||||
|
|
||||||
|
mutex_unlock(&i2c_mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void i2c_init(void)
|
void i2c_init(void)
|
||||||
{
|
{
|
||||||
/* We poll I2C interrupts */
|
/* Init kernel objects */
|
||||||
INTMSK |= (1 << 27);
|
wakeup_init(&i2c_wake);
|
||||||
|
mutex_init(&i2c_mtx);
|
||||||
|
|
||||||
|
/* Clear pending source */
|
||||||
|
SRCPND = IIC_MASK;
|
||||||
|
INTPND = IIC_MASK;
|
||||||
|
|
||||||
|
/* Enable i2c interrupt in controller */
|
||||||
|
INTMOD &= ~IIC_MASK;
|
||||||
|
INTMSK &= ~IIC_MASK;
|
||||||
|
|
||||||
/* Turn on I2C clock */
|
/* Turn on I2C clock */
|
||||||
CLKCON |= (1 << 16);
|
CLKCON |= (1 << 16);
|
||||||
|
|
@ -123,3 +110,33 @@ void i2c_init(void)
|
||||||
/* Turn off I2C clock */
|
/* Turn off I2C clock */
|
||||||
CLKCON &= ~(1 << 16);
|
CLKCON &= ~(1 << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IIC(void)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
/* If ack was received from last byte and bytes are remaining */
|
||||||
|
if (--buf_count >= 0 && (IICSTAT & I2C_ACK_L) == 0)
|
||||||
|
{
|
||||||
|
/* Write next byte to shift register */
|
||||||
|
IICDS = *buf_ptr++;
|
||||||
|
|
||||||
|
/* Clear pending interrupt to continue */
|
||||||
|
IICCON &= ~I2C_TXRX_INTPND;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finished */
|
||||||
|
|
||||||
|
/* Generate STOP */
|
||||||
|
i2c_stop();
|
||||||
|
|
||||||
|
/* Signal thread */
|
||||||
|
wakeup_signal(&i2c_wake);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ack */
|
||||||
|
SRCPND = IIC_MASK;
|
||||||
|
INTPND = IIC_MASK;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue