File indexing completed on 2025-05-11 08:24:04
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #include <dev/i2c/cadence-i2c.h>
0029 #include <dev/i2c/cadence-i2c-regs.h>
0030
0031 #include <rtems/score/assert.h>
0032
0033 #include <dev/i2c/i2c.h>
0034
0035 #define CADENCE_I2C_DIV_A_MAX 4
0036
0037 #define CADENCE_I2C_DIV_B_MAX 64
0038
0039 #define CADENCE_I2C_FIFO_DEPTH 16
0040
0041 #define CADENCE_I2C_DATA_IRQ_DEPTH (CADENCE_I2C_FIFO_DEPTH - 2)
0042
0043 #define CADENCE_I2C_TRANSFER_SIZE_MAX 255
0044
0045 #define CADENCE_I2C_TRANSFER_SIZE_ONCE_MAX (18 * CADENCE_I2C_DATA_IRQ_DEPTH)
0046
0047 #define CADENCE_I2C_IRQ_ERROR \
0048 (CADENCE_I2C_IXR_ARB_LOST \
0049 | CADENCE_I2C_IXR_RX_UNF \
0050 | CADENCE_I2C_IXR_TX_OVR \
0051 | CADENCE_I2C_IXR_RX_OVR \
0052 | CADENCE_I2C_IXR_NACK)
0053
0054 #define CADENCE_I2C_IRQ_USED \
0055 (CADENCE_I2C_IRQ_ERROR \
0056 | CADENCE_I2C_IXR_DATA \
0057 | CADENCE_I2C_IXR_COMP)
0058
0059 typedef struct {
0060 i2c_bus base;
0061 volatile cadence_i2c *regs;
0062 i2c_msg *msgs;
0063 uint32_t msg_todo;
0064 uint32_t current_msg_todo;
0065 uint8_t *current_msg_byte;
0066 uint32_t current_todo;
0067 uint32_t irqstatus;
0068 bool read;
0069 bool hold;
0070 rtems_id task_id;
0071 uint32_t input_clock;
0072 rtems_vector_number irq;
0073 } cadence_i2c_bus;
0074
0075 static void cadence_i2c_disable_interrupts(volatile cadence_i2c *regs)
0076 {
0077 regs->irqdisable = 0xffff;
0078 }
0079
0080 static void cadence_i2c_clear_irq_status(volatile cadence_i2c *regs)
0081 {
0082 regs->irqstatus = regs->irqstatus;
0083 }
0084
0085 static void cadence_i2c_reset(cadence_i2c_bus *bus)
0086 {
0087 volatile cadence_i2c *regs = bus->regs;
0088 uint32_t val;
0089
0090 cadence_i2c_disable_interrupts(regs);
0091
0092 val = regs->control;
0093 val &= ~CADENCE_I2C_CONTROL_HOLD;
0094 val |= CADENCE_I2C_CONTROL_ACKEN
0095 | CADENCE_I2C_CONTROL_MS
0096 | CADENCE_I2C_CONTROL_CLR_FIFO;
0097 regs->control = val;
0098
0099 regs->transfer_size = 0;
0100 regs->status = regs->status;
0101
0102 cadence_i2c_clear_irq_status(regs);
0103 }
0104
0105 static uint32_t cadence_i2c_set_address_size(
0106 const i2c_msg *msg,
0107 uint32_t control
0108 )
0109 {
0110 if ((msg->flags & I2C_M_TEN) == 0) {
0111 control |= CADENCE_I2C_CONTROL_NEA;
0112 } else {
0113 control &= ~CADENCE_I2C_CONTROL_NEA;
0114 }
0115
0116 return control;
0117 }
0118
0119 static void cadence_i2c_setup_read_transfer(
0120 cadence_i2c_bus *bus,
0121 volatile cadence_i2c *regs,
0122 uint32_t control
0123 )
0124 {
0125 control |= CADENCE_I2C_CONTROL_RW;
0126 regs->control = control;
0127
0128 if (bus->current_todo <= CADENCE_I2C_TRANSFER_SIZE_MAX) {
0129 regs->transfer_size = bus->current_todo;
0130 } else {
0131 regs->transfer_size = CADENCE_I2C_TRANSFER_SIZE_ONCE_MAX;
0132 }
0133 }
0134
0135 static void cadence_i2c_next_byte(cadence_i2c_bus *bus)
0136 {
0137 --bus->current_msg_todo;
0138 ++bus->current_msg_byte;
0139
0140 if (bus->current_msg_todo == 0) {
0141 i2c_msg *msg;
0142
0143 ++bus->msgs;
0144 --bus->msg_todo;
0145
0146 msg = &bus->msgs[0];
0147
0148 bus->current_msg_todo = msg->len;
0149 bus->current_msg_byte = msg->buf;
0150 }
0151 }
0152
0153 static void cadence_i2c_write_to_fifo(
0154 cadence_i2c_bus *bus,
0155 volatile cadence_i2c *regs
0156 )
0157 {
0158 uint32_t space_available;
0159 uint32_t todo_now;
0160 uint32_t i;
0161
0162 space_available = CADENCE_I2C_FIFO_DEPTH - regs->transfer_size;
0163
0164 if (bus->current_todo > space_available) {
0165 todo_now = space_available;
0166 } else {
0167 todo_now = bus->current_todo;
0168 }
0169
0170 bus->current_todo -= todo_now;
0171
0172 for (i = 0; i < todo_now; ++i) {
0173 regs->data = *bus->current_msg_byte;
0174
0175 cadence_i2c_next_byte(bus);
0176 }
0177 }
0178
0179 static void cadence_i2c_setup_write_transfer(
0180 cadence_i2c_bus *bus,
0181 volatile cadence_i2c *regs,
0182 uint32_t control
0183 )
0184 {
0185 control &= ~CADENCE_I2C_CONTROL_RW;
0186 regs->control = control;
0187
0188 cadence_i2c_write_to_fifo(bus, regs);
0189 }
0190
0191 static void cadence_i2c_setup_transfer(
0192 cadence_i2c_bus *bus,
0193 volatile cadence_i2c *regs
0194 )
0195 {
0196 const i2c_msg *msgs = bus->msgs;
0197 uint32_t msg_todo = bus->msg_todo;
0198 uint32_t i;
0199 uint32_t control;
0200
0201 bus->current_todo = msgs[0].len;
0202 for (i = 1; i < msg_todo && (msgs[i].flags & I2C_M_NOSTART) != 0; ++i) {
0203 bus->current_todo += msgs[i].len;
0204 }
0205
0206 regs = bus->regs;
0207
0208 control = regs->control;
0209 control |= CADENCE_I2C_CONTROL_CLR_FIFO;
0210
0211 bus->hold = i < msg_todo;
0212
0213 if (bus->hold || bus->current_todo > CADENCE_I2C_FIFO_DEPTH) {
0214 control |= CADENCE_I2C_CONTROL_HOLD;
0215 } else {
0216 control &= ~CADENCE_I2C_CONTROL_HOLD;
0217 }
0218
0219 control = cadence_i2c_set_address_size(msgs, control);
0220
0221 bus->read = (msgs->flags & I2C_M_RD) != 0;
0222 if (bus->read) {
0223 cadence_i2c_setup_read_transfer(bus, regs, control);
0224 } else {
0225 cadence_i2c_setup_write_transfer(bus, regs, control);
0226 }
0227
0228 cadence_i2c_clear_irq_status(regs);
0229
0230 regs->address = CADENCE_I2C_ADDRESS(msgs->addr);
0231 }
0232
0233 static void cadence_i2c_continue_read_transfer(
0234 cadence_i2c_bus *bus,
0235 volatile cadence_i2c *regs
0236 )
0237 {
0238 uint32_t i;
0239
0240 bus->current_todo -= CADENCE_I2C_DATA_IRQ_DEPTH;
0241
0242
0243
0244
0245
0246
0247
0248
0249 if (regs->transfer_size == 0) {
0250 if (bus->current_todo <= CADENCE_I2C_TRANSFER_SIZE_MAX) {
0251 regs->transfer_size = bus->current_todo;
0252 } else {
0253 regs->transfer_size = CADENCE_I2C_TRANSFER_SIZE_ONCE_MAX;
0254 }
0255 }
0256
0257 for (i = 0; i < CADENCE_I2C_DATA_IRQ_DEPTH; ++i) {
0258 *bus->current_msg_byte = (uint8_t) regs->data;
0259
0260 cadence_i2c_next_byte(bus);
0261 }
0262
0263 if (!bus->hold && bus->current_todo <= CADENCE_I2C_FIFO_DEPTH) {
0264 regs->control &= ~CADENCE_I2C_CONTROL_HOLD;
0265 }
0266 }
0267
0268 static void cadence_i2c_interrupt(void *arg)
0269 {
0270 cadence_i2c_bus *bus = arg;
0271 volatile cadence_i2c *regs = bus->regs;
0272 uint32_t irqstatus = regs->irqstatus;
0273 bool done = false;
0274
0275
0276 regs->irqstatus = irqstatus;
0277
0278 if ((irqstatus & (CADENCE_I2C_IXR_ARB_LOST | CADENCE_I2C_IXR_NACK)) != 0) {
0279 done = true;
0280 }
0281
0282 if (
0283 (irqstatus & CADENCE_I2C_IXR_DATA) != 0
0284 && bus->read
0285 && bus->current_todo >= CADENCE_I2C_DATA_IRQ_DEPTH
0286 ) {
0287 cadence_i2c_continue_read_transfer(bus, regs);
0288 }
0289
0290 if ((irqstatus & CADENCE_I2C_IXR_COMP) != 0) {
0291 if (bus->read) {
0292 uint32_t todo_now = bus->current_todo;
0293 uint32_t i;
0294
0295 for (i = 0; i < todo_now; ++i) {
0296 *bus->current_msg_byte = (uint8_t) regs->data;
0297
0298 cadence_i2c_next_byte(bus);
0299 }
0300
0301 bus->current_todo = 0;
0302
0303 done = true;
0304 } else {
0305 if (bus->current_todo > 0) {
0306 cadence_i2c_write_to_fifo(bus, regs);
0307 } else {
0308 done = true;
0309 }
0310
0311 if (!bus->hold && bus->current_todo == 0) {
0312 regs->control &= ~CADENCE_I2C_CONTROL_HOLD;
0313 }
0314 }
0315 }
0316
0317 if (done) {
0318 uint32_t err = irqstatus & CADENCE_I2C_IRQ_ERROR;
0319
0320 if (bus->msg_todo == 0 || err != 0) {
0321 rtems_status_code sc;
0322
0323 cadence_i2c_disable_interrupts(regs);
0324
0325 bus->irqstatus = err;
0326
0327 sc = rtems_event_transient_send(bus->task_id);
0328 _Assert(sc == RTEMS_SUCCESSFUL);
0329 (void) sc;
0330 } else {
0331 cadence_i2c_setup_transfer(bus, regs);
0332 }
0333 }
0334 }
0335
0336 static int cadence_i2c_transfer(
0337 i2c_bus *base,
0338 i2c_msg *msgs,
0339 uint32_t msg_count
0340 )
0341 {
0342 cadence_i2c_bus *bus = (cadence_i2c_bus *) base;
0343 volatile cadence_i2c *regs;
0344 rtems_status_code sc;
0345 uint32_t i;
0346
0347 _Assert(msg_count > 0);
0348
0349 for (i = 0; i < msg_count; ++i) {
0350
0351 if ((msgs[i].flags & I2C_M_RECV_LEN) != 0) {
0352 return -EINVAL;
0353 }
0354 }
0355
0356 bus->msgs = &msgs[0];
0357 bus->msg_todo = msg_count;
0358 bus->current_msg_todo = msgs[0].len;
0359 bus->current_msg_byte = msgs[0].buf;
0360 bus->task_id = rtems_task_self();
0361
0362 regs = bus->regs;
0363 cadence_i2c_setup_transfer(bus, regs);
0364 regs->irqenable = CADENCE_I2C_IRQ_USED;
0365
0366 sc = rtems_event_transient_receive(RTEMS_WAIT, bus->base.timeout);
0367 if (sc != RTEMS_SUCCESSFUL) {
0368 cadence_i2c_reset(bus);
0369 rtems_event_transient_clear();
0370
0371 return -ETIMEDOUT;
0372 }
0373
0374 return bus->irqstatus == 0 ? 0 : -EIO;
0375 }
0376
0377 static int cadence_i2c_set_clock(i2c_bus *base, unsigned long clock)
0378 {
0379 cadence_i2c_bus *bus = (cadence_i2c_bus *) base;
0380 volatile cadence_i2c *regs = bus->regs;
0381 uint32_t error = 0xffffffff;
0382 uint32_t best_div_a = CADENCE_I2C_DIV_A_MAX - 1;
0383 uint32_t best_div_b = CADENCE_I2C_DIV_B_MAX - 1;
0384 uint32_t div = bus->input_clock / (22 * clock);
0385 uint32_t div_a;
0386 uint32_t control;
0387
0388 if (div <= 0 || div > (CADENCE_I2C_DIV_A_MAX * CADENCE_I2C_DIV_B_MAX)) {
0389 return -EIO;
0390 }
0391
0392 for (div_a = 0; div_a < CADENCE_I2C_DIV_A_MAX; ++div_a) {
0393 uint32_t a = 22 * clock * (div_a + 1);
0394 uint32_t b = (bus->input_clock + a - 1) / a;
0395
0396 if (b > 0 && b <= CADENCE_I2C_DIV_B_MAX) {
0397 uint32_t actual_clock = bus->input_clock / (22 * (div_a + 1) * b);
0398 uint32_t e = clock < actual_clock ?
0399 actual_clock - clock : clock - actual_clock;
0400
0401
0402
0403
0404
0405
0406 if (e <= error && actual_clock <= clock) {
0407 error = e;
0408 best_div_a = div_a;
0409 best_div_b = b - 1;
0410 }
0411 }
0412 }
0413
0414 control = regs->control;
0415 control = CADENCE_I2C_CONTROL_DIV_A_SET(control, best_div_a);
0416 control = CADENCE_I2C_CONTROL_DIV_B_SET(control, best_div_b);
0417 regs->control = control;
0418
0419 return 0;
0420 }
0421
0422 static void cadence_i2c_destroy(i2c_bus *base)
0423 {
0424 cadence_i2c_bus *bus = (cadence_i2c_bus *) base;
0425 rtems_status_code sc;
0426
0427 sc = rtems_interrupt_handler_remove(bus->irq, cadence_i2c_interrupt, bus);
0428 _Assert(sc == RTEMS_SUCCESSFUL);
0429 (void) sc;
0430
0431 i2c_bus_destroy_and_free(&bus->base);
0432 }
0433
0434 int i2c_bus_register_cadence(
0435 const char *bus_path,
0436 uintptr_t register_base,
0437 uint32_t input_clock,
0438 rtems_vector_number irq
0439 )
0440 {
0441 cadence_i2c_bus *bus;
0442 rtems_status_code sc;
0443 int err;
0444
0445 bus = (cadence_i2c_bus *) i2c_bus_alloc_and_init(sizeof(*bus));
0446 if (bus == NULL) {
0447 return -1;
0448 }
0449
0450 bus->regs = (volatile cadence_i2c *) register_base;
0451 bus->input_clock = input_clock;
0452 bus->irq = irq;
0453
0454 cadence_i2c_reset(bus);
0455
0456 err = cadence_i2c_set_clock(&bus->base, I2C_BUS_CLOCK_DEFAULT);
0457 if (err != 0) {
0458 (*bus->base.destroy)(&bus->base);
0459
0460 rtems_set_errno_and_return_minus_one(-err);
0461 }
0462
0463 sc = rtems_interrupt_handler_install(
0464 irq,
0465 "Cadence I2C",
0466 RTEMS_INTERRUPT_UNIQUE,
0467 cadence_i2c_interrupt,
0468 bus
0469 );
0470 if (sc != RTEMS_SUCCESSFUL) {
0471 (*bus->base.destroy)(&bus->base);
0472
0473 rtems_set_errno_and_return_minus_one(EIO);
0474 }
0475
0476 bus->base.transfer = cadence_i2c_transfer;
0477 bus->base.set_clock = cadence_i2c_set_clock;
0478 bus->base.destroy = cadence_i2c_destroy;
0479
0480 return i2c_bus_register(&bus->base, bus_path);
0481 }