File indexing completed on 2025-05-11 08:23:03
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
0029
0030
0031
0032
0033
0034 #include <bsp/i2c.h>
0035 #include <bsp.h>
0036 #include <bsp/io.h>
0037 #include <bsp/irq.h>
0038 #include <bsp/irq-generic.h>
0039
0040 #include <rtems/score/assert.h>
0041
0042 #include <dev/i2c/i2c.h>
0043
0044 RTEMS_STATIC_ASSERT(I2C_M_RD == 1, lpc24xx_i2c_read_flag);
0045
0046 typedef struct {
0047 i2c_bus base;
0048 volatile lpc24xx_i2c *regs;
0049 uint8_t *buf;
0050 const uint8_t *buf_end;
0051 size_t todo;
0052 const i2c_msg *msg;
0053 const i2c_msg *msg_end;
0054 int error;
0055 rtems_binary_semaphore sem;
0056 lpc24xx_module module;
0057 rtems_vector_number irq;
0058 } lpc24xx_i2c_bus;
0059
0060 typedef struct {
0061 volatile lpc24xx_i2c *regs;
0062 lpc24xx_module module;
0063 rtems_vector_number irq;
0064 } lpc24xx_i2c_config;
0065
0066 static const i2c_msg *lpc24xx_i2c_msg_inc(lpc24xx_i2c_bus *bus)
0067 {
0068 const i2c_msg *msg;
0069
0070 msg = bus->msg + 1;
0071 bus->msg = msg;
0072 return msg;
0073 }
0074
0075 static void lpc24xx_i2c_msg_inc_and_set_buf(lpc24xx_i2c_bus *bus)
0076 {
0077 const i2c_msg *msg;
0078
0079 msg = lpc24xx_i2c_msg_inc(bus);
0080 bus->buf = msg->buf;
0081 bus->buf_end = bus->buf + msg->len;
0082 }
0083
0084 static void lpc24xx_i2c_buf_inc(lpc24xx_i2c_bus *bus)
0085 {
0086 ++bus->buf;
0087 --bus->todo;
0088 }
0089
0090 static void lpc24xx_i2c_buf_push(lpc24xx_i2c_bus *bus, uint8_t c)
0091 {
0092 while (true) {
0093 if (bus->buf != bus->buf_end) {
0094 bus->buf[0] = c;
0095 lpc24xx_i2c_buf_inc(bus);
0096 break;
0097 }
0098
0099 lpc24xx_i2c_msg_inc_and_set_buf(bus);
0100 }
0101 }
0102
0103 static uint8_t lpc24xx_i2c_buf_pop(lpc24xx_i2c_bus *bus)
0104 {
0105 while (true) {
0106 if (bus->buf != bus->buf_end) {
0107 uint8_t c;
0108
0109 c = bus->buf[0];
0110 lpc24xx_i2c_buf_inc(bus);
0111 return c;
0112 }
0113
0114 lpc24xx_i2c_msg_inc_and_set_buf(bus);
0115 }
0116 }
0117
0118 static void lpc24xx_i2c_setup_msg(lpc24xx_i2c_bus *bus, const i2c_msg *msg)
0119 {
0120 int can_continue;
0121 size_t todo;
0122
0123 bus->msg = msg;
0124 bus->buf = msg->buf;
0125 todo = msg->len;
0126 bus->buf_end = bus->buf + todo;
0127
0128 can_continue = (msg->flags & I2C_M_RD) | I2C_M_NOSTART;
0129 ++msg;
0130
0131 while (msg != bus->msg_end) {
0132 if ((msg->flags & (I2C_M_RD | I2C_M_NOSTART)) != can_continue) {
0133 break;
0134 }
0135
0136 todo += msg->len;
0137 ++msg;
0138 }
0139
0140 bus->todo = todo;
0141 }
0142
0143 static int lpc24xx_i2c_next_msg(
0144 lpc24xx_i2c_bus *bus,
0145 volatile lpc24xx_i2c *regs
0146 )
0147 {
0148 const i2c_msg *msg;
0149 int error;
0150
0151 msg = bus->msg + 1;
0152 error = 1;
0153
0154 if (msg != bus->msg_end) {
0155 lpc24xx_i2c_setup_msg(bus, msg);
0156
0157 if ((msg->flags & I2C_M_NOSTART) == 0) {
0158 regs->conset = LPC24XX_I2C_STA;
0159 regs->conclr = LPC24XX_I2C_SI;
0160 } else {
0161 regs->conset = LPC24XX_I2C_STO;
0162 regs->conclr = LPC24XX_I2C_SI;
0163 error = -EINVAL;
0164 }
0165 } else {
0166 regs->conset = LPC24XX_I2C_STO;
0167 regs->conclr = LPC24XX_I2C_SI;
0168 error = 0;
0169 }
0170
0171 return error;
0172 }
0173
0174 static void lpc24xx_i2c_interrupt(void *arg)
0175 {
0176 lpc24xx_i2c_bus *bus;
0177 volatile lpc24xx_i2c *regs;
0178 const i2c_msg *msg;
0179 int error;
0180
0181 bus = arg;
0182 regs = bus->regs;
0183 error = 1;
0184
0185 switch (regs->stat) {
0186 case 0x00:
0187
0188 case 0x20:
0189
0190 case 0x48:
0191
0192 regs->conset = LPC24XX_I2C_STO | LPC24XX_I2C_AA;
0193 regs->conclr = LPC24XX_I2C_SI;
0194 error = -EIO;
0195 break;
0196 case 0x08:
0197
0198 case 0x10:
0199
0200 msg = bus->msg;
0201 regs->dat = (uint8_t) ((msg->addr << 1) | (msg->flags & I2C_M_RD));
0202 regs->conset = LPC24XX_I2C_AA;
0203 regs->conclr = LPC24XX_I2C_STA | LPC24XX_I2C_SI;
0204 break;
0205 case 0x18:
0206
0207 case 0x28:
0208
0209 if (bus->todo > 0) {
0210 regs->dat = lpc24xx_i2c_buf_pop(bus);
0211 regs->conset = LPC24XX_I2C_AA;
0212 regs->conclr = LPC24XX_I2C_SI;
0213 } else {
0214 error = lpc24xx_i2c_next_msg(bus, regs);
0215 }
0216 break;
0217 case 0x30:
0218
0219 if (bus->todo == 0) {
0220 error = lpc24xx_i2c_next_msg(bus, regs);
0221 } else {
0222 regs->conset = LPC24XX_I2C_STO;
0223 regs->conclr = LPC24XX_I2C_SI;
0224 error = -EIO;
0225 }
0226 break;
0227 case 0x40:
0228
0229 if (bus->todo > 1) {
0230 regs->conset = LPC24XX_I2C_AA;
0231 regs->conclr = LPC24XX_I2C_SI;
0232 } else {
0233 regs->conclr = LPC24XX_I2C_SI | LPC24XX_I2C_AA;
0234 }
0235 break;
0236 case 0x50:
0237
0238 case 0x58:
0239
0240 lpc24xx_i2c_buf_push(bus, regs->dat);
0241
0242 if (bus->todo > 1) {
0243 regs->conset = LPC24XX_I2C_AA;
0244 regs->conclr = LPC24XX_I2C_SI;
0245 } else if (bus->todo == 1) {
0246 regs->conclr = LPC24XX_I2C_SI | LPC24XX_I2C_AA;
0247 } else {
0248 error = lpc24xx_i2c_next_msg(bus, regs);
0249 }
0250 break;
0251 case 0xF8:
0252
0253 break;
0254 default:
0255 error = -EIO;
0256 break;
0257 }
0258
0259 if (error <= 0) {
0260 bus->error = error;
0261 bsp_interrupt_vector_disable(bus->irq);
0262 rtems_binary_semaphore_post(&bus->sem);
0263 }
0264 }
0265
0266 static int
0267 lpc24xx_i2c_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t msg_count)
0268 {
0269 lpc24xx_i2c_bus *bus;
0270 volatile lpc24xx_i2c *regs;
0271 uint16_t supported;
0272 uint32_t i;
0273 int eno;
0274
0275 if (msg_count == 0){
0276 return 0;
0277 }
0278
0279 supported = I2C_M_RD;
0280
0281 for (i = 0; i < msg_count; ++i) {
0282 if ((msgs[i].flags & ~supported) != 0) {
0283 return -EINVAL;
0284 }
0285
0286 supported |= I2C_M_NOSTART;
0287 }
0288
0289 bus = (lpc24xx_i2c_bus *) base;
0290 bus->msg_end = msgs + msg_count;
0291 lpc24xx_i2c_setup_msg(bus, msgs);
0292
0293 regs = bus->regs;
0294
0295
0296 regs->conset = LPC24XX_I2C_STA;
0297
0298 bsp_interrupt_vector_enable(bus->irq);
0299 eno = rtems_binary_semaphore_wait_timed_ticks(
0300 &bus->sem,
0301 bus->base.timeout
0302 );
0303 if (eno != 0) {
0304 regs->conclr = LPC24XX_I2C_EN;
0305 regs->conset = LPC24XX_I2C_EN;
0306 rtems_binary_semaphore_try_wait(&bus->sem);
0307 return -ETIMEDOUT;
0308 }
0309
0310 return bus->error;
0311 }
0312
0313
0314 static const uint16_t lpc24xx_i2c_t_low_high[3][2] = {
0315 { 4700, 4000 },
0316 { 1300, 600 },
0317 { 500, 260 }
0318 };
0319
0320 static uint32_t lpc24xx_i2c_cycle_count(uint32_t scl, uint32_t x, uint32_t t)
0321 {
0322 scl = (scl * x + t - 1) / t;
0323
0324 if (scl <= 4) {
0325 scl = 4;
0326 } else if (scl >= 0xffff) {
0327 scl = 0xffff;
0328 }
0329
0330 return scl;
0331 }
0332
0333 static int lpc24xx_i2c_set_clock(i2c_bus *base, unsigned long clock)
0334 {
0335 lpc24xx_i2c_bus *bus;
0336 volatile lpc24xx_i2c *regs;
0337 size_t i;
0338 uint32_t low;
0339 uint32_t high;
0340 uint32_t t;
0341 uint32_t scl;
0342
0343 if (clock <= 100000) {
0344 i = 0;
0345 } else if (clock <= 400000) {
0346 i = 1;
0347 } else {
0348 i = 2;
0349 }
0350
0351 low = lpc24xx_i2c_t_low_high[i][0];
0352 high = lpc24xx_i2c_t_low_high[i][1];
0353 t = low + high;
0354 scl = (LPC24XX_PCLK + clock - 1) / clock;
0355
0356 bus = (lpc24xx_i2c_bus *) base;
0357 regs = bus->regs;
0358
0359 regs->scll = lpc24xx_i2c_cycle_count(scl, low, t);
0360 regs->sclh = lpc24xx_i2c_cycle_count(scl, high, t);
0361
0362 return 0;
0363 }
0364
0365 static void
0366 lpc24xx_i2c_destroy(i2c_bus *base)
0367 {
0368 lpc24xx_i2c_bus *bus;
0369 rtems_status_code sc;
0370
0371 bus = (lpc24xx_i2c_bus *) base;
0372
0373 sc = rtems_interrupt_handler_remove(bus->irq, lpc24xx_i2c_interrupt, bus);
0374 _Assert(sc == RTEMS_SUCCESSFUL);
0375 (void) sc;
0376
0377
0378 bus->regs->conclr = LPC24XX_I2C_EN;
0379
0380 sc = lpc24xx_module_disable(bus->module);
0381 _Assert(sc == RTEMS_SUCCESSFUL);
0382 (void) sc;
0383
0384 rtems_binary_semaphore_destroy(&bus->sem);
0385 i2c_bus_destroy_and_free(&bus->base);
0386 }
0387
0388 static int lpc24xx_i2c_init(lpc24xx_i2c_bus *bus)
0389 {
0390 rtems_status_code sc;
0391
0392 sc = lpc24xx_module_enable(bus->module, LPC24XX_MODULE_PCLK_DEFAULT);
0393 _Assert(sc == RTEMS_SUCCESSFUL);
0394 (void) sc;
0395
0396
0397 bus->regs->conclr = LPC24XX_I2C_EN;
0398
0399 sc = rtems_interrupt_handler_install(
0400 bus->irq,
0401 "I2C",
0402 RTEMS_INTERRUPT_UNIQUE,
0403 lpc24xx_i2c_interrupt,
0404 bus
0405 );
0406 if (sc != RTEMS_SUCCESSFUL) {
0407 return EAGAIN;
0408 }
0409
0410 rtems_binary_semaphore_init(&bus->sem, "I2C");
0411
0412 lpc24xx_i2c_set_clock(&bus->base, I2C_BUS_CLOCK_DEFAULT);
0413
0414
0415 bus->regs->conset = LPC24XX_I2C_EN;
0416
0417 return 0;
0418 }
0419
0420 static int i2c_bus_register_lpc24xx(
0421 const char *bus_path,
0422 const lpc24xx_i2c_config *config
0423 )
0424 {
0425 lpc24xx_i2c_bus *bus;
0426 int eno;
0427
0428 bus = (lpc24xx_i2c_bus *) i2c_bus_alloc_and_init(sizeof(*bus));
0429 if (bus == NULL){
0430 return -1;
0431 }
0432
0433 bus->regs = config->regs;
0434 bus->module = config->module;
0435 bus->irq = config->irq;
0436
0437 eno = lpc24xx_i2c_init(bus);
0438 if (eno != 0) {
0439 (*bus->base.destroy)(&bus->base);
0440 rtems_set_errno_and_return_minus_one(eno);
0441 }
0442
0443 bus->base.transfer = lpc24xx_i2c_transfer;
0444 bus->base.set_clock = lpc24xx_i2c_set_clock;
0445 bus->base.destroy = lpc24xx_i2c_destroy;
0446
0447 return i2c_bus_register(&bus->base, bus_path);
0448 }
0449
0450 int lpc24xx_register_i2c_0(void)
0451 {
0452 static const lpc24xx_i2c_config config = {
0453 .regs = (volatile lpc24xx_i2c *) I2C0_BASE_ADDR,
0454 .module = LPC24XX_MODULE_I2C_0,
0455 .irq = LPC24XX_IRQ_I2C_0
0456 };
0457
0458 return i2c_bus_register_lpc24xx(
0459 LPC24XX_I2C_0_BUS_PATH,
0460 &config
0461 );
0462 }
0463
0464 int lpc24xx_register_i2c_1(void)
0465 {
0466 static const lpc24xx_i2c_config config = {
0467 .regs = (volatile lpc24xx_i2c *) I2C1_BASE_ADDR,
0468 .module = LPC24XX_MODULE_I2C_1,
0469 .irq = LPC24XX_IRQ_I2C_1
0470 };
0471
0472 return i2c_bus_register_lpc24xx(
0473 LPC24XX_I2C_2_BUS_PATH,
0474 &config
0475 );
0476 }
0477
0478 int lpc24xx_register_i2c_2(void)
0479 {
0480 static const lpc24xx_i2c_config config = {
0481 .regs = (volatile lpc24xx_i2c *) I2C2_BASE_ADDR,
0482 .module = LPC24XX_MODULE_I2C_2,
0483 .irq = LPC24XX_IRQ_I2C_2
0484 };
0485
0486 return i2c_bus_register_lpc24xx(
0487 LPC24XX_I2C_2_BUS_PATH,
0488 &config
0489 );
0490 }