Add the i2c driver for Beaglebone Black

Update ticket #2891 and my GSOC project
add c/src/lib/libbsp/arm/beagle/i2c/bbb-i2c.c
modify c/src/lib/libbsp/arm/beagle/include/i2c.h
modify c/src/lib/libbsp/arm/beagle/include/bbb-gpio.h
modify c/src/lib/libcpu/arm/shared/include/am335x.h
modify c/src/lib/libbsp/arm/beagle/Makefile.am
Now can read the EEPROM by i2c, the test application link is: https://github.com/hahchenchen/GSOC-test-application
This commit is contained in:
Sichen Zhao
2017-06-14 22:53:44 +08:00
committed by Joel Sherrill
parent 7741545bfc
commit 8f550d2fa1
5 changed files with 752 additions and 128 deletions

View File

@@ -114,6 +114,7 @@ libbsp_a_SOURCES += ../../shared/console.c \
../../shared/console_control.c
# I2C
libbsp_a_SOURCES += i2c/bbb-i2c.c
# GPIO
libbsp_a_SOURCES += gpio/bbb-gpio.c

View File

@@ -0,0 +1,461 @@
/**
* @file
*
* @ingroup arm_beagle
*
* @brief BeagleBoard I2C bus initialization and API Support.
*/
/*
* Copyright (c) 2017 Sichen Zhao <zsc19940506@gmail.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
/*
* Modified on Punit Vara<punitvara@gmail.com> works, currently
* the i2c file is working on the Beaglebone Black board(AM335x)
*/
#include <stdio.h>
#include <bsp/i2c.h>
#include <libcpu/am335x.h>
#include <rtems/irq-extension.h>
#include <rtems/counter.h>
#include <bsp/bbb-gpio.h>
#include <rtems/score/assert.h>
static void am335x_i2c0_pinmux( bbb_i2c_bus *bus )
{
REG( bus->regs + AM335X_CONF_I2C0_SDA ) =
( BBB_RXACTIVE | BBB_SLEWCTRL | BBB_PU_EN );
REG( bus->regs + AM335X_CONF_I2C0_SCL ) =
( BBB_RXACTIVE | BBB_SLEWCTRL | BBB_PU_EN );
}
static void I2C0ModuleClkConfig( void )
{
/* Writing to MODULEMODE field of AM335X_CM_WKUP_I2C0_CLKCTRL register. */
REG( AM335X_SOC_CM_WKUP_REGS + AM335X_CM_WKUP_I2C0_CLKCTRL ) |=
AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE_ENABLE;
/* Waiting for MODULEMODE field to reflect the written value. */
while ( AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE_ENABLE !=
( REG( AM335X_SOC_CM_WKUP_REGS + AM335X_CM_WKUP_I2C0_CLKCTRL ) &
AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE ) ) ;
/*
** Waiting for IDLEST field in AM335X_CM_WKUP_CONTROL_CLKCTRL
** register to attain
** desired value.
*/
while ( ( AM335X_CM_WKUP_CONTROL_CLKCTRL_IDLEST_FUNC <<
AM335X_CM_WKUP_CONTROL_CLKCTRL_IDLEST_SHIFT ) !=
( REG( AM335X_SOC_CM_WKUP_REGS + AM335X_CM_WKUP_CONTROL_CLKCTRL ) &
AM335X_CM_WKUP_CONTROL_CLKCTRL_IDLEST ) ) ;
/*
** Waiting for CLKACTIVITY_I2C0_GFCLK field in AM335X_CM_WKUP_CLKSTCTRL
** register to attain desired value.
*/
while ( AM335X_CM_WKUP_CLKSTCTRL_CLKACTIVITY_I2C0_GFCLK !=
( REG( AM335X_SOC_CM_WKUP_REGS + AM335X_CM_WKUP_CLKSTCTRL ) &
AM335X_CM_WKUP_CLKSTCTRL_CLKACTIVITY_I2C0_GFCLK ) ) ;
/*
** Waiting for IDLEST field in AM335X_CM_WKUP_I2C0_CLKCTRL register to attain
** desired value.
*/
while ( ( AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST_FUNC <<
AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST_SHIFT ) !=
( REG( AM335X_SOC_CM_WKUP_REGS + AM335X_CM_WKUP_I2C0_CLKCTRL ) &
AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST ) ) ;
}
static void am335x_i2c_reset( bbb_i2c_bus *bus )
{
volatile bbb_i2c_regs *regs = bus->regs;
int timeout = I2C_TIMEOUT;
if ( REG( &regs->BBB_I2C_CON ) & BBB_I2C_CON_EN ) {
REG( &regs->BBB_I2C_CON ) = BBB_I2C_CON_CLR;
udelay( 50000 );
}
REG( &regs->BBB_I2C_SYSC ) = BBB_I2C_SYSC_SRST; /* for ES2 after soft reset */
udelay( 1000 );
REG( &regs->BBB_I2C_CON ) = BBB_I2C_CON_EN;
while ( !( REG( &regs->BBB_I2C_SYSS ) & BBB_I2C_SYSS_RDONE ) && timeout-- ) {
if ( timeout <= 0 ) {
puts( "ERROR: Timeout in soft-reset\n" );
return;
}
udelay( 1000 );
}
}
/*
Possible values for msg->flag
* - @ref I2C_M_TEN,
* - @ref I2C_M_RD,
* - @ref I2C_M_STOP,
* - @ref I2C_M_NOSTART,
* - @ref I2C_M_REV_DIR_ADDR,
* - @ref I2C_M_IGNORE_NAK,
* - @ref I2C_M_NO_RD_ACK, and
* - @ref I2C_M_RECV_LEN.
*/
static void am335x_i2c_set_address_size(
const i2c_msg *msgs,
volatile bbb_i2c_regs *regs
)
{
/*can be configured multiple modes here.
**Need to think about own address modes*/
if ( ( msgs->flags & I2C_M_TEN ) == 0 ) {
/* 7-bit mode slave address mode*/
REG( &regs->BBB_I2C_CON ) = AM335X_I2C_CFG_7BIT_SLAVE_ADDR;
} else {
/* 10-bit slave address mode*/
REG( &regs->BBB_I2C_CON ) = AM335X_I2C_CFG_10BIT_SLAVE_ADDR;
}
}
static void am335x_i2c_next_byte( bbb_i2c_bus *bus )
{
i2c_msg *msg;
++bus->msgs;
--bus->msg_todo;
msg = &bus->msgs[ 0 ];
bus->current_msg_todo = msg->len;
bus->current_msg_byte = msg->buf;
}
static void am335x_i2c_masterint_enable(
volatile bbb_i2c_regs *regs,
unsigned int flag
)
{
REG( &regs->BBB_I2C_IRQENABLE_SET ) |= flag;
}
static void am335x_i2c_masterint_disable(
volatile bbb_i2c_regs *regs,
unsigned int flag
)
{
REG( &regs->BBB_I2C_IRQENABLE_CLR ) = flag;
}
static void am335x_int_clear(
volatile bbb_i2c_regs *regs,
unsigned int flag
)
{
REG( &regs->BBB_I2C_IRQSTATUS ) = flag;
}
static void am335x_clean_interrupts( volatile bbb_i2c_regs *regs )
{
am335x_i2c_masterint_enable( regs, BBB_I2C_ALL_FLAGS );
am335x_int_clear( regs, BBB_I2C_ALL_FLAGS );
am335x_i2c_masterint_disable( regs, BBB_I2C_ALL_FLAGS );
}
static void am335x_i2c_setup_read_transfer(
bbb_i2c_bus *bus,
volatile bbb_i2c_regs *regs,
const i2c_msg *msgs,
bool send_stop
)
{
REG( &regs->BBB_I2C_CNT ) = bus->current_msg_todo;
REG( &regs->BBB_I2C_CON ) = AM335X_I2C_CFG_MST_RX | AM335X_I2C_CON_I2C_EN;
if ( send_stop ) {
REG( &regs->BBB_I2C_CON ) |= AM335X_I2C_CON_START | AM335X_I2C_CON_STOP;
} else {
REG( &regs->BBB_I2C_CON ) |= AM335X_I2C_CON_START;
}
am335x_i2c_masterint_enable( regs, AM335X_I2C_INT_RECV_READY |
AM335X_I2C_IRQSTATUS_ARDY );
}
static void am335x_i2c_continue_read_transfer(
bbb_i2c_bus *bus,
volatile bbb_i2c_regs *regs
)
{
bus->current_msg_byte[ bus->already_transferred ] =
REG( &regs->BBB_I2C_DATA );
bus->already_transferred++;
REG( &regs->BBB_I2C_IRQSTATUS ) = AM335X_I2C_INT_RECV_READY;
if ( bus->already_transferred == bus->current_msg_todo - 1 ) {
REG( &regs->BBB_I2C_CON ) |= AM335X_I2C_CON_STOP;
}
}
static void am335x_i2c_continue_write(
bbb_i2c_bus *bus,
volatile bbb_i2c_regs *regs
)
{
if ( bus->already_transferred == bus->msg_todo ) {
REG( &regs->BBB_I2C_DATA ) =
bus->current_msg_byte[ bus->already_transferred ];
REG( &regs->BBB_I2C_IRQSTATUS ) = AM335X_I2C_IRQSTATUS_XRDY;
am335x_i2c_masterint_disable( regs, AM335X_I2C_IRQSTATUS_XRDY );
REG( &regs->BBB_I2C_CON ) |= AM335X_I2C_CON_STOP;
} else {
writeb( bus->current_msg_byte[ bus->already_transferred ],
&regs->BBB_I2C_DATA );
REG( &regs->BBB_I2C_IRQSTATUS ) = AM335X_I2C_IRQSTATUS_XRDY;
bus->already_transferred++;
}
}
static void am335x_i2c_setup_write_transfer(
bbb_i2c_bus *bus,
volatile bbb_i2c_regs *regs,
const i2c_msg *msgs
)
{
volatile unsigned int no_bytes;
REG( &regs->BBB_I2C_CNT ) = bus->current_msg_todo;
no_bytes = REG( &regs->BBB_I2C_CNT );
REG( &regs->BBB_I2C_SA ) = msgs->addr;
REG( &regs->BBB_I2C_CON ) = AM335X_I2C_CFG_MST_TX | AM335X_I2C_CON_I2C_EN;
am335x_clean_interrupts( regs );
am335x_i2c_masterint_enable( regs, AM335X_I2C_IRQSTATUS_XRDY );
REG( &regs->BBB_I2C_CON ) |= AM335X_I2C_CON_START | AM335X_I2C_CON_STOP;
}
static void am335x_i2c_setup_transfer(
bbb_i2c_bus *bus,
volatile bbb_i2c_regs *regs
)
{
const i2c_msg *msgs = bus->msgs;
uint32_t msg_todo = bus->msg_todo;
bool send_stop = false;
uint32_t i;
bus->current_todo = msgs[ 0 ].len;
for ( i = 1; i < msg_todo && ( msgs[ i ].flags & I2C_M_NOSTART ) != 0;
++i ) {
bus->current_todo += msgs[ i ].len;
}
regs = bus->regs;
REG( &bus->regs->BBB_I2C_BUF ) |= AM335X_I2C_BUF_TXFIFO_CLR;
REG( &bus->regs->BBB_I2C_BUF ) |= AM335X_I2C_BUF_RXFIFO_CLR;
am335x_i2c_set_address_size( msgs, regs );
bus->read = ( msgs->flags & I2C_M_RD ) != 0;
bus->already_transferred = ( bus->read == true ) ? 0 : 1;
if ( bus->read ) {
if ( bus->current_msg_todo == 1 ) {
send_stop = true;
}
am335x_i2c_setup_read_transfer( bus, regs, msgs, send_stop );
} else {
am335x_i2c_setup_write_transfer( bus, regs, msgs );
}
}
static void am335x_i2c_interrupt( void *arg )
{
bbb_i2c_bus *bus = arg;
volatile bbb_i2c_regs *regs = bus->regs;
/* get status of enabled interrupts */
uint32_t irqstatus = REG( &regs->BBB_I2C_IRQSTATUS );
bool done = false;
/* Clear all enabled interrupt except receive ready
and transmit ready interrupt in status register */
REG( &regs->BBB_I2C_IRQSTATUS ) =
( irqstatus & ~( AM335X_I2C_IRQSTATUS_RRDY |
AM335X_I2C_IRQSTATUS_XRDY ) );
if ( irqstatus & AM335X_I2C_INT_RECV_READY ) {
am335x_i2c_continue_read_transfer( bus, regs );
}
if ( irqstatus & AM335X_I2C_IRQSTATUS_XRDY ) {
am335x_i2c_continue_write( bus, regs );
}
if ( irqstatus & AM335X_I2C_IRQSTATUS_NACK ) {
done = true;
am335x_i2c_masterint_disable( regs, AM335X_I2C_IRQSTATUS_NACK );
}
if ( irqstatus & AM335X_I2C_IRQSTATUS_ARDY ) {
done = true;
REG( &regs->BBB_I2C_IRQSTATUS ) = BBB_I2C_STAT_ARDY;
}
if ( irqstatus & AM335X_I2C_IRQSTATUS_BF ) {
REG( &regs->BBB_I2C_IRQSTATUS ) = AM335X_I2C_IRQSTATUS_BF;
}
if ( done ) {
uint32_t err = irqstatus & BBB_I2C_IRQ_ERROR;
am335x_i2c_next_byte( bus );
if ( bus->msg_todo == 0 ) {
rtems_status_code sc;
am335x_i2c_masterint_disable( regs, ( AM335X_I2C_IRQSTATUS_RRDY |
AM335X_I2C_IRQSTATUS_XRDY |
AM335X_I2C_IRQSTATUS_BF ) );
REG( &regs->BBB_I2C_IRQSTATUS ) = err;
sc = rtems_event_transient_send( bus->task_id );
_Assert( sc == RTEMS_SUCCESSFUL );
(void) sc;
} else {
am335x_i2c_setup_transfer( bus, regs );
}
}
}
static int am335x_i2c_transfer(
i2c_bus *base,
i2c_msg *msgs,
uint32_t msg_count
)
{
rtems_status_code sc;
bbb_i2c_bus *bus = (bbb_i2c_bus *) base;
volatile bbb_i2c_regs *regs;
uint32_t i;
rtems_task_wake_after( 1 );
if ( msg_count < 1 ) {
return 1;
}
for ( i = 0; i < msg_count; ++i ) {
if ( ( msgs[ i ].flags & I2C_M_RECV_LEN ) != 0 ) {
return -EINVAL;
}
}
bus->msgs = &msgs[ 0 ];
bus->msg_todo = msg_count;
bus->current_msg_todo = msgs[ 0 ].len;
bus->current_msg_byte = msgs[ 0 ].buf;
bus->task_id = rtems_task_self();
regs = bus->regs;
am335x_i2c_setup_transfer( bus, regs );
REG( &regs->BBB_I2C_IRQENABLE_SET ) = BBB_I2C_IRQ_USED;
sc = rtems_event_transient_receive( RTEMS_WAIT, bus->base.timeout );
if ( sc != RTEMS_SUCCESSFUL ) {
am335x_i2c_reset( bus );
rtems_event_transient_clear();
return -ETIMEDOUT;
}
return 0;
}
static int am335x_i2c_set_clock(
i2c_bus *base,
unsigned long clock
)
{
bbb_i2c_bus *bus = (bbb_i2c_bus *) base;
uint32_t prescaler, divider;
prescaler = ( BBB_I2C_SYSCLK / BBB_I2C_INTERNAL_CLK ) - 1;
REG( &bus->regs->BBB_I2C_PSC ) = prescaler;
divider = BBB_I2C_INTERNAL_CLK / ( 2 * clock );
REG( &bus->regs->BBB_I2C_SCLL ) = ( divider - 7 );
REG( &bus->regs->BBB_I2C_SCLH ) = ( divider - 5 );
return 0;
}
static void am335x_i2c_destroy( i2c_bus *base )
{
bbb_i2c_bus *bus = (bbb_i2c_bus *) base;
rtems_status_code sc;
sc = rtems_interrupt_handler_remove( bus->irq, am335x_i2c_interrupt, bus );
_Assert( sc == RTEMS_SUCCESSFUL );
(void) sc;
i2c_bus_destroy_and_free( &bus->base );
}
int am335x_i2c_bus_register(
const char *bus_path,
uintptr_t register_base,
uint32_t input_clock,
rtems_vector_number irq
)
{
bbb_i2c_bus *bus;
rtems_status_code sc;
int err;
/*check bus number is >0 & <MAX*/
bus = (bbb_i2c_bus *) i2c_bus_alloc_and_init( sizeof( *bus ) );
if ( bus == NULL ) {
return -1;
}
bus->regs = (volatile bbb_i2c_regs *) register_base;
I2C0ModuleClkConfig();
am335x_i2c0_pinmux( bus );
am335x_i2c_reset( bus );
bus->input_clock = input_clock;
err = am335x_i2c_set_clock( &bus->base, I2C_BUS_CLOCK_DEFAULT );
if ( err != 0 ) {
( *bus->base.destroy )( &bus->base );
rtems_set_errno_and_return_minus_one( -err );
}
bus->irq = irq;
REG( &bus->regs->BBB_I2C_IRQSTATUS ) = BBB_I2C_ALL_IRQ_FLAGS;
sc = rtems_interrupt_handler_install(
irq,
"BBB_I2C",
RTEMS_INTERRUPT_UNIQUE,
(rtems_interrupt_handler) am335x_i2c_interrupt,
bus
);
if ( sc != RTEMS_SUCCESSFUL ) {
( *bus->base.destroy )( &bus->base );
rtems_set_errno_and_return_minus_one( EIO );
}
bus->base.transfer = am335x_i2c_transfer;
bus->base.set_clock = am335x_i2c_set_clock;
bus->base.destroy = am335x_i2c_destroy;
return i2c_bus_register( &bus->base, bus_path );
}

View File

@@ -35,9 +35,11 @@ extern "C" {
#define BBB_PU_EN (1 << 4)
#define BBB_PD_EN ~BBB_PU_EN
#define BBB_MUXMODE(X) (X & 0x7)
#define BBB_RXACTIVE (1 << 5)
#define BBB_SLEWCTRL (1 << 6)
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* LIBBSP_ARM_BEAGLE_BBB_GPIO_H */
#endif /* LIBBSP_ARM_BEAGLE_BBB_GPIO_H */

View File

@@ -24,7 +24,7 @@
#define LIBBSP_ARM_BEAGLE_I2C_H
#include <rtems.h>
#include <dev/i2c/i2c.h>
#include <bsp.h>
#ifdef __cplusplus
@@ -34,151 +34,175 @@ extern "C" {
/* I2C Configuration Register (I2C_CON): */
#define I2C_CON_EN (1 << 15) /* I2C module enable */
#define I2C_CON_BE (1 << 14) /* Big endian mode */
#define I2C_CON_STB (1 << 11) /* Start byte mode (master mode only) */
#define I2C_CON_MST (1 << 10) /* Master/slave mode */
#define I2C_CON_TRX (1 << 9) /* Transmitter/receiver mode */
#define BBB_I2C_CON_EN (1 << 15) /* I2C module enable */
#define BBB_I2C_CON_BE (1 << 14) /* Big endian mode */
#define BBB_I2C_CON_STB (1 << 11) /* Start byte mode (master mode only) */
#define BBB_I2C_CON_MST (1 << 10) /* Master/slave mode */
#define BBB_I2C_CON_TRX (1 << 9) /* Transmitter/receiver mode */
/* (master mode only) */
#define I2C_CON_XA (1 << 8) /* Expand address */
#define I2C_CON_STP (1 << 1) /* Stop condition (master mode only) */
#define I2C_CON_STT (1 << 0) /* Start condition (master mode only) */
#define BBB_I2C_CON_XA (1 << 8) /* Expand address */
#define BBB_I2C_CON_STP (1 << 1) /* Stop condition (master mode only) */
#define BBB_I2C_CON_STT (1 << 0) /* Start condition (master mode only) */
#define BBB_I2C_CON_CLR 0x0 /* Clear configuration register */
/* I2C Status Register (I2C_STAT): */
#define I2C_STAT_SBD (1 << 15) /* Single byte data */
#define I2C_STAT_BB (1 << 12) /* Bus busy */
#define I2C_STAT_ROVR (1 << 11) /* Receive overrun */
#define I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
#define I2C_STAT_AAS (1 << 9) /* Address as slave */
#define I2C_STAT_GC (1 << 5)
#define I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
#define I2C_STAT_RRDY (1 << 3) /* Receive data ready */
#define I2C_STAT_ARDY (1 << 2) /* Register access ready */
#define I2C_STAT_NACK (1 << 1) /* No acknowledgment interrupt enable */
#define I2C_STAT_AL (1 << 0) /* Arbitration lost interrupt enable */
#define BBB_I2C_STAT_SBD (1 << 15) /* Single byte data */
#define BBB_I2C_STAT_BB (1 << 12) /* Bus busy */
#define BBB_I2C_STAT_ROVR (1 << 11) /* Receive overrun */
#define BBB_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
#define BBB_I2C_STAT_AAS (1 << 9) /* Address as slave */
#define BBB_I2C_STAT_GC (1 << 5)
#define BBB_I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
#define BBB_I2C_STAT_RRDY (1 << 3) /* Receive data ready */
#define BBB_I2C_STAT_ARDY (1 << 2) /* Register access ready */
#define BBB_I2C_STAT_NACK (1 << 1) /* No acknowledgment interrupt enable */
#define BBB_I2C_STAT_AL (1 << 0) /* Arbitration lost interrupt enable */
/* I2C Interrupt Enable Register (I2C_IE): */
#define I2C_IE_GC_IE (1 << 5)
#define I2C_IE_XRDY_IE (1 << 4) /* Transmit data ready interrupt enable */
#define I2C_IE_RRDY_IE (1 << 3) /* Receive data ready interrupt enable */
#define I2C_IE_ARDY_IE (1 << 2) /* Register access ready interrupt enable */
#define I2C_IE_NACK_IE (1 << 1) /* No acknowledgment interrupt enable */
#define I2C_IE_AL_IE (1 << 0) /* Arbitration lost interrupt enable */
/*
* The equation for the low and high time is
* tlow = scll + scll_trim = (sampling clock * tlow_duty) / speed
* thigh = sclh + sclh_trim = (sampling clock * (1 - tlow_duty)) / speed
*
* If the duty cycle is 50%
*
* tlow = scll + scll_trim = sampling clock / (2 * speed)
* thigh = sclh + sclh_trim = sampling clock / (2 * speed)
*
* In TRM
* scll_trim = 7
* sclh_trim = 5
*
* The linux 2.6.30 kernel uses
* scll_trim = 6
* sclh_trim = 6
*
* These are the trim values for standard and fast speed
*/
#ifndef I2C_FASTSPEED_SCLL_TRIM
#define I2C_FASTSPEED_SCLL_TRIM 6
#endif
#ifndef I2C_FASTSPEED_SCLH_TRIM
#define I2C_FASTSPEED_SCLH_TRIM 6
#endif
#define BBB_I2C_IE_GC_IE (1 << 5)
#define BBB_I2C_IE_XRDY_IE (1 << 4) /* Transmit data ready interrupt enable */
#define BBB_I2C_IE_RRDY_IE (1 << 3) /* Receive data ready interrupt enable */
#define BBB_I2C_IE_ARDY_IE (1 << 2) /* Register access ready interrupt enable */
#define BBB_I2C_IE_NACK_IE (1 << 1) /* No acknowledgment interrupt enable */
#define BBB_I2C_IE_AL_IE (1 << 0) /* Arbitration lost interrupt enable */
/* These are the trim values for high speed */
#ifndef I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM
#define I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM I2C_FASTSPEED_SCLL_TRIM
#endif
#ifndef I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM
#define I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM I2C_FASTSPEED_SCLH_TRIM
#endif
#ifndef I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM
#define I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM I2C_FASTSPEED_SCLL_TRIM
#endif
#ifndef I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM
#define I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM I2C_FASTSPEED_SCLH_TRIM
#endif
/* I2C SYSC Register (I2C_SYSC): */
#define BBB_I2C_SYSC_SRST (1 << 1)
#define OMAP_I2C_STANDARD 100000
#define OMAP_I2C_FAST_MODE 400000
#define OMAP_I2C_HIGH_SPEED 3400000
#define BBB_I2C_TIMEOUT 1000
#define BBB_I2C_SYSS_RDONE (1 << 0) /* Internel reset monitoring */
/* Use the reference value of 96MHz if not explicitly set by the board */
#ifndef I2C_IP_CLK
#define I2C_IP_CLK SYSTEM_CLOCK_96
#endif
#define BBB_CONFIG_SYS_I2C_SPEED 100000
#define BBB_CONFIG_SYS_I2C_SLAVE 1
#define BBB_I2C_ALL_FLAGS 0x7FFF
#define BBB_I2C_ALL_IRQ_FLAGS 0xFFFF
/*
* The reference minimum clock for high speed is 19.2MHz.
* The linux 2.6.30 kernel uses this value.
* The reference minimum clock for fast mode is 9.6MHz
* The reference minimum clock for standard mode is 4MHz
* In TRM, the value of 12MHz is used.
*/
#ifndef I2C_INTERNAL_SAMPLING_CLK
#define I2C_INTERNAL_SAMPLING_CLK 19200000
#endif
#define BBB_I2C_SYSCLK 48000000
#define BBB_I2C_INTERNAL_CLK 12000000
#define BBB_I2C_SPEED_CLK 100000
#define I2C_PSC_MAX 0x0f
#define I2C_PSC_MIN 0x00
#define BBB_I2C_IRQ_ERROR \
( AM335X_I2C_IRQSTATUS_NACK \
| AM335X_I2C_IRQSTATUS_ROVR \
| AM335X_I2C_IRQSTATUS_AL \
| AM335X_I2C_IRQSTATUS_ARDY \
| AM335X_I2C_IRQSTATUS_RRDY \
| AM335X_I2C_IRQSTATUS_XRDY \
| AM335X_I2C_IRQSTATUS_XUDF )
#define BBB_I2C_IRQ_USED \
( AM335X_I2C_IRQSTATUS_ARDY \
| AM335X_I2C_IRQSTATUS_XRDY )
#define DISP_LINE_LEN 128
#define I2C_TIMEOUT 1000
#define BBB_I2C_0_BUS_PATH "/dev/i2c-0"
#define BBB_I2C_1_BUS_PATH "/dev/i2c-1"
#define BBB_I2C_2_BUS_PATH "/dev/i2c-2"
#define I2C_BUS_MAX 3
#define BBB_I2C0_IRQ 70
#define BBB_I2C1_IRQ 71
#define BBB_I2C2_IRQ 30
#define I2C_BASE1 (OMAP34XX_CORE_L4_IO_BASE + 0x070000)
#define BBB_MODE2 2
#define BBB_MODE3 3
#define I2C_DEFAULT_BASE I2C_BASE1
typedef enum {
I2C0,
I2C1,
I2C2,
I2C_COUNT
} bbb_i2c_id_t;
#define I2C_SYSS_RDONE (1 << 0) /* Internel reset monitoring */
typedef struct i2c_regs {
uint32_t BBB_I2C_REVNB_LO;
uint32_t BBB_I2C_REVNB_HI;
uint32_t dummy1[ 2 ];
uint32_t BBB_I2C_SYSC;
uint32_t dummy2[ 4 ];
uint32_t BBB_I2C_IRQSTATUS_RAW;
uint32_t BBB_I2C_IRQSTATUS;
uint32_t BBB_I2C_IRQENABLE_SET;
uint32_t BBB_I2C_IRQENABLE_CLR;
uint32_t BBB_I2C_WE;
uint32_t BBB_I2C_DMARXENABLE_SET;
uint32_t BBB_I2C_DMATXENABLE_SET;
uint32_t BBB_I2C_DMARXENABLE_CLR;
uint32_t BBB_I2C_DMATXENABLE_CLR;
uint32_t BBB_I2C_DMARXWAKE_EN;
uint32_t BBB_I2C_DMATXWAKE_EN;
uint32_t dummy3[ 16 ];
uint32_t BBB_I2C_SYSS;
uint32_t BBB_I2C_BUF;
uint32_t BBB_I2C_CNT;
uint32_t BBB_I2C_DATA;
uint32_t dummy4;
uint32_t BBB_I2C_CON;
uint32_t BBB_I2C_OA;
uint32_t BBB_I2C_SA;
uint32_t BBB_I2C_PSC;
uint32_t BBB_I2C_SCLL;
uint32_t BBB_I2C_SCLH;
uint32_t BBB_I2C_SYSTEST;
uint32_t BBB_I2C_BUFSTAT;
uint32_t BBB_I2C_OA1;
uint32_t BBB_I2C_OA2;
uint32_t BBB_I2C_OA3;
uint32_t BBB_I2C_ACTOA;
uint32_t BBB_I2C_SBLOCK;
} bbb_i2c_regs;
#define CONFIG_SYS_I2C_SPEED 100000
#define CONFIG_SYS_I2C_SLAVE 1
typedef struct bbb_i2c_bus {
i2c_bus base;
volatile bbb_i2c_regs *regs;
i2c_msg *msgs;
uint32_t msg_todo;
uint32_t current_msg_todo;
uint8_t *current_msg_byte;
uint32_t current_todo;
bool read;
bool hold;
rtems_id task_id;
rtems_vector_number irq;
uint32_t input_clock;
uint32_t already_transferred;
} bbb_i2c_bus;
struct i2c {
unsigned short rev; /* 0x00 */
unsigned short res1;
unsigned short ie; /* 0x04 */
unsigned short res2;
unsigned short stat; /* 0x08 */
unsigned short res3;
unsigned short iv; /* 0x0C */
unsigned short res4;
unsigned short syss; /* 0x10 */
unsigned short res4a;
unsigned short buf; /* 0x14 */
unsigned short res5;
unsigned short cnt; /* 0x18 */
unsigned short res6;
unsigned short data; /* 0x1C */
unsigned short res7;
unsigned short sysc; /* 0x20 */
unsigned short res8;
unsigned short con; /* 0x24 */
unsigned short res9;
unsigned short oa; /* 0x28 */
unsigned short res10;
unsigned short sa; /* 0x2C */
unsigned short res11;
unsigned short psc; /* 0x30 */
unsigned short res12;
unsigned short scll; /* 0x34 */
unsigned short res13;
unsigned short sclh; /* 0x38 */
unsigned short res14;
unsigned short systest; /* 0x3c */
unsigned short res15;
};
int am335x_i2c_bus_register(
const char *bus_path,
uintptr_t register_base,
uint32_t input_clock,
rtems_vector_number irq
);
static inline int bbb_register_i2c_0( void )
{
return am335x_i2c_bus_register(
BBB_I2C_0_BUS_PATH,
AM335X_I2C0_BASE,
I2C_BUS_CLOCK_DEFAULT,
BBB_I2C0_IRQ
);
}
static inline int bbb_register_i2c_1( void )
{
return am335x_i2c_bus_register(
BBB_I2C_1_BUS_PATH,
AM335X_I2C1_BASE,
I2C_BUS_CLOCK_DEFAULT,
BBB_I2C1_IRQ
);
}
static inline int bbb_register_i2c_2( void )
{
return am335x_i2c_bus_register(
BBB_I2C_2_BUS_PATH,
AM335X_I2C2_BASE,
I2C_BUS_CLOCK_DEFAULT,
BBB_I2C2_IRQ
);
}
#ifdef __cplusplus
}

View File

@@ -563,3 +563,139 @@
/* I2C registers */
#define AM335X_I2C0_BASE 0x44e0b000
/* I2C0 base address */
#define AM335X_I2C1_BASE 0x4802a000
/* I2C1 base address */
#define AM335X_I2C2_BASE 0x4819c000
/* I2C2 base address */
#define AM335X_I2C_REVNB_LO 0x00
/* Module Revision Register (low bytes) */
#define AM335X_I2C_REVNB_HI 0x04
/* Module Revision Register (high bytes) */
#define AM335X_I2C_SYSC 0x10
/* System Configuration Register */
#define AM335X_I2C_IRQSTATUS_RAW 0x24
/* I2C Status Raw Register */
#define AM335X_I2C_IRQSTATUS 0x28
/* I2C Status Register */
#define AM335X_I2C_IRQENABLE_SET 0x2c
/* I2C Interrupt Enable Set Register */
#define AM335X_I2C_IRQENABLE_CLR 0x30
/* I2C Interrupt Enable Clear Register */
#define AM335X_I2C_WE 0x34
/* I2C Wakeup Enable Register */
#define AM335X_I2C_DMARXENABLE_SET 0x38
/* Receive DMA Enable Set Register */
#define AM335X_I2C_DMATXENABLE_SET 0x3c
/* Transmit DMA Enable Set Register */
#define AM335X_I2C_DMARXENABLE_CLR 0x40
/* Receive DMA Enable Clear Register */
#define AM335X_I2C_DMATXENABLE_CLR 0x44
/* Transmit DMA Enable Clear Register */
#define AM335X_I2C_DMARXWAKE_EN 0x48
/* Receive DMA Wakeup Register */
#define AM335X_I2C_DMATXWAKE_EN 0x4c
/* Transmit DMA Wakeup Register */
#define AM335X_I2C_SYSS 0x90
/* System Status Register */
#define AM335X_I2C_BUF 0x94
/* Buffer Configuration Register */
#define AM335X_I2C_CNT 0x98
/* Data Counter Register */
#define AM335X_I2C_DATA 0x9c
/* Data Access Register */
#define AM335X_I2C_CON 0xa4
/* I2C Configuration Register */
#define AM335X_I2C_OA 0xa8
/* I2C Own Address Register */
#define AM335X_I2C_SA 0xac
/* I2C Slave Address Register */
#define AM335X_I2C_PSC 0xb0
/* I2C Clock Prescaler Register */
#define AM335X_I2C_SCLL 0xb4
/* I2C SCL Low Time Register */
#define AM335X_I2C_SCLH 0xb8
/* I2C SCL High Time Register */
#define AM335X_I2C_SYSTEST 0xbc
/* System Test Register */
#define AM335X_I2C_BUFSTAT 0xc0
/* I2C Buffer Status Register */
#define AM335X_I2C_OA1 0xc4
/* I2C Own Address 1 Register */
#define AM335X_I2C_OA2 0xc8
/* I2C Own Address 2 Register */
#define AM335X_I2C_OA3 0xcc
/* I2C Own Address 3 Register */
#define AM335X_I2C_ACTOA 0xd0
/* Active Own Address Register */
#define AM335X_I2C_SBLOCK 0xd4
/* I2C Clock Blocking Enable Register */
#define AM335X_CM_PER_L4LS_CLKSTCTRL (0x0)
#define AM335X_CM_PER_L4LS_CLKSTCTRL_CLKTRCTRL_SW_WKUP (0x2u)
#define AM335X_CM_PER_L4LS_CLKSTCTRL_CLKTRCTRL (0x00000003u)
#define AM335X_CM_PER_L4LS_CLKCTRL (0x60)
#define AM335X_CM_PER_L4LS_CLKCTRL_MODULEMODE_ENABLE (0x2u)
#define AM335X_CM_PER_L4LS_CLKCTRL_MODULEMODE (0x00000003u)
#define AM335X_CM_PER_I2C1_CLKCTRL (0x48)
#define AM335X_CM_PER_I2C1_CLKCTRL_MODULEMODE_ENABLE (0x2u)
#define AM335X_CM_PER_I2C1_CLKCTRL_MODULEMODE (0x00000003u)
#define AM335X_CM_PER_I2C2_CLKCTRL (0x44)
#define AM335X_CM_PER_I2C2_CLKCTRL_MODULEMODE_ENABLE (0x2u)
#define AM335X_CM_PER_I2C2_CLKCTRL_MODULEMODE (0x00000003u)
#define AM335X_CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_L4LS_GCLK (0x00000100u)
#define AM335X_CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_I2C_FCLK (0x01000000u)
#define AM335X_CM_PER_I2C1_CLKCTRL_MODULEMODE (0x00000003u)
#define AM335X_I2C_CON_XSA (0x00000100u)
#define AM335X_I2C_CFG_10BIT_SLAVE_ADDR AM335X_I2C_CON_XSA
#define AM335X_I2C_CON_XSA_SHIFT (0x00000008u)
#define AM335X_I2C_CFG_7BIT_SLAVE_ADDR (0 << AM335X_I2C_CON_XSA_SHIFT)
#define AM335X_I2C_CON_I2C_EN (0x00008000u)
#define AM335X_I2C_CON_TRX (0x00000200u)
#define AM335X_I2C_CON_MST (0x00000400u)
#define AM335X_I2C_CON_STB (0x00000800u)
#define AM335X_I2C_SYSC_AUTOIDLE (0x00000001u)
/*I2C0 module clock registers*/
#define AM335X_CM_WKUP_CONTROL_CLKCTRL (0x4)
#define AM335X_CM_WKUP_CLKSTCTRL (0x0)
#define AM335X_CM_WKUP_I2C0_CLKCTRL (0xb8)
#define AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE_ENABLE (0x2u)
#define AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE (0x00000003u)
#define AM335X_CM_WKUP_CONTROL_CLKCTRL_IDLEST_FUNC (0x0u)
#define AM335X_CM_WKUP_CONTROL_CLKCTRL_IDLEST_SHIFT (0x00000010u)
#define AM335X_CM_WKUP_CONTROL_CLKCTRL_IDLEST (0x00030000u)
#define AM335X_CM_WKUP_CLKSTCTRL_CLKACTIVITY_I2C0_GFCLK (0x00000800u)
#define AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST_FUNC (0x0u)
#define AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST_SHIFT (0x00000010u)
#define AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST (0x00030000u)
#define AM335X_SOC_CM_WKUP_REGS (AM335X_CM_PER_ADDR + 0x400)
/* I2C status Register */
#define AM335X_I2C_IRQSTATUS_NACK (1 << 1)
#define AM335X_I2C_IRQSTATUS_ROVR (1 << 11)
#define AM335X_I2C_IRQSTATUS_AL (1<<0)
#define AM335X_I2C_IRQSTATUS_ARDY (1 << 2)
#define AM335X_I2C_IRQSTATUS_RRDY (1 << 3)
#define AM335X_I2C_IRQSTATUS_XRDY (1 << 4)
#define AM335X_I2C_IRQSTATUS_XUDF (1 << 10)
#define AM335X_I2C_BUF_TXFIFO_CLR (0x00000040u)
#define AM335X_I2C_BUF_RXFIFO_CLR (0x00004000u)
#define AM335X_I2C_IRQSTATUS_AAS (1 << 9)
#define AM335X_I2C_IRQSTATUS_BF (1 << 8)
#define AM335X_I2C_IRQSTATUS_STC (1 << 6)
#define AM335X_I2C_IRQSTATUS_GC (1 << 5)
#define AM335X_I2C_IRQSTATUS_XDR (1 << 14)
#define AM335X_I2C_IRQSTATUS_RDR (1 << 13)
#define AM335X_I2C_INT_RECV_READY AM335X_I2C_IRQSTATUS_RRDY
#define AM335X_I2C_CON_STOP (0x00000002u)
#define AM335X_I2C_CON_START (0x00000001u)
#define AM335X_I2C_CFG_MST_RX AM335X_I2C_CON_MST
#define AM335X_I2C_CFG_MST_TX (AM335X_I2C_CON_TRX | AM335X_I2C_CON_MST)
#define AM335X_I2C_IRQSTATUS_RAW_BB (0x00001000u)
#define AM335X_CM_PER_OCPWP_L3_CLKSTCTRL_CLKACTIVITY_OCPWP_L4_GCLK (0x00000020u)
#define AM335X_I2C_INT_STOP_CONDITION AM335X_I2C_IRQSTATUS_BF