add missing i2c.c file

This commit is contained in:
Thomas Doerfler
2009-07-20 07:24:06 +00:00
parent 1497405428
commit 72ea4cc86f

View File

@@ -0,0 +1,386 @@
/**
* @file
*
* @ingroup lpc24xx
*
* LibI2C bus driver for the I2C modules.
*/
/*
* Copyright (c) 2009
* embedded brains GmbH
* Obere Lagerstr. 30
* D-82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <rtems.h>
#include <bsp.h>
#include <bsp/i2c.h>
#include <bsp/io.h>
#include <bsp/irq.h>
#include <bsp/irq-generic.h>
#include <bsp/lpc24xx.h>
#include <bsp/system-clocks.h>
#define RTEMS_STATUS_CHECKS_USE_PRINTK
#include <rtems/status-checks.h>
typedef struct {
rtems_libi2c_bus_t bus;
volatile lpc24xx_i2c *regs;
unsigned index;
unsigned config;
rtems_vector_number vector;
rtems_id state_update;
uint8_t * volatile data;
uint8_t * volatile end;
} lpc24xx_i2c_bus_entry;
static void lpc24xx_i2c_handler( rtems_vector_number vector, void *arg)
{
lpc24xx_i2c_bus_entry *e = arg;
volatile lpc24xx_i2c *regs = e->regs;
unsigned state = regs->stat;
uint8_t *data = e->data;
uint8_t *end = e->end;
bool notify = true;
switch (state) {
case 0x28U:
/* Data has been transmitted successfully */
if (data != end) {
regs->dat = *data;
++data;
regs->conset = LPC24XX_I2C_AA;
regs->conclr = LPC24XX_I2C_SI;
notify = false;
e->data = data;
}
break;
case 0x50U:
/* Data has been received */
if (data != end) {
*data = (uint8_t) regs->dat;
++data;
if (data != end) {
if (data + 1 != end) {
regs->conset = LPC24XX_I2C_AA;
} else {
regs->conclr = LPC24XX_I2C_AA;
}
regs->conclr = LPC24XX_I2C_SI;
notify = false;
e->data = data;
} else {
/* This is an error and should never happen */
}
}
break;
case 0x58U:
/* Last data has been received */
if (data != end) {
*data = (uint8_t) regs->dat;
}
break;
default:
/* Do nothing */
break;
}
/* Notify task if necessary */
if (notify) {
bsp_interrupt_vector_disable( e->vector);
rtems_semaphore_release( e->state_update);
}
}
static rtems_status_code lpc24xx_i2c_wait( lpc24xx_i2c_bus_entry *e)
{
bsp_interrupt_vector_enable( e->vector);
return rtems_semaphore_obtain( e->state_update, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
}
static rtems_status_code lpc24xx_i2c_init( rtems_libi2c_bus_t *bus)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus;
volatile lpc24xx_i2c *regs = e->regs;
unsigned cycles = LPC24XX_CCLK / (8U * 100000U * 2U);
/* Create semaphore */
sc = rtems_semaphore_create (
rtems_build_name ( 'I', '2', 'C', '0' + e->index),
0,
RTEMS_SIMPLE_BINARY_SEMAPHORE,
0,
&e->state_update
);
RTEMS_CHECK_SC( sc, "create status update semaphore");
/* Enable module power */
sc = lpc24xx_module_enable( LPC24XX_MODULE_I2C, e->index, LPC24XX_MODULE_CCLK_8);
RTEMS_CHECK_SC( sc, "enable module");
/* IO configuration */
sc = lpc24xx_io_config( LPC24XX_MODULE_I2C, e->index, e->config);
RTEMS_CHECK_SC( sc, "IO configuration");
/* Clock high and low duty cycles */
regs->sclh = cycles;
regs->scll = cycles;
/* Disable module */
regs->conclr = LPC24XX_I2C_EN;
/* Install interrupt handler and disable this vector */
sc = rtems_interrupt_handler_install(
e->vector,
"I2C",
RTEMS_INTERRUPT_UNIQUE,
lpc24xx_i2c_handler,
e
);
RTEMS_CHECK_SC( sc, "install interrupt handler");
bsp_interrupt_vector_disable( e->vector);
/* Enable module in master mode */
regs->conset = LPC24XX_I2C_EN;
/* Set self address */
regs->adr = 0;
return RTEMS_SUCCESSFUL;
}
static rtems_status_code lpc24xx_i2c_send_start( rtems_libi2c_bus_t *bus)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus;
volatile lpc24xx_i2c *regs = e->regs;
/* Start */
regs->conclr = LPC24XX_I2C_STA | LPC24XX_I2C_AA | LPC24XX_I2C_SI;
regs->conset = LPC24XX_I2C_STA;
/* Wait */
sc = lpc24xx_i2c_wait( e);
RTEMS_CHECK_SC( sc, "wait for state update");
return RTEMS_SUCCESSFUL;
}
static rtems_status_code lpc24xx_i2c_send_stop( rtems_libi2c_bus_t *bus)
{
lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus;
volatile lpc24xx_i2c *regs = e->regs;
/* Stop */
regs->conset = LPC24XX_I2C_STO | LPC24XX_I2C_AA;
regs->conclr = LPC24XX_I2C_STA | LPC24XX_I2C_SI;
return RTEMS_SUCCESSFUL;
}
static rtems_status_code lpc24xx_i2c_send_addr(
rtems_libi2c_bus_t *bus,
uint32_t addr,
int rw
)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus;
volatile lpc24xx_i2c *regs = e->regs;
unsigned state = regs->stat;
/* Check state */
if (state != 0x8U && state != 0x10U) {
return -RTEMS_IO_ERROR;
}
/* Send address */
regs->dat = (uint8_t) ((addr << 1U) | ((rw != 0) ? 1U : 0U));
regs->conset = LPC24XX_I2C_AA;
regs->conclr = LPC24XX_I2C_STA | LPC24XX_I2C_SI;
/* Wait */
sc = lpc24xx_i2c_wait( e);
RTEMS_CHECK_SC_RV( sc, "wait for state update");
/* Check state */
state = regs->stat;
if (state != 0x18U && state != 0x40U) {
return -RTEMS_IO_ERROR;
}
return RTEMS_SUCCESSFUL;
}
static int lpc24xx_i2c_read( rtems_libi2c_bus_t *bus, unsigned char *in, int n)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus;
volatile lpc24xx_i2c *regs = e->regs;
unsigned state = regs->stat;
uint8_t *data = in;
uint8_t *end = in + n;
if (n <= 0) {
return n;
} else if (state != 0x40U) {
return -RTEMS_IO_ERROR;
}
/* Setup receive buffer */
e->data = data;
e->end = end;
/* Ready to receive data */
if (data + 1 != end) {
regs->conset = LPC24XX_I2C_AA;
} else {
regs->conclr = LPC24XX_I2C_AA;
}
regs->conclr = LPC24XX_I2C_SI;
/* Wait */
sc = lpc24xx_i2c_wait( e);
RTEMS_CHECK_SC_RV( sc, "wait for state update");
/* Check state */
state = regs->stat;
if (state != 0x58U) {
return -RTEMS_IO_ERROR;
}
return n;
}
static int lpc24xx_i2c_write(
rtems_libi2c_bus_t *bus,
unsigned char *out,
int n
)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus;
volatile lpc24xx_i2c *regs = e->regs;
unsigned state = 0;
if (n <= 0) {
return n;
}
/* Setup transmit buffer */
e->data = out + 1;
e->end = out + n;
/* Transmit first byte */
regs->dat = *out;
regs->conset = LPC24XX_I2C_AA;
regs->conclr = LPC24XX_I2C_SI;
/* Wait */
sc = lpc24xx_i2c_wait( e);
RTEMS_CHECK_SC_RV( sc, "wait for state update");
/* Check state */
state = regs->stat;
if (state != 0x28U) {
return -RTEMS_IO_ERROR;
}
return n;
}
static int lpc24xx_i2c_set_transfer_mode(
rtems_libi2c_bus_t *bus,
const rtems_libi2c_tfr_mode_t *mode
)
{
return -RTEMS_NOT_IMPLEMENTED;
}
static int lpc24xx_i2c_ioctl( rtems_libi2c_bus_t *bus, int cmd, void *arg)
{
int rv = -1;
const rtems_libi2c_tfr_mode_t *tm = (const rtems_libi2c_tfr_mode_t *) arg;
switch (cmd) {
case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
rv = lpc24xx_i2c_set_transfer_mode( bus, tm);
break;
default:
rv = -RTEMS_NOT_DEFINED;
break;
}
return rv;
}
static const rtems_libi2c_bus_ops_t lpc24xx_i2c_ops = {
.init = lpc24xx_i2c_init,
.send_start = lpc24xx_i2c_send_start,
.send_stop = lpc24xx_i2c_send_stop,
.send_addr = lpc24xx_i2c_send_addr,
.read_bytes = lpc24xx_i2c_read,
.write_bytes = lpc24xx_i2c_write,
.ioctl = lpc24xx_i2c_ioctl
};
#ifdef LPC24XX_CONFIG_I2C_0
static lpc24xx_i2c_bus_entry lpc24xx_i2c_entry_0 = {
.bus = {
.ops = &lpc24xx_i2c_ops,
.size = sizeof( lpc24xx_i2c_bus_entry)
},
.regs = (volatile lpc24xx_i2c *) I2C0_BASE_ADDR,
.index = 0,
.config = LPC24XX_CONFIG_I2C_0,
.vector = LPC24XX_IRQ_I2C_0
};
rtems_libi2c_bus_t * const lpc24xx_i2c_0 =
(rtems_libi2c_bus_t *) &lpc24xx_i2c_entry_0;
#endif
#ifdef LPC24XX_CONFIG_I2C_1
static lpc24xx_i2c_bus_entry lpc24xx_i2c_entry_1 = {
.bus = {
.ops = &lpc24xx_i2c_ops,
.size = sizeof( lpc24xx_i2c_bus_entry)
},
.regs = (volatile lpc24xx_i2c *) I2C1_BASE_ADDR,
.index = 1,
.config = LPC24XX_CONFIG_I2C_1,
.vector = LPC24XX_IRQ_I2C_1
};
rtems_libi2c_bus_t * const lpc24xx_i2c_1 =
(rtems_libi2c_bus_t *) &lpc24xx_i2c_entry_1;
#endif
#ifdef LPC24XX_CONFIG_I2C_2
static lpc24xx_i2c_bus_entry lpc24xx_i2c_entry_2 = {
.bus = {
.ops = &lpc24xx_i2c_ops,
.size = sizeof( lpc24xx_i2c_bus_entry)
},
.regs = (volatile lpc24xx_i2c *) I2C2_BASE_ADDR,
.index = 2,
.config = LPC24XX_CONFIG_I2C_2,
.vector = LPC24XX_IRQ_I2C_2
};
rtems_libi2c_bus_t * const lpc24xx_i2c_2 =
(rtems_libi2c_bus_t *) &lpc24xx_i2c_entry_2;
#endif