File indexing completed on 2025-05-11 08:22:49
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 <bsp.h>
0029 #include <bsp/fdt.h>
0030 #include <libfdt.h>
0031 #include <arm/freescale/imx/imx_ccmvar.h>
0032 #include <arm/freescale/imx/imx_i2creg.h>
0033 #include <dev/i2c/i2c.h>
0034 #include <rtems/irq-extension.h>
0035
0036 #define IMX_I2C_TRANSMIT (IMX_I2C_I2CR_IEN | IMX_I2C_I2CR_IIEN \
0037 | IMX_I2C_I2CR_MSTA | IMX_I2C_I2CR_MTX)
0038
0039 #define IMX_I2C_RECEIVE (IMX_I2C_I2CR_IEN | IMX_I2C_I2CR_IIEN \
0040 | IMX_I2C_I2CR_MSTA)
0041
0042 typedef struct {
0043 i2c_bus base;
0044 volatile imx_i2c *regs;
0045 uint32_t msg_todo;
0046 const i2c_msg *msg;
0047 bool read;
0048 bool start;
0049 uint16_t restart;
0050 uint32_t chunk_total;
0051 uint32_t chunk_done;
0052 uint16_t buf_todo;
0053 uint8_t *buf;
0054 rtems_id task_id;
0055 int eno;
0056 rtems_vector_number irq;
0057 } imx_i2c_bus;
0058
0059 typedef struct {
0060 uint16_t divisor;
0061 uint8_t ifdr;
0062 } imx_i2c_clock_divisor;
0063
0064 static const imx_i2c_clock_divisor imx_i2c_clock_divisor_table[] = {
0065 { 0, 0x20 }, { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 },
0066 { 28, 0x23 }, { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 },
0067 { 40, 0x26 }, { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 },
0068 { 52, 0x05 }, { 56, 0x29 }, { 60, 0x06 }, { 64, 0x2a },
0069 { 72, 0x2b }, { 80, 0x2c }, { 88, 0x09 }, { 96, 0x2d },
0070 { 104, 0x0a }, { 112, 0x2e }, { 128, 0x2f }, { 144, 0x0c },
0071 { 160, 0x30 }, { 192, 0x31 }, { 224, 0x32 }, { 240, 0x0f },
0072 { 256, 0x33 }, { 288, 0x10 }, { 320, 0x34 }, { 384, 0x35 },
0073 { 448, 0x36 }, { 480, 0x13 }, { 512, 0x37 }, { 576, 0x14 },
0074 { 640, 0x38 }, { 768, 0x39 }, { 896, 0x3a }, { 960, 0x17 },
0075 { 1024, 0x3b }, { 1152, 0x18 }, { 1280, 0x3c }, { 1536, 0x3d },
0076 { 1792, 0x3e }, { 1920, 0x1b }, { 2048, 0x3f }, { 2304, 0x1c },
0077 { 2560, 0x1d }, { 3072, 0x1e }, { 3840, 0x1f }, { 0xffff, 0x1f }
0078 };
0079
0080 static void imx_i2c_stop(volatile imx_i2c *regs)
0081 {
0082 regs->i2cr = IMX_I2C_I2CR_IEN;
0083 regs->i2sr = 0;
0084 regs->i2sr;
0085 }
0086
0087 static void imx_i2c_trigger_receive(imx_i2c_bus *bus, volatile imx_i2c *regs)
0088 {
0089 uint16_t i2cr;
0090
0091 i2cr = IMX_I2C_RECEIVE;
0092
0093 if (bus->chunk_total == 1) {
0094 i2cr |= IMX_I2C_I2CR_TXAK;
0095 }
0096
0097 regs->i2cr = i2cr;
0098 regs->i2dr;
0099 }
0100
0101 static void imx_i2c_done(imx_i2c_bus *bus, int eno)
0102 {
0103
0104
0105
0106
0107 imx_i2c_stop(bus->regs);
0108
0109 bus->eno = eno;
0110 rtems_event_transient_send(bus->task_id);
0111 }
0112
0113 static const i2c_msg *imx_i2c_msg_inc(imx_i2c_bus *bus)
0114 {
0115 const i2c_msg *next;
0116
0117 next = bus->msg + 1;
0118 bus->msg = next;
0119 --bus->msg_todo;
0120 return next;
0121 }
0122
0123 static void imx_i2c_msg_inc_and_set_buf(imx_i2c_bus *bus)
0124 {
0125 const i2c_msg *next;
0126
0127 next = imx_i2c_msg_inc(bus);
0128 bus->buf_todo = next->len;
0129 bus->buf = next->buf;
0130 }
0131
0132 static void imx_i2c_buf_inc(imx_i2c_bus *bus)
0133 {
0134 ++bus->buf;
0135 --bus->buf_todo;
0136 ++bus->chunk_done;
0137 }
0138
0139 static void imx_i2c_buf_push(imx_i2c_bus *bus, uint8_t c)
0140 {
0141 while (true) {
0142 if (bus->buf_todo > 0) {
0143 bus->buf[0] = c;
0144 imx_i2c_buf_inc(bus);
0145 break;
0146 }
0147
0148 imx_i2c_msg_inc_and_set_buf(bus);
0149 }
0150 }
0151
0152 static uint8_t imx_i2c_buf_pop(imx_i2c_bus *bus)
0153 {
0154 while (true) {
0155 if (bus->buf_todo > 0) {
0156 uint8_t c;
0157
0158 c = bus->buf[0];
0159 imx_i2c_buf_inc(bus);
0160 return c;
0161 }
0162
0163 imx_i2c_msg_inc_and_set_buf(bus);
0164 }
0165 }
0166
0167 RTEMS_STATIC_ASSERT(I2C_M_RD == 1, imx_i2c_read_flag);
0168
0169 static void imx_i2c_setup_chunk(imx_i2c_bus *bus, volatile imx_i2c *regs)
0170 {
0171 while (true) {
0172 const i2c_msg *msg;
0173 int flags;
0174 int can_continue;
0175 uint32_t i;
0176
0177 if (bus->msg_todo == 0) {
0178 imx_i2c_done(bus, 0);
0179 break;
0180 }
0181
0182 msg = bus->msg;
0183 flags = msg->flags;
0184
0185 bus->read = (flags & I2C_M_RD) != 0;
0186 bus->start = (flags & I2C_M_NOSTART) == 0;
0187 bus->chunk_total = msg->len;
0188 bus->chunk_done = 0;
0189 bus->buf_todo = msg->len;
0190 bus->buf = msg->buf;
0191
0192 can_continue = (flags & I2C_M_RD) | I2C_M_NOSTART;
0193
0194 for (i = 1; i < bus->msg_todo; ++i) {
0195 if ((msg[i].flags & (I2C_M_RD | I2C_M_NOSTART)) != can_continue) {
0196 break;
0197 }
0198
0199 bus->chunk_total += msg[i].len;
0200 }
0201
0202 if (bus->start) {
0203 regs->i2cr = IMX_I2C_TRANSMIT | bus->restart;
0204 regs->i2dr = (uint8_t) ((msg->addr << 1) | (flags & I2C_M_RD));
0205 bus->restart = IMX_I2C_I2CR_RSTA;
0206 break;
0207 } else if (bus->chunk_total > 0) {
0208 if (bus->read) {
0209 imx_i2c_trigger_receive(bus, regs);
0210 } else {
0211 regs->i2cr = IMX_I2C_TRANSMIT;
0212 regs->i2dr = imx_i2c_buf_pop(bus);
0213 }
0214
0215 break;
0216 } else {
0217 ++bus->msg;
0218 --bus->msg_todo;
0219 }
0220 }
0221 }
0222
0223 static void imx_i2c_transfer_complete(
0224 imx_i2c_bus *bus,
0225 volatile imx_i2c *regs,
0226 uint16_t i2sr
0227 )
0228 {
0229 if (bus->start) {
0230 bus->start = false;
0231
0232 if ((i2sr & IMX_I2C_I2SR_RXAK) != 0) {
0233 imx_i2c_done(bus, EIO);
0234 return;
0235 }
0236
0237 if (bus->read) {
0238 imx_i2c_trigger_receive(bus, regs);
0239 return;
0240 }
0241 }
0242
0243 if (bus->chunk_done < bus->chunk_total) {
0244 if (bus->read) {
0245 if (bus->chunk_done + 2 == bus->chunk_total) {
0246
0247 regs->i2cr = IMX_I2C_RECEIVE | IMX_I2C_I2CR_TXAK;
0248 } else if (bus->chunk_done + 1 == bus->chunk_total) {
0249
0250 bus->restart = 0;
0251 regs->i2cr = (IMX_I2C_RECEIVE | IMX_I2C_I2CR_TXAK)
0252 & ~IMX_I2C_I2CR_MSTA;
0253 }
0254
0255 imx_i2c_buf_push(bus, (uint8_t) regs->i2dr);
0256
0257 if (bus->chunk_done == bus->chunk_total) {
0258 imx_i2c_msg_inc(bus);
0259 imx_i2c_setup_chunk(bus, regs);
0260 }
0261 } else {
0262 if (bus->chunk_done > 0 && (i2sr & IMX_I2C_I2SR_RXAK) != 0) {
0263 imx_i2c_done(bus, EIO);
0264 return;
0265 }
0266
0267 regs->i2dr = imx_i2c_buf_pop(bus);
0268 }
0269 } else {
0270 imx_i2c_msg_inc(bus);
0271 imx_i2c_setup_chunk(bus, regs);
0272 }
0273 }
0274
0275 static void imx_i2c_interrupt(void *arg)
0276 {
0277 imx_i2c_bus *bus;
0278 volatile imx_i2c *regs;
0279 uint16_t i2sr;
0280
0281 bus = arg;
0282 regs = bus->regs;
0283
0284 i2sr = regs->i2sr;
0285 regs->i2sr = 0;
0286
0287 if ((i2sr & (IMX_I2C_I2SR_IAL | IMX_I2C_I2SR_ICF)) == IMX_I2C_I2SR_ICF) {
0288 imx_i2c_transfer_complete(bus, regs, i2sr);
0289 } else {
0290 imx_i2c_done(bus, EIO);
0291 }
0292 }
0293
0294 static int imx_i2c_wait_for_not_busy(volatile imx_i2c *regs)
0295 {
0296 rtems_interval timeout;
0297 bool before;
0298
0299 if ((regs->i2sr & IMX_I2C_I2SR_IBB) == 0) {
0300 return 0;
0301 }
0302
0303 timeout = rtems_clock_tick_later(10);
0304
0305 do {
0306 before = rtems_clock_tick_before(timeout);
0307
0308 if ((regs->i2sr & IMX_I2C_I2SR_IBB) == 0) {
0309 return 0;
0310 }
0311 } while (before);
0312
0313 return ETIMEDOUT;
0314 }
0315
0316 static int imx_i2c_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t n)
0317 {
0318 imx_i2c_bus *bus;
0319 int supported_flags;
0320 uint32_t i;
0321 volatile imx_i2c *regs;
0322 int eno;
0323 rtems_status_code sc;
0324
0325 supported_flags = I2C_M_RD;
0326
0327 for (i = 0; i < n; ++i) {
0328 if ((msgs[i].flags & ~supported_flags) != 0) {
0329 return -EINVAL;
0330 }
0331
0332 supported_flags |= I2C_M_NOSTART;
0333 }
0334
0335 bus = (imx_i2c_bus *) base;
0336 regs = bus->regs;
0337
0338 eno = imx_i2c_wait_for_not_busy(regs);
0339 if (eno != 0) {
0340 return -eno;
0341 }
0342
0343 bus->msg_todo = n;
0344 bus->msg = &msgs[0];
0345 bus->restart = 0;
0346 bus->task_id = rtems_task_self();
0347 bus->eno = 0;
0348
0349 regs->i2sr = 0;
0350 imx_i2c_setup_chunk(bus, regs);
0351
0352 sc = rtems_event_transient_receive(RTEMS_WAIT, bus->base.timeout);
0353 if (sc != RTEMS_SUCCESSFUL) {
0354 imx_i2c_stop(bus->regs);
0355 rtems_event_transient_clear();
0356 return -ETIMEDOUT;
0357 }
0358
0359 return -bus->eno;
0360 }
0361
0362 static int imx_i2c_set_clock(i2c_bus *base, unsigned long clock)
0363 {
0364 imx_i2c_bus *bus;
0365 uint32_t ipg_clock;
0366 uint16_t div;
0367 size_t i;
0368 const imx_i2c_clock_divisor *clock_divisor;
0369
0370 bus = (imx_i2c_bus *) base;
0371 ipg_clock = imx_ccm_ipg_hz();
0372 div = (uint16_t) ((ipg_clock + clock - 1) / clock);
0373
0374 for (i = 0; i < RTEMS_ARRAY_SIZE(imx_i2c_clock_divisor_table); ++i) {
0375 clock_divisor = &imx_i2c_clock_divisor_table[i];
0376
0377 if (clock_divisor->divisor >= div) {
0378 break;
0379 }
0380 }
0381
0382 bus->regs->ifdr = clock_divisor->ifdr;
0383 return 0;
0384 }
0385
0386 static void imx_i2c_destroy(i2c_bus *base)
0387 {
0388 imx_i2c_bus *bus;
0389
0390 bus = (imx_i2c_bus *) base;
0391 rtems_interrupt_handler_remove(bus->irq, imx_i2c_interrupt, bus);
0392 i2c_bus_destroy_and_free(&bus->base);
0393 }
0394
0395 static int imx_i2c_init(imx_i2c_bus *bus)
0396 {
0397 rtems_status_code sc;
0398
0399 imx_i2c_set_clock(&bus->base, I2C_BUS_CLOCK_DEFAULT);
0400 bus->regs->i2cr = IMX_I2C_I2CR_IEN;
0401
0402 sc = rtems_interrupt_handler_install(
0403 bus->irq,
0404 "I2C",
0405 RTEMS_INTERRUPT_UNIQUE,
0406 imx_i2c_interrupt,
0407 bus
0408 );
0409 if (sc != RTEMS_SUCCESSFUL) {
0410 return EAGAIN;
0411 }
0412
0413 return 0;
0414 }
0415
0416 int i2c_bus_register_imx(const char *bus_path, const char *alias_or_path)
0417 {
0418 const void *fdt;
0419 const char *path;
0420 int node;
0421 imx_i2c_bus *bus;
0422 int eno;
0423
0424 fdt = bsp_fdt_get();
0425 path = fdt_get_alias(fdt, alias_or_path);
0426
0427 if (path == NULL) {
0428 path = alias_or_path;
0429 }
0430
0431 node = fdt_path_offset(fdt, path);
0432 if (node < 0) {
0433 rtems_set_errno_and_return_minus_one(ENXIO);
0434 }
0435
0436 bus = (imx_i2c_bus *) i2c_bus_alloc_and_init(sizeof(*bus));
0437 if (bus == NULL){
0438 return -1;
0439 }
0440
0441 bus->regs = imx_get_reg_of_node(fdt, node);
0442 bus->irq = imx_get_irq_of_node(fdt, node, 0);
0443
0444 eno = imx_i2c_init(bus);
0445 if (eno != 0) {
0446 (*bus->base.destroy)(&bus->base);
0447 rtems_set_errno_and_return_minus_one(eno);
0448 }
0449
0450 bus->base.transfer = imx_i2c_transfer;
0451 bus->base.set_clock = imx_i2c_set_clock;
0452 bus->base.destroy = imx_i2c_destroy;
0453
0454 return i2c_bus_register(&bus->base, bus_path);
0455 }