Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:50

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (C) 2020 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #include <bsp.h>
0029 #include <bsp/fatal.h>
0030 #include <bsp/fdt.h>
0031 #include <bsp/irq.h>
0032 
0033 #include <chip.h>
0034 #include <dev/i2c/i2c.h>
0035 #include <fsl_clock.h>
0036 #include <fsl_lpi2c.h>
0037 #include <libfdt.h>
0038 
0039 #define LPI2C_MTDR_CMD_transmit                           LPI2C_MTDR_CMD(0)
0040 #define LPI2C_MTDR_CMD_receive                            LPI2C_MTDR_CMD(1)
0041 #define LPI2C_MTDR_CMD_stop                               LPI2C_MTDR_CMD(2)
0042 #define LPI2C_MTDR_CMD_receive_and_discard                LPI2C_MTDR_CMD(3)
0043 #define LPI2C_MTDR_CMD_start_and_transmit                 LPI2C_MTDR_CMD(4)
0044 #define LPI2C_MTDR_CMD_start_and_transmit_NACK            LPI2C_MTDR_CMD(5)
0045 #define LPI2C_MTDR_CMD_start_and_transmit_highspeed       LPI2C_MTDR_CMD(6)
0046 #define LPI2C_MTDR_CMD_start_and_transmit_highspeed_NACK  LPI2C_MTDR_CMD(7)
0047 
0048 #define LPI2C_INT_ERRORS_SERIOUS ( \
0049   LPI2C_MSR_FEF_MASK | LPI2C_MSR_ALF_MASK | LPI2C_MSR_PLTF_MASK )
0050 
0051 #define LPI2C_INT_ERROR_NO_ACK (LPI2C_MSR_NDF_MASK)
0052 
0053 #define LPI2C_INT_ERRORS (LPI2C_INT_ERRORS_SERIOUS | LPI2C_INT_ERROR_NO_ACK)
0054 
0055 #define LPI2C_INT_ADDRESSED (LPI2C_INT_ERRORS | LPI2C_MSR_TDF_MASK)
0056 
0057 #define LPI2C_INT_STOP_SENT (LPI2C_INT_ERRORS | LPI2C_MSR_SDF_MASK)
0058 
0059 #define LPI2C_INT_RECEIVED (LPI2C_INT_ERRORS | LPI2C_MSR_RDF_MASK)
0060 
0061 #define LPI2C_INT_TRANSMITTED (LPI2C_INT_ERRORS | LPI2C_MSR_TDF_MASK)
0062 
0063 struct imxrt_lpi2c_bus {
0064   i2c_bus base;
0065   volatile LPI2C_Type *regs;
0066   rtems_vector_number irq;
0067   uint32_t src_clock_hz;
0068   clock_ip_name_t clock_ip;
0069   unsigned long clock;
0070 
0071   rtems_binary_semaphore sem;
0072   int eno;
0073 
0074   uint32_t msg_todo;
0075   const i2c_msg *msg;
0076 
0077   /* Everything that is necessary for the current message */
0078   uint32_t chunk_todo;
0079   uint16_t buf_todo;
0080   uint8_t *buf;
0081   bool stop;
0082   bool read;
0083 };
0084 
0085 static void imxrt_lpi2c_sw_reset(volatile LPI2C_Type *regs)
0086 {
0087   regs->MCR = LPI2C_MCR_RST_MASK | LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
0088   regs->SCR = LPI2C_SCR_RST_MASK | LPI2C_SCR_RRF_MASK | LPI2C_SCR_RTF_MASK;
0089   regs->MCR = 0;
0090   regs->SCR = 0;
0091 }
0092 
0093 static int imxrt_lpi2c_set_clock(i2c_bus *base, unsigned long clock)
0094 {
0095   struct imxrt_lpi2c_bus *bus;
0096   volatile LPI2C_Type *regs;
0097 
0098   bus = (struct imxrt_lpi2c_bus *) base;
0099   regs = bus->regs;
0100 
0101   bus->clock = clock;
0102 
0103   /*
0104    * Maybe there is a more efficient way than used by that function. But
0105    * changing clock doesn't happen often. So it should be OK for now.
0106    */
0107   LPI2C_MasterSetBaudRate((LPI2C_Type *)regs, bus->src_clock_hz, clock);
0108 
0109   return 0;
0110 }
0111 
0112 static void imxrt_lpi2c_do_reinit(
0113   struct imxrt_lpi2c_bus *bus,
0114   volatile LPI2C_Type *regs
0115 )
0116 {
0117   regs->MIER = 0;
0118   imxrt_lpi2c_sw_reset(regs);
0119 
0120   regs->MCFGR2 = LPI2C_MCFGR2_FILTSDA(0) | LPI2C_MCFGR2_FILTSCL(0) |
0121     LPI2C_MCFGR2_BUSIDLE(0);
0122   regs->MCFGR3 = LPI2C_MCFGR3_PINLOW(0);
0123 
0124   regs->MFCR = LPI2C_MFCR_RXWATER(0) | LPI2C_MFCR_TXWATER(1);
0125 
0126   imxrt_lpi2c_set_clock(&bus->base, bus->clock);
0127 }
0128 
0129 static void imxrt_lpi2c_done(
0130   struct imxrt_lpi2c_bus *bus,
0131   volatile LPI2C_Type *regs
0132 )
0133 {
0134   regs->MIER = 0;
0135   regs->MCR &= ~LPI2C_MCR_MEN_MASK;
0136   rtems_binary_semaphore_post(&bus->sem);
0137 }
0138 
0139 static void imxrt_lpi2c_next_msg(
0140   struct imxrt_lpi2c_bus *bus,
0141   volatile LPI2C_Type *regs
0142 );
0143 
0144 static void imxrt_lpi2c_transmit_next(
0145   struct imxrt_lpi2c_bus *bus,
0146   volatile LPI2C_Type *regs
0147 )
0148 {
0149   if (bus->chunk_todo == 0) {
0150     /* Check whether a stop has to be send */
0151     if (bus->stop) {
0152       regs->MTDR = LPI2C_MTDR_CMD_stop;
0153       bus->stop = false;
0154       regs->MIER = LPI2C_INT_STOP_SENT;
0155     } else {
0156       imxrt_lpi2c_next_msg(bus, regs);
0157     }
0158   } else {
0159     if (bus->read) {
0160       uint16_t to_read;
0161       to_read = MIN(bus->chunk_todo, 256);
0162       bus->chunk_todo -= to_read;
0163 
0164       regs->MTDR = LPI2C_MTDR_CMD_receive | (to_read - 1);
0165       regs->MIER = LPI2C_INT_RECEIVED;
0166     } else {
0167       regs->MTDR = LPI2C_MTDR_CMD_transmit | *bus->buf;
0168       ++bus->buf;
0169       --bus->buf_todo;
0170       --bus->chunk_todo;
0171       regs->MIER = LPI2C_INT_TRANSMITTED;
0172     }
0173   }
0174 }
0175 
0176 static void imxrt_lpi2c_next_msg(
0177   struct imxrt_lpi2c_bus *bus,
0178   volatile LPI2C_Type *regs
0179 )
0180 {
0181   if (bus->msg_todo == 0) {
0182     imxrt_lpi2c_done(bus, regs);
0183   } else {
0184     const i2c_msg *msg;
0185     int flags;
0186     bool start;
0187     uint16_t addr;
0188 
0189     msg = bus->msg;
0190     flags = msg->flags;
0191 
0192     addr = msg->addr;
0193     start = (flags & I2C_M_NOSTART) == 0;
0194     bus->read = (flags & I2C_M_RD) != 0;
0195     bus->chunk_todo = msg->len;
0196     bus->buf_todo = msg->len;
0197     bus->buf = msg->buf;
0198     bus->stop = (flags & I2C_M_STOP) != 0 || bus->msg_todo <= 1;
0199 
0200     ++bus->msg;
0201     --bus->msg_todo;
0202 
0203     if (start) {
0204       uint32_t mtdr;
0205       mtdr = LPI2C_MTDR_CMD_start_and_transmit;
0206       mtdr |= addr << 1;
0207       if (bus->read) {
0208         mtdr |= 1;
0209       }
0210       regs->MTDR = mtdr;
0211       regs->MIER = LPI2C_INT_ADDRESSED;
0212     } else {
0213       imxrt_lpi2c_transmit_next(bus, regs);
0214     }
0215   }
0216 }
0217 
0218 static void imxrt_lpi2c_interrupt(void *arg)
0219 {
0220   struct imxrt_lpi2c_bus *bus;
0221   volatile LPI2C_Type *regs;
0222   uint32_t msr;
0223 
0224   bus = arg;
0225   regs = bus->regs;
0226 
0227   msr = regs->MSR;
0228   regs->MSR = msr;
0229 
0230   if ((msr & LPI2C_INT_ERROR_NO_ACK) != 0) {
0231     /* Just end the transmission */
0232     bus->eno = EIO;
0233     imxrt_lpi2c_done(bus, regs);
0234   } else if ((msr & LPI2C_INT_ERRORS_SERIOUS) != 0) {
0235     /* Some worse error occurred. Reset hardware. */
0236     bus->eno = EIO;
0237     imxrt_lpi2c_do_reinit(bus, regs);
0238     imxrt_lpi2c_done(bus, regs);
0239   } else {
0240     uint32_t mrdr;
0241     while (((mrdr = regs->MRDR) & LPI2C_MRDR_RXEMPTY_MASK) == 0) {
0242       if (bus->read && bus->buf_todo > 0) {
0243         *bus->buf = (mrdr & LPI2C_MRDR_DATA_MASK) >> LPI2C_MRDR_DATA_SHIFT;
0244         ++bus->buf;
0245         --bus->buf_todo;
0246       }
0247     }
0248 
0249     if (
0250       ((msr & LPI2C_MSR_TDF_MASK) != 0) &&
0251       (!bus->read || bus->chunk_todo > 0 || bus->buf_todo == 0)
0252     ) {
0253       imxrt_lpi2c_transmit_next(bus, regs);
0254     }
0255   }
0256 }
0257 
0258 static int imxrt_lpi2c_wait_for_not_busy(volatile LPI2C_Type *regs)
0259 {
0260   rtems_interval timeout;
0261   bool before;
0262 
0263   if ((regs->MSR & LPI2C_MSR_BBF_MASK) == 0) {
0264     return 0;
0265   }
0266 
0267   timeout = rtems_clock_tick_later_usec(5000);
0268 
0269   do {
0270     before = rtems_clock_tick_before(timeout);
0271 
0272     if ((regs->MSR & LPI2C_MSR_BBF_MASK) == 0) {
0273       return 0;
0274     }
0275   } while (before);
0276 
0277   return ETIMEDOUT;
0278 }
0279 
0280 static void imxrt_lpi2c_first_msg(
0281   struct imxrt_lpi2c_bus *bus,
0282   volatile LPI2C_Type *regs
0283 )
0284 {
0285   if ((regs->MCR & LPI2C_MCR_MEN_MASK) == 0) {
0286     regs->MCR |= LPI2C_MCR_MEN_MASK;
0287   }
0288 
0289   imxrt_lpi2c_next_msg(bus, regs);
0290 }
0291 
0292 static int imxrt_lpi2c_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t n)
0293 {
0294   struct imxrt_lpi2c_bus *bus;
0295   volatile LPI2C_Type *regs;
0296   int supported_flags;
0297   int eno;
0298   uint16_t i;
0299 
0300   bus = (struct imxrt_lpi2c_bus *) base;
0301   regs = bus->regs;
0302 
0303   supported_flags = I2C_M_RD | I2C_M_STOP;
0304 
0305   for (i = 0; i < n; ++i) {
0306     if ((msgs[i].flags & ~supported_flags) != 0) {
0307       return -EINVAL;
0308     }
0309 
0310     supported_flags |= I2C_M_NOSTART;
0311   }
0312 
0313   eno = imxrt_lpi2c_wait_for_not_busy(regs);
0314   if (eno != 0) {
0315     imxrt_lpi2c_do_reinit(bus, regs);
0316     return -eno;
0317   }
0318 
0319   bus->msg_todo = n;
0320   bus->msg = &msgs[0];
0321   bus->eno = 0;
0322 
0323   imxrt_lpi2c_first_msg(bus, regs);
0324 
0325   eno = rtems_binary_semaphore_wait_timed_ticks(&bus->sem, bus->base.timeout);
0326   if (eno != 0) {
0327     /* Timeout */
0328     imxrt_lpi2c_do_reinit(bus, regs);
0329     rtems_binary_semaphore_try_wait(&bus->sem);
0330     return -eno;
0331   }
0332 
0333   return -bus->eno;
0334 }
0335 
0336 static void imxrt_lpi2c_destroy(i2c_bus *base)
0337 {
0338   struct imxrt_lpi2c_bus *bus;
0339   volatile LPI2C_Type *regs;
0340 
0341   bus = (struct imxrt_lpi2c_bus *) base;
0342   regs = bus->regs;
0343   imxrt_lpi2c_sw_reset(regs);
0344   CLOCK_DisableClock(bus->clock_ip);
0345 
0346   rtems_interrupt_handler_remove(bus->irq, imxrt_lpi2c_interrupt, bus);
0347   i2c_bus_destroy_and_free(&bus->base);
0348 }
0349 
0350 static int imxrt_lpi2c_hw_init(struct imxrt_lpi2c_bus *bus)
0351 {
0352   rtems_status_code sc;
0353   volatile LPI2C_Type *regs;
0354 
0355   regs = bus->regs;
0356 
0357   CLOCK_EnableClock(bus->clock_ip);
0358 
0359   bus->clock = I2C_BUS_CLOCK_DEFAULT;
0360   imxrt_lpi2c_do_reinit(bus, regs);
0361 
0362   sc = rtems_interrupt_handler_install(
0363     bus->irq,
0364     "LPI2C",
0365     RTEMS_INTERRUPT_UNIQUE,
0366     imxrt_lpi2c_interrupt,
0367     bus
0368   );
0369   if (sc != RTEMS_SUCCESSFUL) {
0370     return EAGAIN;
0371   }
0372 
0373   return 0;
0374 }
0375 
0376 static uint32_t imxrt_lpi2c_get_src_freq(clock_ip_name_t clock_ip)
0377 {
0378   uint32_t freq;
0379 #if IMXRT_IS_MIMXRT10xx
0380   uint32_t mux;
0381   uint32_t divider;
0382 
0383   (void) clock_ip; /* Not necessary for i.MXRT1050 */
0384 
0385   mux = CLOCK_GetMux(kCLOCK_Lpi2cMux);
0386   divider = 1;
0387 
0388   switch (mux) {
0389   case 0: /* pll3_sw_clk */
0390     freq = CLOCK_GetFreq(kCLOCK_Usb1PllClk);
0391     divider = 8;
0392     break;
0393   case 1: /* OSC */
0394     freq = CLOCK_GetFreq(kCLOCK_OscClk);
0395     break;
0396   default:
0397     freq = 0;
0398   }
0399 
0400   divider *= CLOCK_GetDiv(kCLOCK_Lpi2cDiv) + 1;
0401   freq /= divider;
0402 #elif IMXRT_IS_MIMXRT11xx
0403   /*
0404    * FIXME: A future version of the mcux_sdk might provide a better method to
0405    * get the clock instead of this hack.
0406    */
0407   clock_root_t clock_root = clock_ip + kCLOCK_Root_Lpi2c1 - kCLOCK_Lpi2c1;
0408 
0409   freq = CLOCK_GetRootClockFreq(clock_root);
0410 #else
0411   #error Getting I2C frequency is not implemented for this chip.
0412 #endif
0413 
0414   return freq;
0415 }
0416 
0417 static clock_ip_name_t imxrt_lpi2c_clock_ip(volatile LPI2C_Type *regs)
0418 {
0419   LPI2C_Type *const base_addresses[] = LPI2C_BASE_PTRS;
0420   static const clock_ip_name_t lpi2c_clocks[] = LPI2C_CLOCKS;
0421   size_t i;
0422 
0423   for (i = 0; i < RTEMS_ARRAY_SIZE(base_addresses); ++i) {
0424     if (base_addresses[i] == regs) {
0425       return lpi2c_clocks[i];
0426     }
0427   }
0428 
0429   return kCLOCK_IpInvalid;
0430 }
0431 
0432 void imxrt_lpi2c_init(void)
0433 {
0434   const void *fdt;
0435   int node;
0436 
0437   fdt = bsp_fdt_get();
0438   node = -1;
0439 
0440   do {
0441     node = fdt_node_offset_by_compatible(fdt, node, "nxp,imxrt-lpi2c");
0442 
0443     if (node >= 0 && imxrt_fdt_node_is_enabled(fdt, node)) {
0444       struct imxrt_lpi2c_bus *bus;
0445       int eno;
0446       const char *bus_path;
0447 
0448       bus = (struct imxrt_lpi2c_bus*) i2c_bus_alloc_and_init(sizeof(*bus));
0449       if (bus == NULL) {
0450         bsp_fatal(IMXRT_FATAL_LPI2C_ALLOC_FAILED);
0451       }
0452 
0453       rtems_binary_semaphore_init(&bus->sem, "LPI2C");
0454 
0455       bus->regs = imx_get_reg_of_node(fdt, node);
0456       if (bus->regs == NULL) {
0457         (*bus->base.destroy)(&bus->base);
0458         bsp_fatal(IMXRT_FATAL_LPI2C_INVALID_FDT);
0459       }
0460 
0461       bus->irq = imx_get_irq_of_node(fdt, node, 0);
0462       if (bus->irq == BSP_INTERRUPT_VECTOR_INVALID) {
0463         (*bus->base.destroy)(&bus->base);
0464         bsp_fatal(IMXRT_FATAL_LPI2C_INVALID_FDT);
0465       }
0466 
0467       bus_path = fdt_getprop(fdt, node, "rtems,path", NULL);
0468       if (bus_path == NULL) {
0469         (*bus->base.destroy)(&bus->base);
0470         bsp_fatal(IMXRT_FATAL_LPI2C_INVALID_FDT);
0471       }
0472 
0473       bus->clock_ip = imxrt_lpi2c_clock_ip(bus->regs);
0474       bus->src_clock_hz = imxrt_lpi2c_get_src_freq(bus->clock_ip);
0475 
0476       eno = imxrt_lpi2c_hw_init(bus);
0477       if (eno != 0) {
0478         (*bus->base.destroy)(&bus->base);
0479         bsp_fatal(IMXRT_FATAL_LPI2C_HW_INIT_FAILED);
0480       }
0481 
0482       bus->base.transfer = imxrt_lpi2c_transfer;
0483       bus->base.set_clock = imxrt_lpi2c_set_clock;
0484       bus->base.destroy = imxrt_lpi2c_destroy;
0485 
0486       /*
0487        * Need at least three FIFO bytes:
0488        * 1. One to two data to transmit or receive.
0489        *    Two is necessary for long receives without NACK.
0490        * 2. A stop condition.
0491        */
0492       if ((1 << ((bus->regs->PARAM & LPI2C_PARAM_MTXFIFO_MASK) >>
0493           LPI2C_PARAM_MTXFIFO_SHIFT)) < 3) {
0494         bsp_fatal(IMXRT_FATAL_LPI2C_UNSUPPORTED_HARDWARE);
0495       }
0496 
0497       eno = i2c_bus_register(&bus->base, bus_path);
0498       if (eno != 0) {
0499         bsp_fatal(IMXRT_FATAL_LPI2C_REGISTER_FAILED);
0500       }
0501     }
0502   } while (node >= 0);
0503 }