Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:48

0001 /**
0002  * @file
0003  *
0004  * @ingroup arm_beagle
0005  *
0006  * @brief BeagleBoard I2C bus initialization and API Support.
0007  */
0008 
0009 /*
0010  * Copyright (c) 2016 Punit Vara <punitvara@gmail.com>
0011  * Copyright (c) 2017 Sichen Zhao <zsc19940506@gmail.com>
0012  * Copyright (c) 2019 Christian Mauderer <christian.mauderer@embedded-brains.de>
0013  *
0014  * The license and distribution terms for this file may be
0015  * found in the file LICENSE in this distribution or at
0016  * http://www.rtems.org/license/LICENSE.
0017  */
0018 
0019 #include <rtems/bspIo.h>
0020 #include <stdio.h>
0021 #include <bsp/i2c.h>
0022 #include <libcpu/am335x.h>
0023 #include <rtems/irq-extension.h>
0024 #include <rtems/counter.h>
0025 #include <bsp/bbb-gpio.h>
0026 #include <rtems/score/assert.h>
0027 #include <dev/i2c/i2c.h>
0028 #include <ofw/ofw.h>
0029 
0030 typedef struct bbb_i2c_bus {
0031   i2c_bus base;
0032   volatile bbb_i2c_regs *regs;
0033   struct {
0034     volatile uint32_t *ctrl_clkctrl;
0035     volatile uint32_t *i2c_clkctrl;
0036     volatile uint32_t *clkstctrl;
0037   } clkregs;
0038   rtems_id task_id;
0039   rtems_vector_number irq;
0040   i2c_msg *buffer;
0041   size_t buffer_pos;
0042   int error;
0043   uint32_t con_reg;
0044 } bbb_i2c_bus;
0045 
0046 #define TRANSFER_TIMEOUT_COUNT 100
0047 #define FIFO_THRESHOLD 5
0048 #define min(l,r) ((l) < (r) ? (l) : (r))
0049 #if 0
0050 #define debug_print(fmt, args...) printk("bbb-i2c: " fmt, ## args)
0051 #else
0052 #define debug_print(fmt, args...)
0053 #endif
0054 /*
0055  * Here we assume the number of i2c nodes
0056  * will be less than 100.
0057  */
0058 #define PATH_LEN (strlen("/dev/i2c-xx") + 1)
0059 
0060 static int am335x_i2c_fill_registers(
0061   bbb_i2c_bus *bus,
0062   uint32_t base
0063 )
0064 {
0065   bus->regs = (volatile bbb_i2c_regs *)base;
0066 
0067   /*
0068    * FIXME: Implement a clock driver to parse and setup clocks
0069    */
0070   switch ((intptr_t) bus->regs) {
0071   case AM335X_I2C0_BASE:
0072     bus->clkregs.ctrl_clkctrl = &REG(AM335X_SOC_CM_WKUP_REGS +
0073                                  AM335X_CM_WKUP_CONTROL_CLKCTRL);
0074     bus->clkregs.i2c_clkctrl = &REG(AM335X_SOC_CM_WKUP_REGS +
0075                                  AM335X_CM_WKUP_I2C0_CLKCTRL);
0076     bus->clkregs.clkstctrl = &REG(AM335X_SOC_CM_WKUP_REGS +
0077                                    AM335X_CM_WKUP_CLKSTCTRL);
0078     break;
0079   case AM335X_I2C1_BASE:
0080     bus->clkregs.ctrl_clkctrl = &REG(AM335X_SOC_CM_WKUP_REGS +
0081                                  AM335X_CM_WKUP_CONTROL_CLKCTRL);
0082     bus->clkregs.i2c_clkctrl = &REG(AM335X_CM_PER_ADDR +
0083                                  AM335X_CM_PER_I2C1_CLKCTRL);
0084     bus->clkregs.clkstctrl = NULL;
0085     break;
0086   case AM335X_I2C2_BASE:
0087     bus->clkregs.ctrl_clkctrl = &REG(AM335X_SOC_CM_WKUP_REGS +
0088                                  AM335X_CM_WKUP_CONTROL_CLKCTRL);
0089     bus->clkregs.i2c_clkctrl = &REG(AM335X_CM_PER_ADDR +
0090                                  AM335X_CM_PER_I2C2_CLKCTRL);
0091     bus->clkregs.clkstctrl = NULL;
0092     break;
0093   default:
0094     return EINVAL;
0095   }
0096 
0097   return 0;
0098 }
0099 
0100 static void am335x_i2c_module_clk_enable( bbb_i2c_bus *bus )
0101 {
0102   volatile uint32_t *ctrl_clkctrl = bus->clkregs.ctrl_clkctrl;
0103   volatile uint32_t *i2c_clkctrl = bus->clkregs.i2c_clkctrl;
0104   volatile uint32_t *clkstctrl = bus->clkregs.clkstctrl;
0105 
0106   /* Writing to MODULEMODE field of AM335X_CM_WKUP_I2C0_CLKCTRL register. */
0107   *i2c_clkctrl |= AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE_ENABLE;
0108 
0109   /* Waiting for MODULEMODE field to reflect the written value. */
0110   while ( AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE_ENABLE !=
0111           ( *i2c_clkctrl & AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE ) )
0112   { /* busy wait */ }
0113 
0114   /*
0115    * Waiting for IDLEST field in AM335X_CM_WKUP_CONTROL_CLKCTRL
0116    * register to attain desired value.
0117    */
0118   while ( ( AM335X_CM_WKUP_CONTROL_CLKCTRL_IDLEST_FUNC <<
0119             AM335X_CM_WKUP_CONTROL_CLKCTRL_IDLEST_SHIFT ) !=
0120           ( *ctrl_clkctrl & AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST ) )
0121   { /* busy wait */ }
0122 
0123   if ( clkstctrl != NULL ) {
0124     /*
0125      * Waiting for CLKACTIVITY_I2C0_GFCLK field in AM335X_CM_WKUP_CLKSTCTRL
0126      * register to attain desired value.
0127      */
0128     while ( AM335X_CM_WKUP_CLKSTCTRL_CLKACTIVITY_I2C0_GFCLK !=
0129             ( *clkstctrl & AM335X_CM_WKUP_CLKSTCTRL_CLKACTIVITY_I2C0_GFCLK ) )
0130     { /* busy wait */ }
0131   }
0132 
0133   /*
0134    * Waiting for IDLEST field in AM335X_CM_WKUP_I2C0_CLKCTRL register to attain
0135    * desired value.
0136    */
0137   while ( ( AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST_FUNC <<
0138             AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST_SHIFT ) !=
0139           ( *i2c_clkctrl & AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST ) ) ;
0140 }
0141 
0142 static int am335x_i2c_set_clock(
0143   i2c_bus      *base,
0144   unsigned long clock
0145 )
0146 {
0147   bbb_i2c_bus           *bus = (bbb_i2c_bus *) base;
0148   uint32_t               prescaler, divider;
0149 
0150   prescaler = ( BBB_I2C_SYSCLK / BBB_I2C_INTERNAL_CLK ) - 1;
0151   bus->regs->BBB_I2C_PSC = prescaler;
0152   divider = BBB_I2C_INTERNAL_CLK / ( 2 * clock );
0153   bus->regs->BBB_I2C_SCLL = ( divider - 7 );
0154   bus->regs->BBB_I2C_SCLH = ( divider - 5 );
0155 
0156   return 0;
0157 }
0158 
0159 static int am335x_i2c_reset( bbb_i2c_bus *bus )
0160 {
0161   volatile bbb_i2c_regs *regs = bus->regs;
0162   int                    timeout = 100;
0163   int                    err;
0164 
0165   bus->con_reg = 0;
0166   regs->BBB_I2C_CON = bus->con_reg;
0167   rtems_counter_delay_nanoseconds(50000000);
0168 
0169   regs->BBB_I2C_SYSC = AM335X_I2C_SYSC_SRST;
0170   rtems_counter_delay_nanoseconds(1000000);
0171   regs->BBB_I2C_CON = AM335X_I2C_CON_I2C_EN;
0172 
0173   while ( !( regs->BBB_I2C_SYSS & AM335X_I2C_SYSS_RDONE )
0174           && timeout >= 0 ) {
0175     --timeout;
0176     rtems_counter_delay_nanoseconds(100000);
0177   }
0178 
0179   if ( timeout <= 0 ) {
0180     debug_print( "ERROR: Timeout in soft-reset\n" );
0181     return ETIMEDOUT;
0182   }
0183 
0184   /* Disable again after reset */
0185   regs->BBB_I2C_CON = bus->con_reg;
0186 
0187   err = am335x_i2c_set_clock( &bus->base, I2C_BUS_CLOCK_DEFAULT );
0188   if (err) {
0189     return err;
0190   }
0191 
0192   regs->BBB_I2C_BUF = AM335X_I2C_BUF_TXTRSH(FIFO_THRESHOLD) |
0193                               AM335X_I2C_BUF_RXTRSH(FIFO_THRESHOLD);
0194 
0195   /* Enable the I2C controller in master mode. */
0196   bus->con_reg |= AM335X_I2C_CON_I2C_EN | AM335X_I2C_CON_MST;
0197   regs->BBB_I2C_CON = bus->con_reg;
0198 
0199   regs->BBB_I2C_IRQENABLE_SET =
0200       AM335X_I2C_IRQSTATUS_XDR | AM335X_I2C_IRQSTATUS_XRDY |
0201       AM335X_I2C_IRQSTATUS_RDR | AM335X_I2C_IRQSTATUS_RRDY |
0202       AM335X_I2C_IRQSTATUS_ARDY | AM335X_I2C_IRQSTATUS_NACK |
0203       AM335X_I2C_IRQSTATUS_AL;
0204 
0205   return 0;
0206 }
0207 
0208 /* Return true if done. */
0209 static bool am335x_i2c_transfer_intr(bbb_i2c_bus *bus, uint32_t status)
0210 {
0211   size_t i;
0212   size_t amount = 0;
0213   volatile bbb_i2c_regs *regs = bus->regs;
0214 
0215   /* Handle errors */
0216   if ((status & AM335X_I2C_IRQSTATUS_NACK) != 0) {
0217     debug_print("NACK\n");
0218     regs->BBB_I2C_IRQSTATUS = AM335X_I2C_IRQSTATUS_NACK;
0219     bus->error = ENXIO;
0220   } else if ((status & AM335X_I2C_IRQSTATUS_AL) != 0) {
0221     debug_print("Arbitration lost\n");
0222     regs->BBB_I2C_IRQSTATUS = AM335X_I2C_IRQSTATUS_AL;
0223     bus->error = ENXIO;
0224   }
0225 
0226   /* Transfer finished? */
0227   if ((status & AM335X_I2C_IRQSTATUS_ARDY) != 0) {
0228     debug_print("ARDY transaction complete\n");
0229     if (bus->error != 0 && (bus->buffer->flags & I2C_M_STOP) == 0) {
0230       regs->BBB_I2C_CON = bus->con_reg | AM335X_I2C_CON_STOP;
0231     }
0232     regs->BBB_I2C_IRQSTATUS = AM335X_I2C_IRQSTATUS_ARDY |
0233                               AM335X_I2C_IRQSTATUS_RDR |
0234                               AM335X_I2C_IRQSTATUS_RRDY |
0235                               AM335X_I2C_IRQSTATUS_XDR |
0236                               AM335X_I2C_IRQSTATUS_XRDY;
0237     return true;
0238   }
0239 
0240   if (bus->buffer->flags & I2C_M_RD) {
0241     if (status & AM335X_I2C_IRQSTATUS_RDR) {
0242       debug_print("RDR\n");
0243       /* last data received */
0244       amount = bus->buffer->len - bus->buffer_pos;
0245     } else if (status & AM335X_I2C_IRQSTATUS_RRDY) {
0246       debug_print("RRDY\n");
0247       /* FIFO threshold reached */
0248       amount = min(FIFO_THRESHOLD, bus->buffer->len - bus->buffer_pos);
0249     }
0250 
0251     debug_print("Read %d bytes\n", amount);
0252     for (i = 0; i < amount; i++) {
0253       bus->buffer->buf[bus->buffer_pos] = (uint8_t)(regs->BBB_I2C_DATA);
0254       ++bus->buffer_pos;
0255     }
0256 
0257     if (status & AM335X_I2C_IRQSTATUS_RDR) {
0258       regs->BBB_I2C_IRQSTATUS =AM335X_I2C_IRQSTATUS_RDR;
0259     }
0260     if (status & AM335X_I2C_IRQSTATUS_RRDY) {
0261       regs->BBB_I2C_IRQSTATUS =AM335X_I2C_IRQSTATUS_RRDY;
0262     }
0263   } else {
0264     if (status & AM335X_I2C_IRQSTATUS_XDR) {
0265       debug_print("XDR\n");
0266       /* Remaining TX data won't reach the FIFO threshold. */
0267       amount = bus->buffer->len - bus->buffer_pos;
0268     } else if (status & AM335X_I2C_IRQSTATUS_XRDY) {
0269       debug_print("XRDY\n");
0270       /* FIFO threshold reached */
0271       amount = min(FIFO_THRESHOLD, bus->buffer->len - bus->buffer_pos);
0272     }
0273 
0274     debug_print("Write %d bytes\n", amount);
0275     for (i = 0; i < amount; i++) {
0276       regs->BBB_I2C_DATA = bus->buffer->buf[bus->buffer_pos];
0277       ++bus->buffer_pos;
0278     }
0279 
0280     if (status & AM335X_I2C_IRQSTATUS_XDR) {
0281       regs->BBB_I2C_IRQSTATUS = AM335X_I2C_IRQSTATUS_XDR;
0282     }
0283     if (status & AM335X_I2C_IRQSTATUS_XRDY) {
0284       regs->BBB_I2C_IRQSTATUS = AM335X_I2C_IRQSTATUS_XRDY;
0285     }
0286   }
0287 
0288   return false;
0289 }
0290 
0291 static void am335x_i2c_interrupt( void *arg )
0292 {
0293   bbb_i2c_bus *bus = arg;
0294   volatile bbb_i2c_regs *regs = bus->regs;
0295   uint32_t status;
0296 
0297   status = regs->BBB_I2C_IRQSTATUS;
0298 
0299   debug_print("interrupt: %08x\n", status);
0300 
0301   if (status == 0) {
0302     /* Why can this even happen? */
0303     return;
0304   }
0305 
0306   if (bus->buffer == NULL) {
0307     debug_print("Buffer is NULL\n");
0308     bus->error = EINVAL;
0309   }
0310 
0311   if (bus->buffer == NULL || am335x_i2c_transfer_intr(bus, status)) {
0312     rtems_status_code sc;
0313     sc = rtems_event_transient_send( bus->task_id );
0314     _Assert( sc == RTEMS_SUCCESSFUL );
0315     (void) sc; /* suppress warning in case of no assert */
0316   }
0317 }
0318 
0319 static int am335x_i2c_transfer(
0320   i2c_bus *base,
0321   i2c_msg *msgs,
0322   uint32_t nmsgs
0323 )
0324 {
0325   size_t i;
0326   int err = 0;
0327   bool repstart = false;
0328   int timeout = 0;
0329   bbb_i2c_bus *bus = (bbb_i2c_bus *) base;
0330   volatile bbb_i2c_regs *regs = bus->regs;
0331   uint32_t reg;
0332   rtems_status_code sc;
0333 
0334   bus->task_id = rtems_task_self();
0335 
0336   for (i = 0; i < nmsgs; i++) {
0337     bus->buffer = &msgs[i];
0338     bus->buffer_pos = 0;
0339     bus->error = 0;
0340 
0341     debug_print("processing %2d/%d: addr: 0x%04x, flags: 0x%04x, len: %d, buf: %p\n",
0342         i, nmsgs, msgs[i].addr, msgs[i].flags, msgs[i].len, msgs[i].buf);
0343 
0344     if (bus->buffer == NULL || bus->buffer->buf == NULL ||
0345         bus->buffer->len == 0) {
0346       err = EINVAL;
0347       break;
0348     }
0349 
0350     /*
0351      * Send START when bus is busy on repeated starts.
0352      * Otherwise wait some time.
0353      */
0354     if (!repstart) {
0355       timeout = 0;
0356       while ((regs->BBB_I2C_IRQSTATUS_RAW & AM335X_I2C_IRQSTATUS_BB) != 0
0357               && timeout <= TRANSFER_TIMEOUT_COUNT) {
0358         ++timeout;
0359         rtems_task_wake_after(RTEMS_MICROSECONDS_TO_TICKS(1000));
0360       }
0361       if (timeout > TRANSFER_TIMEOUT_COUNT) {
0362         err = EBUSY;
0363         break;
0364       }
0365       timeout = 0;
0366     } else {
0367       repstart = false;
0368     }
0369 
0370     if ((bus->buffer->flags & I2C_M_STOP) == 0) {
0371       repstart = true;
0372     }
0373 
0374     regs->BBB_I2C_SA = bus->buffer->addr;
0375     regs->BBB_I2C_CNT = bus->buffer->len;
0376 
0377     regs->BBB_I2C_BUF |= AM335X_I2C_BUF_RXFIFO_CLR | AM335X_I2C_BUF_TXFIFO_CLR;
0378 
0379     reg = bus->con_reg | AM335X_I2C_CON_START;
0380     if (!repstart) {
0381       reg |= AM335X_I2C_CON_STOP;
0382     }
0383     if ((bus->buffer->flags & I2C_M_RD) == 0) {
0384       reg |= AM335X_I2C_CON_TRX;
0385     }
0386     /* Implicit stop on last message. */
0387     if (i == nmsgs - 1) {
0388       reg |= AM335X_I2C_CON_STOP;
0389     }
0390     regs->BBB_I2C_CON = reg;
0391 
0392     sc = rtems_event_transient_receive( RTEMS_WAIT, bus->base.timeout );
0393     if ( sc != RTEMS_SUCCESSFUL ) {
0394       rtems_event_transient_clear();
0395       err = ETIMEDOUT;
0396       break;
0397     }
0398     if (bus->error) {
0399       err = bus->error;
0400       break;
0401     }
0402   }
0403 
0404   if (timeout == 0) {
0405     while ((regs->BBB_I2C_IRQSTATUS_RAW & AM335X_I2C_IRQSTATUS_BB) != 0
0406             && timeout <= TRANSFER_TIMEOUT_COUNT) {
0407       ++timeout;
0408       rtems_task_wake_after(RTEMS_MICROSECONDS_TO_TICKS(1000));
0409     }
0410   }
0411 
0412   if ((regs->BBB_I2C_CON & AM335X_I2C_CON_MST) == 0) {
0413     regs->BBB_I2C_CON = bus->con_reg;
0414   }
0415 
0416   bus->buffer = NULL;
0417 
0418   return -err;
0419 }
0420 
0421 static void am335x_i2c_destroy( i2c_bus *base )
0422 {
0423   bbb_i2c_bus      *bus = (bbb_i2c_bus *) base;
0424   rtems_status_code sc;
0425 
0426   bus->regs->BBB_I2C_IRQENABLE_CLR = 0xFFFF;
0427   bus->regs->BBB_I2C_CON = 0;
0428   sc = rtems_interrupt_handler_remove( bus->irq, am335x_i2c_interrupt, bus );
0429   _Assert( sc == RTEMS_SUCCESSFUL );
0430   (void) sc;
0431   i2c_bus_destroy_and_free( &bus->base );
0432 }
0433 
0434 static int am335x_i2c_bus_register(
0435   uint32_t reg_base,
0436   rtems_vector_number irq,
0437   const char *bus_path
0438 )
0439 {
0440   bbb_i2c_bus        *bus;
0441   rtems_status_code   sc;
0442   int                 err;
0443 
0444   bus = (bbb_i2c_bus *) i2c_bus_alloc_and_init( sizeof( *bus ) );
0445   bus->irq = irq;
0446 
0447   if ( bus == NULL ) {
0448     return -1;
0449   }
0450 
0451   err = am335x_i2c_fill_registers(bus, reg_base);
0452   if (err != 0) {
0453     printf("i2c: invalid register base\n");
0454     ( *bus->base.destroy )( &bus->base );
0455     rtems_set_errno_and_return_minus_one( err );
0456   }
0457 
0458   am335x_i2c_module_clk_enable( bus );
0459   err = am335x_i2c_reset( bus );
0460   if (err != 0) {
0461     printk("i2c: reset timed out\n");
0462     ( *bus->base.destroy )( &bus->base );
0463     rtems_set_errno_and_return_minus_one( err );
0464   }
0465 
0466   sc = rtems_interrupt_handler_install(
0467     bus->irq,
0468     "BBB_I2C",
0469     RTEMS_INTERRUPT_UNIQUE,
0470     (rtems_interrupt_handler) am335x_i2c_interrupt,
0471     bus
0472   );
0473 
0474   if ( sc != RTEMS_SUCCESSFUL ) {
0475     ( *bus->base.destroy )( &bus->base );
0476     rtems_set_errno_and_return_minus_one( EIO );
0477   }
0478 
0479   bus->base.transfer = am335x_i2c_transfer;
0480   bus->base.set_clock = am335x_i2c_set_clock;
0481   bus->base.destroy = am335x_i2c_destroy;
0482 
0483   return i2c_bus_register( &bus->base, bus_path );
0484 }
0485 
0486 void beagle_i2c_init(phandle_t node)
0487 {
0488   int                   err;
0489   int                   unit;
0490   char                  bus_path[PATH_LEN];
0491   rtems_vector_number   irq;
0492   rtems_ofw_memory_area reg;
0493 
0494   if (!rtems_ofw_is_node_compatible(node, "ti,omap4-i2c"))
0495     /* We cannot handle this device */
0496     return ;
0497 
0498   unit = beagle_get_node_unit(node);
0499   if (unit < 0 || unit >= 100) {
0500     printk("i2c: cannot register device, node unit number invalid.");
0501     printk(" Valid range is 0 <= unit < 100\n");
0502     return ;
0503   }
0504 
0505   err = rtems_ofw_get_prop(node, "rtems,path", (void *)bus_path, PATH_LEN);
0506   if (err < 0) {
0507     /* No path was provided in the device tree therefore use the default one */
0508     snprintf(bus_path, PATH_LEN, "/dev/i2c-%d", unit);
0509   } else if (err >= PATH_LEN) {
0510     /* Null terminate the string */
0511     bus_path[PATH_LEN - 1] = 0;
0512     printk("i2c: bus path too long, trucated %s\n", bus_path);
0513   }
0514 
0515   err = rtems_ofw_get_interrupts(node, &irq, sizeof(irq));
0516   if (err < 1) {
0517     printk("i2c: cannot register device, irq missing in device tree\n");
0518     return ;
0519   }
0520 
0521   err = rtems_ofw_get_reg(node, &reg, sizeof(reg));
0522   if (err <= 0) {
0523     printk("i2c: cannot register device, regs field missing\n");
0524     return ;
0525   }
0526 
0527   err = am335x_i2c_bus_register(reg.start, irq, bus_path);
0528   if (err != 0)
0529     printk("i2c: Could not register device (%d)\n", err);
0530 }