Changeset b89d6cc in rtems


Ignore:
Timestamp:
Jun 24, 2019, 8:16:59 PM (4 weeks ago)
Author:
Christian Mauderer <christian.mauderer@…>
Branches:
master
Children:
5cbee18
Parents:
5803f37
git-author:
Christian Mauderer <christian.mauderer@…> (06/24/19 20:16:59)
git-committer:
Christian Mauderer <oss@…> (06/29/19 07:37:24)
Message:

bsp/beagle: Partial re-write of I2C driver.

The old driver worked well for EEPROMS with the RTEMS EEPROM driver. But
it had problems with a lot of other situations. Although it's not a
direct port, the new driver is heavily modeled after the FreeBSD ti_i2c
driver.

Closes #3764.

Location:
bsps/arm
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • bsps/arm/beagle/i2c/bbb-i2c.c

    r5803f37 rb89d6cc  
    1010 * Copyright (c) 2016 Punit Vara <punitvara@gmail.com>
    1111 * Copyright (c) 2017 Sichen Zhao <zsc19940506@gmail.com>
     12 * Copyright (c) 2019 Christian Mauderer <christian.mauderer@embedded-brains.de>
    1213 *
    1314 * The license and distribution terms for this file may be
     
    1617 */
    1718
    18 /*
    19  * Modified on Punit Vara<punitvara@gmail.com> works, currently
    20  * the i2c file is working on the Beaglebone Black board(AM335x)
    21  */
    22 
     19#include <rtems/bspIo.h>
    2320#include <stdio.h>
    2421#include <bsp/i2c.h>
     
    2825#include <bsp/bbb-gpio.h>
    2926#include <rtems/score/assert.h>
    30 
    31 static void am335x_i2c0_pinmux( bbb_i2c_bus *bus )
    32 {
    33   REG( bus->regs + AM335X_CONF_I2C0_SDA ) =
    34     ( BBB_RXACTIVE | BBB_SLEWCTRL | BBB_PU_EN );
    35 
    36   REG( bus->regs + AM335X_CONF_I2C0_SCL ) =
    37     ( BBB_RXACTIVE | BBB_SLEWCTRL | BBB_PU_EN );
    38 }
    39 
    40 static void I2C0ModuleClkConfig( void )
    41 {
     27#include <dev/i2c/i2c.h>
     28
     29typedef struct bbb_i2c_bus {
     30  i2c_bus base;
     31  volatile bbb_i2c_regs *regs;
     32  struct {
     33    volatile uint32_t *ctrl_clkctrl;
     34    volatile uint32_t *i2c_clkctrl;
     35    volatile uint32_t *clkstctrl;
     36  } clkregs;
     37  struct {
     38    volatile uint32_t *conf_sda;
     39    uint32_t mmode_sda;
     40    volatile uint32_t *conf_scl;
     41    uint32_t mmode_scl;
     42  } pinregs;
     43  rtems_id task_id;
     44  rtems_vector_number irq;
     45  i2c_msg *buffer;
     46  size_t buffer_pos;
     47  int error;
     48  uint32_t con_reg;
     49} bbb_i2c_bus;
     50
     51#define TRANSFER_TIMEOUT_COUNT 100
     52#define FIFO_THRESHOLD 5
     53#define min(l,r) ((l) < (r) ? (l) : (r))
     54#if 0
     55#define debug_print(fmt, args...) printk("bbb-i2c: " fmt, ## args)
     56#else
     57#define debug_print(fmt, args...)
     58#endif
     59
     60static int am335x_i2c_fill_registers(
     61  bbb_i2c_bus *bus,
     62  uintptr_t register_base
     63)
     64{
     65  /* FIXME: The pin handling should be replaced by a proper pin handling during
     66   * initialization. This one is heavily board specific. */
     67#if ! IS_AM335X
     68  printk ("The I2C driver currently only works on Beagle Bone. Please add your pin configs.")
     69  return EINVAL;
     70#endif
     71  bus->regs = (volatile bbb_i2c_regs *) register_base;
     72  switch ((intptr_t) bus->regs) {
     73  case AM335X_I2C0_BASE:
     74    bus->clkregs.ctrl_clkctrl = &REG(AM335X_SOC_CM_WKUP_REGS +
     75                                 AM335X_CM_WKUP_CONTROL_CLKCTRL);
     76    bus->clkregs.i2c_clkctrl = &REG(AM335X_SOC_CM_WKUP_REGS +
     77                                 AM335X_CM_WKUP_I2C0_CLKCTRL);
     78    bus->clkregs.clkstctrl = &REG(AM335X_SOC_CM_WKUP_REGS +
     79                                   AM335X_CM_WKUP_CLKSTCTRL);
     80    bus->pinregs.conf_sda = &REG(AM335X_PADCONF_BASE + AM335X_CONF_I2C0_SDA);
     81    bus->pinregs.mmode_sda = 0;
     82    bus->pinregs.conf_scl = &REG(AM335X_PADCONF_BASE + AM335X_CONF_I2C0_SCL);
     83    bus->pinregs.mmode_scl = 0;
     84    break;
     85  case AM335X_I2C1_BASE:
     86    bus->clkregs.ctrl_clkctrl = &REG(AM335X_SOC_CM_WKUP_REGS +
     87                                 AM335X_CM_WKUP_CONTROL_CLKCTRL);
     88    bus->clkregs.i2c_clkctrl = &REG(AM335X_CM_PER_ADDR +
     89                                 AM335X_CM_PER_I2C1_CLKCTRL);
     90    bus->clkregs.clkstctrl = NULL;
     91    bus->pinregs.conf_sda = &REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_D1);
     92    bus->pinregs.mmode_sda = 2;
     93    bus->pinregs.conf_scl = &REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_CS0);
     94    bus->pinregs.mmode_scl = 2;
     95    break;
     96  case AM335X_I2C2_BASE:
     97    bus->clkregs.ctrl_clkctrl = &REG(AM335X_SOC_CM_WKUP_REGS +
     98                                 AM335X_CM_WKUP_CONTROL_CLKCTRL);
     99    bus->clkregs.i2c_clkctrl = &REG(AM335X_CM_PER_ADDR +
     100                                 AM335X_CM_PER_I2C2_CLKCTRL);
     101    bus->clkregs.clkstctrl = NULL;
     102    bus->pinregs.conf_sda = &REG(AM335X_PADCONF_BASE + AM335X_CONF_UART1_CTSN);
     103    bus->pinregs.mmode_sda = 3;
     104    bus->pinregs.conf_scl = &REG(AM335X_PADCONF_BASE + AM335X_CONF_UART1_RTSN);
     105    bus->pinregs.mmode_scl = 3;
     106    break;
     107  default:
     108    return EINVAL;
     109  }
     110  return 0;
     111}
     112
     113static void am335x_i2c_pinmux( bbb_i2c_bus *bus )
     114{
     115  *bus->pinregs.conf_sda =
     116    ( BBB_RXACTIVE | BBB_SLEWCTRL | bus->pinregs.mmode_sda);
     117
     118  *bus->pinregs.conf_scl =
     119    ( BBB_RXACTIVE | BBB_SLEWCTRL | bus->pinregs.mmode_scl);
     120}
     121
     122static void am335x_i2c_module_clk_enable( bbb_i2c_bus *bus )
     123{
     124  volatile uint32_t *ctrl_clkctrl = bus->clkregs.ctrl_clkctrl;
     125  volatile uint32_t *i2c_clkctrl = bus->clkregs.i2c_clkctrl;
     126  volatile uint32_t *clkstctrl = bus->clkregs.clkstctrl;
     127
    42128  /* Writing to MODULEMODE field of AM335X_CM_WKUP_I2C0_CLKCTRL register. */
    43   REG( AM335X_SOC_CM_WKUP_REGS + AM335X_CM_WKUP_I2C0_CLKCTRL ) |=
    44     AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE_ENABLE;
     129  *i2c_clkctrl |= AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE_ENABLE;
    45130
    46131  /* Waiting for MODULEMODE field to reflect the written value. */
    47132  while ( AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE_ENABLE !=
    48           ( REG( AM335X_SOC_CM_WKUP_REGS + AM335X_CM_WKUP_I2C0_CLKCTRL ) &
    49             AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE ) ) ;
     133          ( *i2c_clkctrl & AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE ) )
     134  { /* busy wait */ }
    50135
    51136  /*
     
    55140  while ( ( AM335X_CM_WKUP_CONTROL_CLKCTRL_IDLEST_FUNC <<
    56141            AM335X_CM_WKUP_CONTROL_CLKCTRL_IDLEST_SHIFT ) !=
    57           ( REG( AM335X_SOC_CM_WKUP_REGS + AM335X_CM_WKUP_CONTROL_CLKCTRL ) &
    58             AM335X_CM_WKUP_CONTROL_CLKCTRL_IDLEST ) ) ;
    59 
    60   /*
    61    * Waiting for CLKACTIVITY_I2C0_GFCLK field in AM335X_CM_WKUP_CLKSTCTRL
    62    * register to attain desired value.
    63    */
    64   while ( AM335X_CM_WKUP_CLKSTCTRL_CLKACTIVITY_I2C0_GFCLK !=
    65           ( REG( AM335X_SOC_CM_WKUP_REGS + AM335X_CM_WKUP_CLKSTCTRL ) &
    66             AM335X_CM_WKUP_CLKSTCTRL_CLKACTIVITY_I2C0_GFCLK ) ) ;
     142          ( *ctrl_clkctrl & AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST ) )
     143  { /* busy wait */ }
     144
     145  if ( clkstctrl != NULL ) {
     146    /*
     147     * Waiting for CLKACTIVITY_I2C0_GFCLK field in AM335X_CM_WKUP_CLKSTCTRL
     148     * register to attain desired value.
     149     */
     150    while ( AM335X_CM_WKUP_CLKSTCTRL_CLKACTIVITY_I2C0_GFCLK !=
     151            ( *clkstctrl & AM335X_CM_WKUP_CLKSTCTRL_CLKACTIVITY_I2C0_GFCLK ) )
     152    { /* busy wait */ }
     153  }
    67154
    68155  /*
     
    72159  while ( ( AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST_FUNC <<
    73160            AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST_SHIFT ) !=
    74           ( REG( AM335X_SOC_CM_WKUP_REGS + AM335X_CM_WKUP_I2C0_CLKCTRL ) &
    75             AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST ) ) ;
    76 }
    77 
    78 static void am335x_i2c_reset( bbb_i2c_bus *bus )
    79 {
    80   volatile bbb_i2c_regs *regs = bus->regs;
    81   int                    timeout = I2C_TIMEOUT;
    82 
    83   if ( REG( &regs->BBB_I2C_CON ) & BBB_I2C_CON_EN ) {
    84     REG( &regs->BBB_I2C_CON ) = BBB_I2C_CON_CLR;
    85     udelay( 50000 );
    86   }
    87 
    88   REG( &regs->BBB_I2C_SYSC ) = BBB_I2C_SYSC_SRST; /* for ES2 after soft reset */
    89   udelay( 1000 );
    90   REG( &regs->BBB_I2C_CON ) = BBB_I2C_CON_EN;
    91 
    92   while ( !( REG( &regs->BBB_I2C_SYSS ) & BBB_I2C_SYSS_RDONE ) && timeout-- ) {
    93     if ( timeout <= 0 ) {
    94       puts( "ERROR: Timeout in soft-reset\n" );
    95 
    96       return;
    97     }
    98 
    99     udelay( 1000 );
    100   }
    101 }
    102 /*
    103  * Possible values for msg->flag
    104  * - @ref I2C_M_TEN,
    105  * - @ref I2C_M_RD,
    106  * - @ref I2C_M_STOP,
    107  * - @ref I2C_M_NOSTART,
    108  * - @ref I2C_M_REV_DIR_ADDR,
    109  * - @ref I2C_M_IGNORE_NAK,
    110  * - @ref I2C_M_NO_RD_ACK, and
    111  * - @ref I2C_M_RECV_LEN.
    112  */
    113 
    114 static void am335x_i2c_set_address_size(
    115   const i2c_msg         *msgs,
    116   volatile bbb_i2c_regs *regs
    117 )
    118 {
    119   /*
    120    * Can be configured multiple modes here.
    121    * Need to think about own address modes
    122    */
    123   if ( ( msgs->flags & I2C_M_TEN ) == 0 ) {
    124     /* 7-bit mode slave address mode */
    125     REG( &regs->BBB_I2C_CON ) = AM335X_I2C_CFG_7BIT_SLAVE_ADDR;
    126   } else {
    127     /* 10-bit slave address mode */
    128     REG( &regs->BBB_I2C_CON ) = AM335X_I2C_CFG_10BIT_SLAVE_ADDR;
    129   }
    130 }
    131 
    132 static void am335x_i2c_next_byte( bbb_i2c_bus *bus )
    133 {
    134   i2c_msg *msg;
    135 
    136   ++bus->msgs;
    137   --bus->msg_todo;
    138   msg = &bus->msgs[ 0 ];
    139   bus->current_msg_todo = msg->len;
    140   bus->current_msg_byte = msg->buf;
    141 }
    142 
    143 static void am335x_i2c_masterint_enable(
    144   volatile bbb_i2c_regs *regs,
    145   unsigned int           flag
    146 )
    147 {
    148   REG( &regs->BBB_I2C_IRQENABLE_SET ) |= flag;
    149 }
    150 
    151 static void am335x_i2c_masterint_disable(
    152   volatile bbb_i2c_regs *regs,
    153   unsigned int           flag
    154 )
    155 {
    156   REG( &regs->BBB_I2C_IRQENABLE_CLR ) = flag;
    157 }
    158 
    159 static void am335x_int_clear(
    160   volatile bbb_i2c_regs *regs,
    161   unsigned int           flag
    162 )
    163 {
    164   REG( &regs->BBB_I2C_IRQSTATUS ) = flag;
    165 }
    166 
    167 static void am335x_clean_interrupts( volatile bbb_i2c_regs *regs )
    168 {
    169   am335x_i2c_masterint_enable( regs, BBB_I2C_ALL_FLAGS );
    170   am335x_int_clear( regs, BBB_I2C_ALL_FLAGS );
    171   am335x_i2c_masterint_disable( regs, BBB_I2C_ALL_FLAGS );
    172 }
    173 
    174 static void am335x_i2c_setup_read_transfer(
    175   bbb_i2c_bus           *bus,
    176   volatile bbb_i2c_regs *regs,
    177   const i2c_msg         *msgs,
    178   bool                   send_stop
    179 )
    180 {
    181   REG( &regs->BBB_I2C_CNT ) = bus->current_msg_todo;
    182 
    183   REG( &regs->BBB_I2C_CON ) = AM335X_I2C_CFG_MST_RX | AM335X_I2C_CON_I2C_EN;
    184 
    185   if ( send_stop ) {
    186     REG( &regs->BBB_I2C_CON ) |= AM335X_I2C_CON_START | AM335X_I2C_CON_STOP;
    187   } else {
    188     REG( &regs->BBB_I2C_CON ) |= AM335X_I2C_CON_START;
    189   }
    190 
    191   am335x_i2c_masterint_enable( regs, AM335X_I2C_INT_RECV_READY |
    192     AM335X_I2C_IRQSTATUS_ARDY );
    193 }
    194 
    195 static void am335x_i2c_continue_read_transfer(
    196   bbb_i2c_bus           *bus,
    197   volatile bbb_i2c_regs *regs
    198 )
    199 {
    200   bus->current_msg_byte[ bus->already_transferred ] =
    201     REG( &regs->BBB_I2C_DATA );
    202 
    203   bus->already_transferred++;
    204 
    205   REG( &regs->BBB_I2C_IRQSTATUS ) = AM335X_I2C_INT_RECV_READY;
    206 
    207   if ( bus->already_transferred == bus->current_msg_todo - 1 ) {
    208     REG( &regs->BBB_I2C_CON ) |= AM335X_I2C_CON_STOP;
    209   }
    210 }
    211 
    212 static void am335x_i2c_continue_write(
    213   bbb_i2c_bus           *bus,
    214   volatile bbb_i2c_regs *regs
    215 )
    216 {
    217   if ( bus->already_transferred == bus->msg_todo ) {
    218     REG( &regs->BBB_I2C_DATA ) =
    219       bus->current_msg_byte[ bus->already_transferred ];
    220     REG( &regs->BBB_I2C_IRQSTATUS ) = AM335X_I2C_IRQSTATUS_XRDY;
    221     am335x_i2c_masterint_disable( regs, AM335X_I2C_IRQSTATUS_XRDY );
    222     REG( &regs->BBB_I2C_CON ) |= AM335X_I2C_CON_STOP;
    223   } else {
    224     writeb( bus->current_msg_byte[ bus->already_transferred ],
    225       &regs->BBB_I2C_DATA );
    226     REG( &regs->BBB_I2C_IRQSTATUS ) = AM335X_I2C_IRQSTATUS_XRDY;
    227     bus->already_transferred++;
    228   }
    229 }
    230 
    231 static void am335x_i2c_setup_write_transfer(
    232   bbb_i2c_bus           *bus,
    233   volatile bbb_i2c_regs *regs,
    234   const i2c_msg         *msgs
    235 )
    236 {
    237   volatile unsigned int no_bytes;
    238 
    239   REG( &regs->BBB_I2C_CNT ) = bus->current_msg_todo;
    240   no_bytes = REG( &regs->BBB_I2C_CNT );
    241   (void) no_bytes; /* indicate we know that no_bytes is not referenced again */
    242   REG( &regs->BBB_I2C_SA ) = msgs->addr;
    243   REG( &regs->BBB_I2C_CON ) = AM335X_I2C_CFG_MST_TX | AM335X_I2C_CON_I2C_EN;
    244   am335x_clean_interrupts( regs );
    245   am335x_i2c_masterint_enable( regs, AM335X_I2C_IRQSTATUS_XRDY );
    246   REG( &regs->BBB_I2C_CON ) |= AM335X_I2C_CON_START | AM335X_I2C_CON_STOP;
    247 }
    248 
    249 static void am335x_i2c_setup_transfer(
    250   bbb_i2c_bus           *bus,
    251   volatile bbb_i2c_regs *regs
    252 )
    253 {
    254   const i2c_msg *msgs = bus->msgs;
    255   uint32_t       msg_todo = bus->msg_todo;
    256   bool           send_stop = false;
    257   uint32_t       i;
    258 
    259   bus->current_todo = msgs[ 0 ].len;
    260 
    261   for ( i = 1; i < msg_todo && ( msgs[ i ].flags & I2C_M_NOSTART ) != 0;
    262         ++i ) {
    263     bus->current_todo += msgs[ i ].len;
    264   }
    265 
    266   regs = bus->regs;
    267   REG( &bus->regs->BBB_I2C_BUF ) |= AM335X_I2C_BUF_TXFIFO_CLR;
    268   REG( &bus->regs->BBB_I2C_BUF ) |= AM335X_I2C_BUF_RXFIFO_CLR;
    269   am335x_i2c_set_address_size( msgs, regs );
    270   bus->read = ( msgs->flags & I2C_M_RD ) != 0;
    271   bus->already_transferred = ( bus->read == true ) ? 0 : 1;
    272 
    273   if ( bus->read ) {
    274     if ( bus->current_msg_todo == 1 ) {
    275       send_stop = true;
    276     }
    277 
    278     am335x_i2c_setup_read_transfer( bus, regs, msgs, send_stop );
    279   } else {
    280     am335x_i2c_setup_write_transfer( bus, regs, msgs );
    281   }
    282 }
    283 
    284 static void am335x_i2c_interrupt( void *arg )
    285 {
    286   bbb_i2c_bus           *bus = arg;
    287   volatile bbb_i2c_regs *regs = bus->regs;
    288   /* Get status of enabled interrupts */
    289   uint32_t irqstatus = REG( &regs->BBB_I2C_IRQSTATUS );
    290   bool     done = false;
    291 
    292   /*
    293    * Clear all enabled interrupt except receive ready
    294    * and transmit ready interrupt in status register
    295    */
    296   REG( &regs->BBB_I2C_IRQSTATUS ) =
    297     ( irqstatus & ~( AM335X_I2C_IRQSTATUS_RRDY |
    298                      AM335X_I2C_IRQSTATUS_XRDY ) );
    299 
    300   if ( irqstatus & AM335X_I2C_INT_RECV_READY ) {
    301     am335x_i2c_continue_read_transfer( bus, regs );
    302   }
    303 
    304   if ( irqstatus & AM335X_I2C_IRQSTATUS_XRDY ) {
    305     am335x_i2c_continue_write( bus, regs );
    306   }
    307 
    308   if ( irqstatus & AM335X_I2C_IRQSTATUS_NACK ) {
    309     done = true;
    310     am335x_i2c_masterint_disable( regs, AM335X_I2C_IRQSTATUS_NACK );
    311   }
    312 
    313   if ( irqstatus & AM335X_I2C_IRQSTATUS_ARDY ) {
    314     done = true;
    315     REG( &regs->BBB_I2C_IRQSTATUS ) = BBB_I2C_STAT_ARDY;
    316   }
    317 
    318   if ( irqstatus & AM335X_I2C_IRQSTATUS_BF ) {
    319     REG( &regs->BBB_I2C_IRQSTATUS ) = AM335X_I2C_IRQSTATUS_BF;
    320   }
    321 
    322   if ( done ) {
    323     uint32_t err = irqstatus & BBB_I2C_IRQ_ERROR;
    324     am335x_i2c_next_byte( bus );
    325 
    326     if ( bus->msg_todo == 0 ) {
    327       rtems_status_code sc;
    328       am335x_i2c_masterint_disable( regs, ( AM335X_I2C_IRQSTATUS_RRDY |
    329                                             AM335X_I2C_IRQSTATUS_XRDY |
    330                                             AM335X_I2C_IRQSTATUS_BF ) );
    331       REG( &regs->BBB_I2C_IRQSTATUS ) = err;
    332 
    333       sc = rtems_event_transient_send( bus->task_id );
    334       _Assert( sc == RTEMS_SUCCESSFUL );
    335       (void) sc;
    336     } else {
    337       am335x_i2c_setup_transfer( bus, regs );
    338     }
    339   }
    340 }
    341 
    342 static int am335x_i2c_transfer(
    343   i2c_bus *base,
    344   i2c_msg *msgs,
    345   uint32_t msg_count
    346 )
    347 {
    348   rtems_status_code      sc;
    349   bbb_i2c_bus           *bus = (bbb_i2c_bus *) base;
    350   volatile bbb_i2c_regs *regs;
    351   uint32_t               i;
    352 
    353   rtems_task_wake_after( 1 );
    354 
    355   if ( msg_count < 1 ) {
    356     return 1;
    357   }
    358 
    359   for ( i = 0; i < msg_count; ++i ) {
    360     if ( ( msgs[ i ].flags & I2C_M_RECV_LEN ) != 0 ) {
    361       return -EINVAL;
    362     }
    363   }
    364 
    365   bus->msgs = &msgs[ 0 ];
    366   bus->msg_todo = msg_count;
    367   bus->current_msg_todo = msgs[ 0 ].len;
    368   bus->current_msg_byte = msgs[ 0 ].buf;
    369   bus->task_id = rtems_task_self();
    370   regs = bus->regs;
    371   am335x_i2c_setup_transfer( bus, regs );
    372   REG( &regs->BBB_I2C_IRQENABLE_SET ) = BBB_I2C_IRQ_USED;
    373 
    374   sc = rtems_event_transient_receive( RTEMS_WAIT, bus->base.timeout );
    375 
    376   if ( sc != RTEMS_SUCCESSFUL ) {
    377     am335x_i2c_reset( bus );
    378     rtems_event_transient_clear();
    379 
    380     return -ETIMEDOUT;
    381   }
    382 
    383   return 0;
     161          ( *i2c_clkctrl & AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST ) ) ;
    384162}
    385163
     
    393171
    394172  prescaler = ( BBB_I2C_SYSCLK / BBB_I2C_INTERNAL_CLK ) - 1;
    395   REG( &bus->regs->BBB_I2C_PSC ) = prescaler;
     173  bus->regs->BBB_I2C_PSC = prescaler;
    396174  divider = BBB_I2C_INTERNAL_CLK / ( 2 * clock );
    397   REG( &bus->regs->BBB_I2C_SCLL ) = ( divider - 7 );
    398   REG( &bus->regs->BBB_I2C_SCLH ) = ( divider - 5 );
     175  bus->regs->BBB_I2C_SCLL = ( divider - 7 );
     176  bus->regs->BBB_I2C_SCLH = ( divider - 5 );
    399177
    400178  return 0;
     179}
     180
     181static int am335x_i2c_reset( bbb_i2c_bus *bus )
     182{
     183  volatile bbb_i2c_regs *regs = bus->regs;
     184  int                    timeout = 100;
     185  int                    err;
     186
     187  bus->con_reg = 0;
     188  regs->BBB_I2C_CON = bus->con_reg;
     189  udelay( 50000 );
     190
     191  regs->BBB_I2C_SYSC = AM335X_I2C_SYSC_SRST;
     192  udelay( 1000 );
     193  regs->BBB_I2C_CON = AM335X_I2C_CON_I2C_EN;
     194
     195  while ( !( regs->BBB_I2C_SYSS & AM335X_I2C_SYSS_RDONE )
     196          && timeout >= 0 ) {
     197    --timeout;
     198    udelay( 100 );
     199  }
     200
     201  if ( timeout <= 0 ) {
     202    puts( "ERROR: Timeout in soft-reset\n" );
     203    return ETIMEDOUT;
     204  }
     205
     206  /* Disable again after reset */
     207  regs->BBB_I2C_CON = bus->con_reg;
     208
     209  err = am335x_i2c_set_clock( &bus->base, I2C_BUS_CLOCK_DEFAULT );
     210  if (err) {
     211    return err;
     212  }
     213
     214  regs->BBB_I2C_BUF = AM335X_I2C_BUF_TXTRSH(FIFO_THRESHOLD) |
     215                              AM335X_I2C_BUF_RXTRSH(FIFO_THRESHOLD);
     216
     217  /* Enable the I2C controller in master mode. */
     218  bus->con_reg |= AM335X_I2C_CON_I2C_EN | AM335X_I2C_CON_MST;
     219  regs->BBB_I2C_CON = bus->con_reg;
     220
     221  regs->BBB_I2C_IRQENABLE_SET =
     222      AM335X_I2C_IRQSTATUS_XDR | AM335X_I2C_IRQSTATUS_XRDY |
     223      AM335X_I2C_IRQSTATUS_RDR | AM335X_I2C_IRQSTATUS_RRDY |
     224      AM335X_I2C_IRQSTATUS_ARDY | AM335X_I2C_IRQSTATUS_NACK |
     225      AM335X_I2C_IRQSTATUS_AL;
     226
     227  return 0;
     228}
     229
     230/* Return true if done. */
     231static bool am335x_i2c_transfer_intr(bbb_i2c_bus *bus, uint32_t status)
     232{
     233  size_t i;
     234  size_t amount = 0;
     235  volatile bbb_i2c_regs *regs = bus->regs;
     236
     237  /* Handle errors */
     238  if ((status & AM335X_I2C_IRQSTATUS_NACK) != 0) {
     239    debug_print("NACK\n");
     240    regs->BBB_I2C_IRQSTATUS = AM335X_I2C_IRQSTATUS_NACK;
     241    bus->error = ENXIO;
     242  } else if ((status & AM335X_I2C_IRQSTATUS_AL) != 0) {
     243    debug_print("Arbitration lost\n");
     244    regs->BBB_I2C_IRQSTATUS = AM335X_I2C_IRQSTATUS_AL;
     245    bus->error = ENXIO;
     246  }
     247
     248  /* Transfer finished? */
     249  if ((status & AM335X_I2C_IRQSTATUS_ARDY) != 0) {
     250    debug_print("ARDY transaction complete\n");
     251    if (bus->error != 0 && (bus->buffer->flags & I2C_M_STOP) == 0) {
     252      regs->BBB_I2C_CON = bus->con_reg | AM335X_I2C_CON_STOP;
     253    }
     254    regs->BBB_I2C_IRQSTATUS = AM335X_I2C_IRQSTATUS_ARDY |
     255                              AM335X_I2C_IRQSTATUS_RDR |
     256                              AM335X_I2C_IRQSTATUS_RRDY |
     257                              AM335X_I2C_IRQSTATUS_XDR |
     258                              AM335X_I2C_IRQSTATUS_XRDY;
     259    return true;
     260  }
     261
     262  if (bus->buffer->flags & I2C_M_RD) {
     263    if (status & AM335X_I2C_IRQSTATUS_RDR) {
     264      debug_print("RDR\n");
     265      /* last data received */
     266      amount = bus->buffer->len - bus->buffer_pos;
     267    } else if (status & AM335X_I2C_IRQSTATUS_RRDY) {
     268      debug_print("RRDY\n");
     269      /* FIFO threshold reached */
     270      amount = min(FIFO_THRESHOLD, bus->buffer->len - bus->buffer_pos);
     271    }
     272
     273    debug_print("Read %d bytes\n", amount);
     274    for (i = 0; i < amount; i++) {
     275      bus->buffer->buf[bus->buffer_pos] = (uint8_t)(regs->BBB_I2C_DATA);
     276      ++bus->buffer_pos;
     277    }
     278
     279    if (status & AM335X_I2C_IRQSTATUS_RDR) {
     280      regs->BBB_I2C_IRQSTATUS =AM335X_I2C_IRQSTATUS_RDR;
     281    }
     282    if (status & AM335X_I2C_IRQSTATUS_RRDY) {
     283      regs->BBB_I2C_IRQSTATUS =AM335X_I2C_IRQSTATUS_RRDY;
     284    }
     285  } else {
     286    if (status & AM335X_I2C_IRQSTATUS_XDR) {
     287      debug_print("XDR\n");
     288      /* Remaining TX data won't reach the FIFO threshold. */
     289      amount = bus->buffer->len - bus->buffer_pos;
     290    } else if (status & AM335X_I2C_IRQSTATUS_XRDY) {
     291      debug_print("XRDY\n");
     292      /* FIFO threshold reached */
     293      amount = min(FIFO_THRESHOLD, bus->buffer->len - bus->buffer_pos);
     294    }
     295
     296    debug_print("Write %d bytes\n", amount);
     297    for (i = 0; i < amount; i++) {
     298      regs->BBB_I2C_DATA = bus->buffer->buf[bus->buffer_pos];
     299      ++bus->buffer_pos;
     300    }
     301
     302    if (status & AM335X_I2C_IRQSTATUS_XDR) {
     303      regs->BBB_I2C_IRQSTATUS = AM335X_I2C_IRQSTATUS_XDR;
     304    }
     305    if (status & AM335X_I2C_IRQSTATUS_XRDY) {
     306      regs->BBB_I2C_IRQSTATUS = AM335X_I2C_IRQSTATUS_XRDY;
     307    }
     308  }
     309
     310  return false;
     311}
     312
     313static void am335x_i2c_interrupt( void *arg )
     314{
     315  bbb_i2c_bus *bus = arg;
     316  volatile bbb_i2c_regs *regs = bus->regs;
     317  uint32_t status;
     318
     319  status = regs->BBB_I2C_IRQSTATUS;
     320
     321  debug_print("interrupt: %08x\n", status);
     322
     323  if (status == 0) {
     324    /* Why can this even happen? */
     325    return;
     326  }
     327
     328  if (bus->buffer == NULL) {
     329    debug_print("Buffer is NULL\n");
     330    bus->error = EINVAL;
     331  }
     332
     333  if (bus->buffer == NULL || am335x_i2c_transfer_intr(bus, status)) {
     334    rtems_status_code sc;
     335    sc = rtems_event_transient_send( bus->task_id );
     336    _Assert( sc == RTEMS_SUCCESSFUL );
     337    (void) sc; /* suppress warning in case of no assert */
     338  }
     339}
     340
     341static int am335x_i2c_transfer(
     342  i2c_bus *base,
     343  i2c_msg *msgs,
     344  uint32_t nmsgs
     345)
     346{
     347  size_t i;
     348  int err = 0;
     349  bool repstart = false;
     350  int timeout = 0;
     351  bbb_i2c_bus *bus = (bbb_i2c_bus *) base;
     352  volatile bbb_i2c_regs *regs = bus->regs;
     353  uint32_t reg;
     354  rtems_status_code sc;
     355
     356  bus->task_id = rtems_task_self();
     357
     358  for (i = 0; i < nmsgs; i++) {
     359    bus->buffer = &msgs[i];
     360    bus->buffer_pos = 0;
     361    bus->error = 0;
     362
     363    debug_print("processing %2d/%d: addr: 0x%04x, flags: 0x%04x, len: %d, buf: %p\n",
     364        i, nmsgs, msgs[i].addr, msgs[i].flags, msgs[i].len, msgs[i].buf);
     365
     366    if (bus->buffer == NULL || bus->buffer->buf == NULL ||
     367        bus->buffer->len == 0) {
     368      err = EINVAL;
     369      break;
     370    }
     371
     372    /*
     373     * Send START when bus is busy on repeated starts.
     374     * Otherwise wait some time.
     375     */
     376    if (!repstart) {
     377      timeout = 0;
     378      while ((regs->BBB_I2C_IRQSTATUS_RAW & AM335X_I2C_IRQSTATUS_BB) != 0
     379              && timeout <= TRANSFER_TIMEOUT_COUNT) {
     380        ++timeout;
     381        rtems_task_wake_after(RTEMS_MICROSECONDS_TO_TICKS(1000));
     382      }
     383      if (timeout > TRANSFER_TIMEOUT_COUNT) {
     384        err = EBUSY;
     385        break;
     386      }
     387      timeout = 0;
     388    } else {
     389      repstart = false;
     390    }
     391
     392    if ((bus->buffer->flags & I2C_M_STOP) == 0) {
     393      repstart = true;
     394    }
     395
     396    regs->BBB_I2C_SA = bus->buffer->addr;
     397    regs->BBB_I2C_CNT = bus->buffer->len;
     398
     399    regs->BBB_I2C_BUF |= AM335X_I2C_BUF_RXFIFO_CLR | AM335X_I2C_BUF_TXFIFO_CLR;
     400
     401    reg = bus->con_reg | AM335X_I2C_CON_START;
     402    if (!repstart) {
     403      reg |= AM335X_I2C_CON_STOP;
     404    }
     405    if ((bus->buffer->flags & I2C_M_RD) == 0) {
     406      reg |= AM335X_I2C_CON_TRX;
     407    }
     408    /* Implicit stop on last message. */
     409    if (i == nmsgs - 1) {
     410      reg |= AM335X_I2C_CON_STOP;
     411    }
     412    regs->BBB_I2C_CON = reg;
     413
     414    sc = rtems_event_transient_receive( RTEMS_WAIT, bus->base.timeout );
     415    if ( sc != RTEMS_SUCCESSFUL ) {
     416      rtems_event_transient_clear();
     417      err = ETIMEDOUT;
     418      break;
     419    }
     420    if (bus->error) {
     421      err = bus->error;
     422      break;
     423    }
     424  }
     425
     426  if (timeout == 0) {
     427    while ((regs->BBB_I2C_IRQSTATUS_RAW & AM335X_I2C_IRQSTATUS_BB) != 0
     428            && timeout <= TRANSFER_TIMEOUT_COUNT) {
     429      ++timeout;
     430      rtems_task_wake_after(RTEMS_MICROSECONDS_TO_TICKS(1000));
     431    }
     432  }
     433
     434  if ((regs->BBB_I2C_CON & AM335X_I2C_CON_MST) == 0) {
     435    regs->BBB_I2C_CON = bus->con_reg;
     436  }
     437
     438  bus->buffer = NULL;
     439
     440  return -err;
    401441}
    402442
     
    406446  rtems_status_code sc;
    407447
     448  bus->regs->BBB_I2C_IRQENABLE_CLR = 0xFFFF;
     449  bus->regs->BBB_I2C_CON = 0;
    408450  sc = rtems_interrupt_handler_remove( bus->irq, am335x_i2c_interrupt, bus );
    409451  _Assert( sc == RTEMS_SUCCESSFUL );
     
    423465  int               err;
    424466
    425   /* Check bus number is >0 & <MAX */
     467  (void) input_clock; /* FIXME: Unused. Left for compatibility. */
     468
    426469  bus = (bbb_i2c_bus *) i2c_bus_alloc_and_init( sizeof( *bus ) );
    427470
     
    430473  }
    431474
    432   bus->regs = (volatile bbb_i2c_regs *) register_base;
    433 
    434   I2C0ModuleClkConfig();
    435   am335x_i2c0_pinmux( bus );
    436   am335x_i2c_reset( bus );
    437   bus->input_clock = input_clock;
    438   err = am335x_i2c_set_clock( &bus->base, I2C_BUS_CLOCK_DEFAULT );
    439 
    440   if ( err != 0 ) {
     475  bus->irq = irq;
     476
     477  err = am335x_i2c_fill_registers(bus, register_base);
     478  if (err != 0) {
    441479    ( *bus->base.destroy )( &bus->base );
    442     rtems_set_errno_and_return_minus_one( -err );
    443   }
    444 
    445   bus->irq = irq;
    446   REG( &bus->regs->BBB_I2C_IRQSTATUS ) = BBB_I2C_ALL_IRQ_FLAGS;
     480    rtems_set_errno_and_return_minus_one( err );
     481  }
     482  am335x_i2c_module_clk_enable(bus);
     483  am335x_i2c_pinmux( bus );
     484  err = am335x_i2c_reset( bus );
     485  if (err != 0) {
     486    ( *bus->base.destroy )( &bus->base );
     487    rtems_set_errno_and_return_minus_one( err );
     488  }
    447489
    448490  sc = rtems_interrupt_handler_install(
    449     irq,
     491    bus->irq,
    450492    "BBB_I2C",
    451493    RTEMS_INTERRUPT_UNIQUE,
    452494    (rtems_interrupt_handler) am335x_i2c_interrupt,
    453495    bus
    454        );
     496  );
    455497
    456498  if ( sc != RTEMS_SUCCESSFUL ) {
  • bsps/arm/beagle/include/bsp/i2c.h

    r5803f37 rb89d6cc  
    2525
    2626#include <rtems.h>
     27#include <bsp.h>
    2728#include <dev/i2c/i2c.h>
    28 #include <bsp.h>
    2929
    3030#ifdef __cplusplus
     
    3232#endif /* __cplusplus */
    3333
    34 
    35 /* I2C Configuration Register (I2C_CON): */
    36 
    37 #define BBB_I2C_CON_EN  (1 << 15)  /* I2C module enable */
    38 #define BBB_I2C_CON_BE  (1 << 14)  /* Big endian mode */
    39 #define BBB_I2C_CON_STB (1 << 11)  /* Start byte mode (master mode only) */
    40 #define BBB_I2C_CON_MST (1 << 10)  /* Master/slave mode */
    41 #define BBB_I2C_CON_TRX (1 << 9)   /* Transmitter/receiver mode */
    42            /* (master mode only) */
    43 #define BBB_I2C_CON_XA  (1 << 8)   /* Expand address */
    44 #define BBB_I2C_CON_STP (1 << 1)   /* Stop condition (master mode only) */
    45 #define BBB_I2C_CON_STT (1 << 0)   /* Start condition (master mode only) */
    46 #define BBB_I2C_CON_CLR 0x0  /* Clear configuration register */
    47 /* I2C Status Register (I2C_STAT): */
    48 
    49 #define BBB_I2C_STAT_SBD  (1 << 15) /* Single byte data */
    50 #define BBB_I2C_STAT_BB (1 << 12) /* Bus busy */
    51 #define BBB_I2C_STAT_ROVR (1 << 11) /* Receive overrun */
    52 #define BBB_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
    53 #define BBB_I2C_STAT_AAS  (1 << 9)  /* Address as slave */
    54 #define BBB_I2C_STAT_GC (1 << 5)
    55 #define BBB_I2C_STAT_XRDY (1 << 4)  /* Transmit data ready */
    56 #define BBB_I2C_STAT_RRDY (1 << 3)  /* Receive data ready */
    57 #define BBB_I2C_STAT_ARDY (1 << 2)  /* Register access ready */
    58 #define BBB_I2C_STAT_NACK (1 << 1)  /* No acknowledgment interrupt enable */
    59 #define BBB_I2C_STAT_AL (1 << 0)  /* Arbitration lost interrupt enable */
    60 
    61 /* I2C Interrupt Enable Register (I2C_IE): */
    62 #define BBB_I2C_IE_GC_IE  (1 << 5)
    63 #define BBB_I2C_IE_XRDY_IE  (1 << 4) /* Transmit data ready interrupt enable */
    64 #define BBB_I2C_IE_RRDY_IE  (1 << 3) /* Receive data ready interrupt enable */
    65 #define BBB_I2C_IE_ARDY_IE  (1 << 2) /* Register access ready interrupt enable */
    66 #define BBB_I2C_IE_NACK_IE  (1 << 1) /* No acknowledgment interrupt enable */
    67 #define BBB_I2C_IE_AL_IE  (1 << 0) /* Arbitration lost interrupt enable */
    68 
    69 /* I2C SYSC Register (I2C_SYSC): */
    70 #define BBB_I2C_SYSC_SRST (1 << 1)
    71 
    72 #define BBB_I2C_TIMEOUT 1000
    73 
    74 #define BBB_I2C_SYSS_RDONE            (1 << 0)  /* Internel reset monitoring */
    75 
    76 #define BBB_CONFIG_SYS_I2C_SPEED    100000
    77 #define BBB_CONFIG_SYS_I2C_SLAVE    1
    78 #define BBB_I2C_ALL_FLAGS 0x7FFF
    79 #define BBB_I2C_ALL_IRQ_FLAGS 0xFFFF
    80 
    8134#define BBB_I2C_SYSCLK 48000000
    8235#define BBB_I2C_INTERNAL_CLK 12000000
    83 #define BBB_I2C_SPEED_CLK 100000
    84 
    85 #define BBB_I2C_IRQ_ERROR \
    86   ( AM335X_I2C_IRQSTATUS_NACK \
    87     | AM335X_I2C_IRQSTATUS_ROVR \
    88     | AM335X_I2C_IRQSTATUS_AL \
    89     | AM335X_I2C_IRQSTATUS_ARDY \
    90     | AM335X_I2C_IRQSTATUS_RRDY \
    91     | AM335X_I2C_IRQSTATUS_XRDY \
    92     | AM335X_I2C_IRQSTATUS_XUDF )
    93 
    94 #define BBB_I2C_IRQ_USED \
    95   ( AM335X_I2C_IRQSTATUS_ARDY \
    96     | AM335X_I2C_IRQSTATUS_XRDY )
    9736
    9837#define BBB_I2C_0_BUS_PATH "/dev/i2c-0"
     
    10342#define BBB_I2C1_IRQ 71
    10443#define BBB_I2C2_IRQ 30
    105 
    106 #define BBB_MODE2 2
    107 #define BBB_MODE3 3
    10844
    10945typedef enum {
     
    15288} bbb_i2c_regs;
    15389
    154 typedef struct bbb_i2c_bus {
    155   i2c_bus base;
    156   volatile bbb_i2c_regs *regs;
    157   i2c_msg *msgs;
    158   uint32_t msg_todo;
    159   uint32_t current_msg_todo;
    160   uint8_t *current_msg_byte;
    161   uint32_t current_todo;
    162   bool read;
    163   bool hold;
    164   rtems_id task_id;
    165   rtems_vector_number irq;
    166   uint32_t input_clock;
    167   uint32_t already_transferred;
    168 } bbb_i2c_bus;
    169 
    17090int am335x_i2c_bus_register(
    17191  const char         *bus_path,
    17292  uintptr_t           register_base,
    173   uint32_t            input_clock,
     93  uint32_t            input_clock, /* FIXME: Unused. Left for compatibility. */
    17494  rtems_vector_number irq
    17595);
  • bsps/arm/include/libcpu/am335x.h

    r5803f37 rb89d6cc  
    665665#define AM335X_I2C_CON_STB   (0x00000800u)
    666666#define AM335X_I2C_SYSC_AUTOIDLE   (0x00000001u)
     667#define AM335X_I2C_SYSC_SRST       (0x00000002u)
     668#define AM335X_I2C_SYSC_ENAWAKEUP  (0x00000004u)
     669#define AM335X_I2C_SYSS_RDONE      (0x00000001u)
    667670
    668671/*I2C0 module clock registers*/
     
    687690
    688691
     692#define AM335X_I2C_BUF_TXTRSH_SHIFT (0)
     693#define AM335X_I2C_BUF_TXTRSH_MASK  (0x0000003Fu)
     694#define AM335X_I2C_BUF_TXTRSH(X)    (((X) << AM335X_I2C_BUF_TXTRSH_SHIFT) \
     695                                     & AM335X_I2C_BUF_TXTRSH_MASK)
     696#define AM335X_I2C_BUF_TXFIFO_CLR   (0x00000040u)
     697#define AM335X_I2C_BUF_RXTRSH_SHIFT (8)
     698#define AM335X_I2C_BUF_RXTRSH_MASK  (0x00003F00u)
     699#define AM335X_I2C_BUF_RXTRSH(X)    (((X) << AM335X_I2C_BUF_RXTRSH_SHIFT) \
     700                                     & AM335X_I2C_BUF_RXTRSH_MASK)
     701#define AM335X_I2C_BUF_RXFIFO_CLR   (0x00004000u)
     702
    689703/* I2C status Register */
     704#define AM335X_I2C_IRQSTATUS_AL   (1 << 0)
    690705#define AM335X_I2C_IRQSTATUS_NACK (1 << 1)
    691 #define AM335X_I2C_IRQSTATUS_ROVR (1 << 11)
    692 #define AM335X_I2C_IRQSTATUS_AL   (1<<0)
    693706#define AM335X_I2C_IRQSTATUS_ARDY (1 << 2)
    694707#define AM335X_I2C_IRQSTATUS_RRDY (1 << 3)
    695708#define AM335X_I2C_IRQSTATUS_XRDY (1 << 4)
     709#define AM335X_I2C_IRQSTATUS_GC   (1 << 5)
     710#define AM335X_I2C_IRQSTATUS_STC  (1 << 6)
     711#define AM335X_I2C_IRQSTATUS_AERR (1 << 7)
     712#define AM335X_I2C_IRQSTATUS_BF   (1 << 8)
     713#define AM335X_I2C_IRQSTATUS_AAS  (1 << 9)
    696714#define AM335X_I2C_IRQSTATUS_XUDF (1 << 10)
    697 #define AM335X_I2C_BUF_TXFIFO_CLR   (0x00000040u)
    698 #define AM335X_I2C_BUF_RXFIFO_CLR   (0x00004000u)
    699 #define AM335X_I2C_IRQSTATUS_AAS  (1 << 9)
    700 #define AM335X_I2C_IRQSTATUS_BF  (1 << 8)
    701 #define AM335X_I2C_IRQSTATUS_STC  (1 << 6)
    702 #define AM335X_I2C_IRQSTATUS_GC (1 << 5)
    703 #define AM335X_I2C_IRQSTATUS_XDR (1 << 14)
    704 #define AM335X_I2C_IRQSTATUS_RDR (1 << 13)
     715#define AM335X_I2C_IRQSTATUS_ROVR (1 << 11)
     716#define AM335X_I2C_IRQSTATUS_BB   (1 << 12)
     717#define AM335X_I2C_IRQSTATUS_RDR  (1 << 13)
     718#define AM335X_I2C_IRQSTATUS_XDR  (1 << 14)
    705719
    706720#define AM335X_I2C_INT_RECV_READY AM335X_I2C_IRQSTATUS_RRDY
     
    709723#define AM335X_I2C_CFG_MST_RX AM335X_I2C_CON_MST
    710724#define AM335X_I2C_CFG_MST_TX  (AM335X_I2C_CON_TRX | AM335X_I2C_CON_MST)
    711 #define AM335X_I2C_IRQSTATUS_RAW_BB   (0x00001000u)
    712725#define AM335X_CM_PER_OCPWP_L3_CLKSTCTRL_CLKACTIVITY_OCPWP_L4_GCLK (0x00000020u)
    713726#define AM335X_I2C_INT_STOP_CONDITION AM335X_I2C_IRQSTATUS_BF
Note: See TracChangeset for help on using the changeset viewer.