2006-09-29 10:54:01 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* __________ __ ___.
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
* $Id$
|
|
|
|
*
|
2007-06-26 02:11:30 +00:00
|
|
|
* Copyright (C) 2007 by Michael Sevakis
|
2006-09-29 10:54:01 +00:00
|
|
|
*
|
|
|
|
* All files in this archive are subject to the GNU General Public License.
|
|
|
|
* See the file COPYING in the source tree root for full license agreement.
|
|
|
|
*
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
#include "system.h"
|
2007-06-26 02:11:30 +00:00
|
|
|
#include "i2c-meg-fx.h"
|
|
|
|
|
|
|
|
/* Only implements sending bytes for now. Adding receiving bytes should be
|
|
|
|
straightforward if needed. No yielding is present since the calls only
|
|
|
|
involve setting audio codec registers - a very rare event. */
|
|
|
|
|
|
|
|
/* 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)
|
2006-09-29 10:54:01 +00:00
|
|
|
{
|
2007-06-26 02:11:30 +00:00
|
|
|
/* Wait for ACK: 0 = ack received, 1 = ack not received */
|
|
|
|
WAIT_COND(IICCON & I2C_TXRX_INTPND, COND_VOID);
|
|
|
|
return IICSTAT & I2C_ACK_L;
|
2006-09-29 10:54:01 +00:00
|
|
|
}
|
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
static int i2c_start(void)
|
2006-09-29 10:54:01 +00:00
|
|
|
{
|
2007-06-26 02:11:30 +00:00
|
|
|
/* Generate START */
|
|
|
|
IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_START | I2C_RXTX_ENB;
|
|
|
|
return i2c_getack();
|
2006-09-29 10:54:01 +00:00
|
|
|
}
|
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
static void i2c_stop(void)
|
2006-09-29 10:54:01 +00:00
|
|
|
{
|
2007-06-26 02:11:30 +00:00
|
|
|
/* Generate STOP */
|
|
|
|
IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
|
|
|
|
/* Clear pending interrupt to continue */
|
|
|
|
IICCON &= ~I2C_TXRX_INTPND;
|
2006-09-29 10:54:01 +00:00
|
|
|
}
|
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
static int i2c_outb(unsigned char byte)
|
2006-09-29 10:54:01 +00:00
|
|
|
{
|
2007-06-26 02:11:30 +00:00
|
|
|
/* Write byte to shift register */
|
|
|
|
IICDS = byte;
|
|
|
|
/* Clear pending interrupt to continue */
|
|
|
|
IICCON &= ~I2C_TXRX_INTPND;
|
|
|
|
return i2c_getack();
|
2006-09-29 10:54:01 +00:00
|
|
|
}
|
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
void i2c_write(int addr, const unsigned char *buf, int count)
|
2006-09-29 10:54:01 +00:00
|
|
|
{
|
2007-06-26 02:11:30 +00:00
|
|
|
/* Turn on I2C clock */
|
|
|
|
CLKCON |= (1 << 16);
|
2006-09-29 10:54:01 +00:00
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
/* Set mode to master transmitter and enable lines */
|
|
|
|
IICSTAT = I2C_MODE_MASTER | I2C_MODE_TX | I2C_RXTX_ENB;
|
2006-09-29 10:54:01 +00:00
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
/* Wait for bus to be available */
|
|
|
|
if (WAIT_COND(!(IICSTAT & I2C_BUSY), COND_RET))
|
|
|
|
{
|
|
|
|
/* Send slave address and then data */
|
|
|
|
IICCON &= ~I2C_TXRX_INTPND;
|
|
|
|
IICCON |= I2C_TXRX_INTENB;
|
2006-09-29 10:54:01 +00:00
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
IICDS = addr & 0xfe;
|
2006-09-29 10:54:01 +00:00
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
if (i2c_start() == 0)
|
|
|
|
while (count-- > 0 && i2c_outb(*buf++) == 0);
|
2006-09-29 10:54:01 +00:00
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
i2c_stop();
|
2007-01-04 03:31:03 +00:00
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
IICCON &= ~I2C_TXRX_INTENB;
|
|
|
|
}
|
2007-01-20 22:16:01 +00:00
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
/* Go back to slave receive mode and disable lines */
|
|
|
|
IICSTAT = 0;
|
2007-01-04 03:31:03 +00:00
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
/* Turn off I2C clock */
|
|
|
|
CLKCON &= ~(1 << 16);
|
2006-09-29 10:54:01 +00:00
|
|
|
}
|
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
void i2c_init(void)
|
|
|
|
{
|
|
|
|
/* We poll I2C interrupts */
|
|
|
|
INTMSK |= (1 << 27);
|
2007-01-20 22:16:01 +00:00
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
/* Turn on I2C clock */
|
|
|
|
CLKCON |= (1 << 16);
|
2007-01-20 22:16:01 +00:00
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
/* Set GPE15 (IICSDA) and GPE14 (IICSCL) to IIC */
|
|
|
|
GPECON = (GPECON & ~((3 << 30) | (3 << 28))) |
|
|
|
|
((2 << 30) | (2 << 28));
|
2006-09-29 10:54:01 +00:00
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
/* Bus ACK, IICCLK: fPCLK / 16, Rx/Tx Int: Disable, Tx clock: IICCLK/8 */
|
|
|
|
/* OF PCLK: 49.1568MHz / 16 / 8 = 384.0375 kHz */
|
|
|
|
IICCON = (7 << 0);
|
2006-09-29 10:54:01 +00:00
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
/* SDA line delayed 0 PCLKs */
|
|
|
|
IICLC = (0 << 0);
|
2006-09-29 10:54:01 +00:00
|
|
|
|
2007-06-26 02:11:30 +00:00
|
|
|
/* Turn off I2C clock */
|
|
|
|
CLKCON &= ~(1 << 16);
|
2006-09-29 10:54:01 +00:00
|
|
|
}
|