Changeset b89d6cc in rtems for bsps/arm/beagle/i2c/bbb-i2c.c


Ignore:
Timestamp:
Jun 24, 2019, 8:16:59 PM (2 months 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.

File:
1 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 ) {
Note: See TracChangeset for help on using the changeset viewer.