forked from Imagelibrary/rtems
add missing i2c.c file
This commit is contained in:
386
c/src/lib/libbsp/arm/lpc24xx/i2c/i2c.c
Normal file
386
c/src/lib/libbsp/arm/lpc24xx/i2c/i2c.c
Normal 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
|
||||
Reference in New Issue
Block a user