Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:03

0001 /**
0002  * @file
0003  *
0004  * @ingroup RTEMSBSPsARMLPC24XXI2C
0005  */
0006 
0007 /*
0008  * SPDX-License-Identifier: BSD-2-Clause
0009  *
0010  * Copyright (C) 2009, 2019 embedded brains GmbH & Co. KG
0011  *
0012  * Redistribution and use in source and binary forms, with or without
0013  * modification, are permitted provided that the following conditions
0014  * are met:
0015  * 1. Redistributions of source code must retain the above copyright
0016  *    notice, this list of conditions and the following disclaimer.
0017  * 2. Redistributions in binary form must reproduce the above copyright
0018  *    notice, this list of conditions and the following disclaimer in the
0019  *    documentation and/or other materials provided with the distribution.
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0025  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0026  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0027  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0030  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0031  * POSSIBILITY OF SUCH DAMAGE.
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       /* Bus error */
0188     case 0x20:
0189       /* Slave address plus write sent, NACK received */
0190     case 0x48:
0191       /* Slave address plus read sent, NACK received */
0192       regs->conset = LPC24XX_I2C_STO | LPC24XX_I2C_AA;
0193       regs->conclr = LPC24XX_I2C_SI;
0194       error = -EIO;
0195       break;
0196     case 0x08:
0197       /* Start sent */
0198     case 0x10:
0199       /* Repeated start sent */
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       /* Slave address plus write sent, ACK received */
0207     case 0x28:
0208       /* Data sent, ACK received */
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       /* Data sent, NACK received */
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       /* Slave address plus read sent, ACK received */
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       /* Data received, ACK returned */
0238     case 0x58:
0239       /* Data received, NACK returned */
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       /* Do nothing */
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   /* Start */
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 /* I2C-Bus Specification and User Manual, Table 10 */
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   /* Disable I2C module */
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   /* Disable I2C module */
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   /* Initialize I2C module */
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 }