From 8f550d2fa125daf0cf02229324cebf23412e0eeb Mon Sep 17 00:00:00 2001 From: Sichen Zhao <1473996754@qq.com> Date: Wed, 14 Jun 2017 22:53:44 +0800 Subject: 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 --- c/src/lib/libbsp/arm/beagle/Makefile.am | 1 + c/src/lib/libbsp/arm/beagle/i2c/bbb-i2c.c | 461 +++++++++++++++++++++++++ c/src/lib/libbsp/arm/beagle/include/bbb-gpio.h | 4 +- c/src/lib/libbsp/arm/beagle/include/i2c.h | 304 ++++++++-------- c/src/lib/libcpu/arm/shared/include/am335x.h | 136 ++++++++ 5 files changed, 765 insertions(+), 141 deletions(-) create mode 100644 c/src/lib/libbsp/arm/beagle/i2c/bbb-i2c.c diff --git a/c/src/lib/libbsp/arm/beagle/Makefile.am b/c/src/lib/libbsp/arm/beagle/Makefile.am index c14db4976a..8e10ee2fd2 100644 --- a/c/src/lib/libbsp/arm/beagle/Makefile.am +++ b/c/src/lib/libbsp/arm/beagle/Makefile.am @@ -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 diff --git a/c/src/lib/libbsp/arm/beagle/i2c/bbb-i2c.c b/c/src/lib/libbsp/arm/beagle/i2c/bbb-i2c.c new file mode 100644 index 0000000000..3d7d820511 --- /dev/null +++ b/c/src/lib/libbsp/arm/beagle/i2c/bbb-i2c.c @@ -0,0 +1,461 @@ +/** + * @file + * + * @ingroup arm_beagle + * + * @brief BeagleBoard I2C bus initialization and API Support. + */ + +/* + * Copyright (c) 2017 Sichen Zhao + * + * 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 works, currently + * the i2c file is working on the Beaglebone Black board(AM335x) + */ + +#include +#include +#include +#include +#include +#include +#include + +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( ®s->BBB_I2C_CON ) & BBB_I2C_CON_EN ) { + REG( ®s->BBB_I2C_CON ) = BBB_I2C_CON_CLR; + udelay( 50000 ); + } + + REG( ®s->BBB_I2C_SYSC ) = BBB_I2C_SYSC_SRST; /* for ES2 after soft reset */ + udelay( 1000 ); + REG( ®s->BBB_I2C_CON ) = BBB_I2C_CON_EN; + + while ( !( REG( ®s->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( ®s->BBB_I2C_CON ) = AM335X_I2C_CFG_7BIT_SLAVE_ADDR; + } else { + /* 10-bit slave address mode*/ + REG( ®s->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( ®s->BBB_I2C_IRQENABLE_SET ) |= flag; +} + +static void am335x_i2c_masterint_disable( + volatile bbb_i2c_regs *regs, + unsigned int flag +) +{ + REG( ®s->BBB_I2C_IRQENABLE_CLR ) = flag; +} + +static void am335x_int_clear( + volatile bbb_i2c_regs *regs, + unsigned int flag +) +{ + REG( ®s->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( ®s->BBB_I2C_CNT ) = bus->current_msg_todo; + + REG( ®s->BBB_I2C_CON ) = AM335X_I2C_CFG_MST_RX | AM335X_I2C_CON_I2C_EN; + + if ( send_stop ) { + REG( ®s->BBB_I2C_CON ) |= AM335X_I2C_CON_START | AM335X_I2C_CON_STOP; + } else { + REG( ®s->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( ®s->BBB_I2C_DATA ); + + bus->already_transferred++; + + REG( ®s->BBB_I2C_IRQSTATUS ) = AM335X_I2C_INT_RECV_READY; + + if ( bus->already_transferred == bus->current_msg_todo - 1 ) { + REG( ®s->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( ®s->BBB_I2C_DATA ) = + bus->current_msg_byte[ bus->already_transferred ]; + REG( ®s->BBB_I2C_IRQSTATUS ) = AM335X_I2C_IRQSTATUS_XRDY; + am335x_i2c_masterint_disable( regs, AM335X_I2C_IRQSTATUS_XRDY ); + REG( ®s->BBB_I2C_CON ) |= AM335X_I2C_CON_STOP; + } else { + writeb( bus->current_msg_byte[ bus->already_transferred ], + ®s->BBB_I2C_DATA ); + REG( ®s->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( ®s->BBB_I2C_CNT ) = bus->current_msg_todo; + no_bytes = REG( ®s->BBB_I2C_CNT ); + REG( ®s->BBB_I2C_SA ) = msgs->addr; + REG( ®s->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( ®s->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( ®s->BBB_I2C_IRQSTATUS ); + bool done = false; + + /* Clear all enabled interrupt except receive ready + and transmit ready interrupt in status register */ + REG( ®s->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( ®s->BBB_I2C_IRQSTATUS ) = BBB_I2C_STAT_ARDY; + } + + if ( irqstatus & AM335X_I2C_IRQSTATUS_BF ) { + REG( ®s->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( ®s->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( ®s->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 & 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 ); +} \ No newline at end of file diff --git a/c/src/lib/libbsp/arm/beagle/include/bbb-gpio.h b/c/src/lib/libbsp/arm/beagle/include/bbb-gpio.h index 8cce556efd..ceb12a4dec 100644 --- a/c/src/lib/libbsp/arm/beagle/include/bbb-gpio.h +++ b/c/src/lib/libbsp/arm/beagle/include/bbb-gpio.h @@ -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 */ \ No newline at end of file +#endif /* LIBBSP_ARM_BEAGLE_BBB_GPIO_H */ diff --git a/c/src/lib/libbsp/arm/beagle/include/i2c.h b/c/src/lib/libbsp/arm/beagle/include/i2c.h index 010fcee09c..3ada3c4b0d 100644 --- a/c/src/lib/libbsp/arm/beagle/include/i2c.h +++ b/c/src/lib/libbsp/arm/beagle/include/i2c.h @@ -24,7 +24,7 @@ #define LIBBSP_ARM_BEAGLE_I2C_H #include - +#include #include #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 - -/* 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 - -#define OMAP_I2C_STANDARD 100000 -#define OMAP_I2C_FAST_MODE 400000 -#define OMAP_I2C_HIGH_SPEED 3400000 - - -/* 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_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 */ + +/* I2C SYSC Register (I2C_SYSC): */ +#define BBB_I2C_SYSC_SRST (1 << 1) + +#define BBB_I2C_TIMEOUT 1000 + +#define BBB_I2C_SYSS_RDONE (1 << 0) /* Internel reset monitoring */ + +#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 + +#define BBB_I2C_SYSCLK 48000000 +#define BBB_I2C_INTERNAL_CLK 12000000 +#define BBB_I2C_SPEED_CLK 100000 + +#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 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 BBB_I2C0_IRQ 70 +#define BBB_I2C1_IRQ 71 +#define BBB_I2C2_IRQ 30 + +#define BBB_MODE2 2 +#define BBB_MODE3 3 + +typedef enum { + I2C0, + I2C1, + I2C2, + I2C_COUNT +} bbb_i2c_id_t; + +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; + +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; + +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 + ); +} -/* - * 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 I2C_PSC_MAX 0x0f -#define I2C_PSC_MIN 0x00 - - -#define DISP_LINE_LEN 128 -#define I2C_TIMEOUT 1000 - -#define I2C_BUS_MAX 3 - -#define I2C_BASE1 (OMAP34XX_CORE_L4_IO_BASE + 0x070000) - -#define I2C_DEFAULT_BASE I2C_BASE1 - -#define I2C_SYSS_RDONE (1 << 0) /* Internel reset monitoring */ - -#define CONFIG_SYS_I2C_SPEED 100000 -#define CONFIG_SYS_I2C_SLAVE 1 - -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; -}; +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 } diff --git a/c/src/lib/libcpu/arm/shared/include/am335x.h b/c/src/lib/libcpu/arm/shared/include/am335x.h index f59f896c9e..c29ae6c761 100644 --- a/c/src/lib/libcpu/arm/shared/include/am335x.h +++ b/c/src/lib/libcpu/arm/shared/include/am335x.h @@ -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 -- cgit v1.2.3