File indexing completed on 2025-05-11 08:22:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
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
0056
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
0069
0070 switch ((intptr_t) bus->regs) {
0071 case AM335X_I2C0_BASE:
0072 bus->clkregs.ctrl_clkctrl = ®(AM335X_SOC_CM_WKUP_REGS +
0073 AM335X_CM_WKUP_CONTROL_CLKCTRL);
0074 bus->clkregs.i2c_clkctrl = ®(AM335X_SOC_CM_WKUP_REGS +
0075 AM335X_CM_WKUP_I2C0_CLKCTRL);
0076 bus->clkregs.clkstctrl = ®(AM335X_SOC_CM_WKUP_REGS +
0077 AM335X_CM_WKUP_CLKSTCTRL);
0078 break;
0079 case AM335X_I2C1_BASE:
0080 bus->clkregs.ctrl_clkctrl = ®(AM335X_SOC_CM_WKUP_REGS +
0081 AM335X_CM_WKUP_CONTROL_CLKCTRL);
0082 bus->clkregs.i2c_clkctrl = ®(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 = ®(AM335X_SOC_CM_WKUP_REGS +
0088 AM335X_CM_WKUP_CONTROL_CLKCTRL);
0089 bus->clkregs.i2c_clkctrl = ®(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
0107 *i2c_clkctrl |= AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE_ENABLE;
0108
0109
0110 while ( AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE_ENABLE !=
0111 ( *i2c_clkctrl & AM335X_CM_WKUP_I2C0_CLKCTRL_MODULEMODE ) )
0112 { }
0113
0114
0115
0116
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 { }
0122
0123 if ( clkstctrl != NULL ) {
0124
0125
0126
0127
0128 while ( AM335X_CM_WKUP_CLKSTCTRL_CLKACTIVITY_I2C0_GFCLK !=
0129 ( *clkstctrl & AM335X_CM_WKUP_CLKSTCTRL_CLKACTIVITY_I2C0_GFCLK ) )
0130 { }
0131 }
0132
0133
0134
0135
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
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
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
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
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
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
0244 amount = bus->buffer->len - bus->buffer_pos;
0245 } else if (status & AM335X_I2C_IRQSTATUS_RRDY) {
0246 debug_print("RRDY\n");
0247
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
0267 amount = bus->buffer->len - bus->buffer_pos;
0268 } else if (status & AM335X_I2C_IRQSTATUS_XRDY) {
0269 debug_print("XRDY\n");
0270
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
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;
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
0352
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
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
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
0508 snprintf(bus_path, PATH_LEN, "/dev/i2c-%d", unit);
0509 } else if (err >= PATH_LEN) {
0510
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, ®, 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 }