Back to home page

LXR

 
 

    


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

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 #include <bsp/imx-gpio.h>
0033 
0034 #include <chip.h>
0035 #include <dev/spi/spi.h>
0036 #include <fsl_clock.h>
0037 #include <libfdt.h>
0038 #include <imxrt/lpspi.h>
0039 
0040 #if IMXRT_LPSPI_MAX_CS != 0 && IMXRT_LPSPI_MAX_CS < 4
0041 #error IMXRT_LPSPI_MAX_CS hast to be either 0 or at least 4.
0042 #endif
0043 
0044 struct imxrt_lpspi_bus {
0045   spi_bus base;
0046   volatile LPSPI_Type *regs;
0047   rtems_vector_number irq;
0048   uint32_t src_clock_hz;
0049   clock_ip_name_t clock_ip;
0050 
0051   rtems_binary_semaphore sem;
0052   bool cs_change_on_last_msg;
0053 
0054   uint32_t rx_msg_todo;
0055   const spi_ioc_transfer *rx_msg;
0056   size_t remaining_rx_size;
0057   uint8_t *rx_buf;
0058 
0059   uint32_t tx_msg_todo;
0060   const spi_ioc_transfer *tx_msg;
0061   size_t remaining_tx_size;
0062   const uint8_t *tx_buf;
0063 
0064   uint32_t fifo_size;
0065 
0066 #if IMXRT_LPSPI_MAX_CS != 0
0067   struct {
0068     bool is_gpio;
0069     struct imx_gpio_pin gpio;
0070     uint32_t active;
0071   } cs[IMXRT_LPSPI_MAX_CS];
0072   /*
0073    * dummy_cs is either <0 if no dummy exists or the index of the cs that is
0074    * used as dummy.
0075    */
0076   int dummy_cs;
0077 #endif
0078 };
0079 
0080 static const uint32_t word_size = 8;
0081 
0082 static unsigned div_round_up(unsigned divident, unsigned divisor)
0083 {
0084   return (divident + divisor - 1) / divisor;
0085 }
0086 
0087 static void imxrt_lpspi_find_clockdivs(
0088   struct imxrt_lpspi_bus *bus,
0089   uint32_t max_baud_hz,
0090   unsigned *sckdiv,
0091   unsigned *prescale
0092 )
0093 {
0094   const unsigned max_sckdif = LPSPI_CCR_SCKDIV_MASK >> LPSPI_CCR_SCKDIV_SHIFT;
0095   const unsigned max_prescale =
0096       LPSPI_TCR_PRESCALE_MASK >> LPSPI_TCR_PRESCALE_SHIFT;
0097 
0098   unsigned best_baud_hz;
0099   int best_sckdif;
0100   int best_prescale;
0101 
0102   int check_baud_hz;
0103   int check_sckdif;
0104   int check_prescale;
0105 
0106   /* Start with slowest possible */
0107   best_sckdif = max_sckdif;
0108   best_prescale = max_prescale;
0109   best_baud_hz = div_round_up(bus->src_clock_hz,
0110       (1 << best_prescale) * (best_sckdif + 2));
0111 
0112   for (check_prescale = 0;
0113       check_prescale <= max_prescale && best_baud_hz < max_baud_hz;
0114       ++check_prescale) {
0115 
0116     check_sckdif = div_round_up(bus->src_clock_hz,
0117         (1 << check_prescale) * max_baud_hz) - 2;
0118 
0119     if (check_sckdif > max_sckdif) {
0120       check_sckdif = max_sckdif;
0121     }
0122 
0123     check_baud_hz = div_round_up(bus->src_clock_hz,
0124         (1 << check_prescale) * (check_sckdif + 2));
0125 
0126     if (check_baud_hz <= max_baud_hz && check_baud_hz > best_baud_hz) {
0127       best_baud_hz = check_baud_hz;
0128       best_sckdif = check_sckdif;
0129       best_prescale = check_prescale;
0130     }
0131   }
0132 
0133   *sckdiv = best_sckdif;
0134   *prescale = best_prescale;
0135 }
0136 
0137 static void imxrt_lpspi_config(
0138   struct imxrt_lpspi_bus *bus,
0139   volatile LPSPI_Type *regs,
0140   const spi_ioc_transfer *msg
0141 )
0142 {
0143   uint32_t ccr_orig;
0144   uint32_t ccr;
0145   uint32_t tcr;
0146   unsigned sckdiv;
0147   unsigned prescale;
0148 
0149   ccr_orig = ccr = regs->CCR;
0150   tcr = 0;
0151 
0152   imxrt_lpspi_find_clockdivs(bus, msg->speed_hz, &sckdiv, &prescale);
0153 
0154   /* Currently just force half a clock after and before chip select. */
0155   ccr = LPSPI_CCR_SCKDIV(sckdiv) | LPSPI_CCR_SCKPCS(sckdiv) |
0156       LPSPI_CCR_PCSSCK(sckdiv) | LPSPI_CCR_DBT(sckdiv);
0157   tcr |= LPSPI_TCR_PRESCALE(prescale);
0158 
0159   if ((msg->mode & SPI_CPOL) != 0) {
0160     tcr |= LPSPI_TCR_CPOL_MASK;
0161   }
0162   if ((msg->mode & SPI_CPHA) != 0) {
0163     tcr |= LPSPI_TCR_CPHA_MASK;
0164   }
0165   if (msg->mode & SPI_LSB_FIRST) {
0166     tcr |= LPSPI_TCR_LSBF_MASK;
0167   }
0168 
0169 #if IMXRT_LPSPI_MAX_CS > 0
0170   if (bus->cs[msg->cs].is_gpio || (msg->mode & SPI_NO_CS) != 0) {
0171     tcr |= LPSPI_TCR_PCS(bus->dummy_cs);
0172   } else {
0173     tcr |= LPSPI_TCR_PCS(msg->cs);
0174   }
0175 #else
0176   tcr |= LPSPI_TCR_PCS(msg->cs);
0177 #endif
0178   tcr |= LPSPI_TCR_CONT_MASK;
0179   tcr |= LPSPI_TCR_FRAMESZ(word_size-1);
0180 
0181   if (ccr_orig != ccr) {
0182     regs->CR &= ~LPSPI_CR_MEN_MASK;
0183     regs->CCR = ccr;
0184     regs->CR |= LPSPI_CR_MEN_MASK;
0185   }
0186 
0187   if (bus->cs_change_on_last_msg) {
0188     /* No CONTC on first write. Otherwise upper 8 bits are not written. */
0189     regs->TCR = tcr;
0190   }
0191   regs->TCR = tcr | LPSPI_TCR_CONTC_MASK;
0192 
0193   bus->cs_change_on_last_msg = msg->cs_change;
0194 }
0195 
0196 static inline bool imxrt_lpspi_rx_fifo_not_empty(
0197   volatile LPSPI_Type *regs
0198 )
0199 {
0200   return ((regs->RSR & LPSPI_RSR_RXEMPTY_MASK) == 0);
0201 }
0202 
0203 static inline bool imxrt_lpspi_tx_fifo_not_full(
0204   struct imxrt_lpspi_bus *bus,
0205   volatile LPSPI_Type *regs
0206 )
0207 {
0208   /*
0209    * We might add two things to the FIFO: A TCR and data. Therefore leave one
0210    * extra space.
0211    */
0212   return ((regs->FSR & LPSPI_FSR_TXCOUNT_MASK) >> LPSPI_FSR_TXCOUNT_SHIFT) <
0213       bus->fifo_size - 2;
0214 }
0215 
0216 static void imxrt_lpspi_next_tx_msg(
0217   struct imxrt_lpspi_bus *bus,
0218   volatile LPSPI_Type *regs
0219 )
0220 {
0221   if (bus->tx_msg_todo > 0) {
0222     const spi_ioc_transfer *msg;
0223 
0224     msg = bus->tx_msg;
0225 
0226     imxrt_lpspi_config(bus, regs, msg);
0227     bus->remaining_tx_size = msg->len;
0228     bus->tx_buf = msg->tx_buf;
0229   }
0230 }
0231 
0232 static void imxrt_lpspi_fill_tx_fifo(
0233   struct imxrt_lpspi_bus *bus,
0234   volatile LPSPI_Type *regs
0235 )
0236 {
0237   while(imxrt_lpspi_tx_fifo_not_full(bus, regs)
0238       && (bus->tx_msg_todo > 0 || bus->remaining_tx_size > 0)) {
0239     if (bus->remaining_tx_size > 0) {
0240       if (bus->remaining_tx_size == 1 && bus->tx_msg->cs_change) {
0241         /*
0242          * Necessary for getting the last data out of the Rx FIFO. See "i.MX
0243          * RT1050 Processor Reference Manual Rev. 4" Chapter 47.3.2.2 "Receive
0244          * FIFO and Data Match":
0245          *
0246          * "During a continuous transfer, if the transmit FIFO is empty, then
0247          * the receive data is only written to the receive FIFO after the
0248          * transmit FIFO is written or after the Transmit Command Register (TCR)
0249          * is written to end the frame."
0250          */
0251         regs->TCR &= ~(LPSPI_TCR_CONT_MASK);
0252       }
0253 
0254       if (bus->tx_buf != NULL) {
0255         regs->TDR = bus->tx_buf[0];
0256         ++bus->tx_buf;
0257       } else {
0258         regs->TDR = 0;
0259       }
0260       --bus->remaining_tx_size;
0261     }
0262     if (bus->remaining_tx_size == 0) {
0263       --bus->tx_msg_todo;
0264       ++bus->tx_msg;
0265       imxrt_lpspi_next_tx_msg(bus, regs);
0266     }
0267   }
0268 }
0269 
0270 static void imxrt_lpspi_next_rx_msg(
0271   struct imxrt_lpspi_bus *bus,
0272   volatile LPSPI_Type *regs
0273 )
0274 {
0275   if (bus->rx_msg_todo > 0) {
0276     const spi_ioc_transfer *msg;
0277 
0278     msg = bus->rx_msg;
0279 
0280     bus->remaining_rx_size = msg->len;
0281     bus->rx_buf = msg->rx_buf;
0282   }
0283 }
0284 
0285 static void imxrt_lpspi_pull_data_from_rx_fifo(
0286   struct imxrt_lpspi_bus *bus,
0287   volatile LPSPI_Type *regs
0288 )
0289 {
0290   uint32_t data;
0291   while (imxrt_lpspi_rx_fifo_not_empty(regs)
0292       && (bus->rx_msg_todo > 0 || bus->remaining_rx_size > 0)) {
0293     if (bus->remaining_rx_size > 0) {
0294       data = regs->RDR;
0295       if (bus->rx_buf != NULL) {
0296         *bus->rx_buf = data;
0297         ++bus->rx_buf;
0298       }
0299       --bus->remaining_rx_size;
0300     }
0301     if (bus->remaining_rx_size == 0) {
0302       --bus->rx_msg_todo;
0303       ++bus->rx_msg;
0304       imxrt_lpspi_next_rx_msg(bus, regs);
0305     }
0306   }
0307 }
0308 
0309 static void imxrt_lpspi_interrupt(void *arg)
0310 {
0311   struct imxrt_lpspi_bus *bus;
0312   volatile LPSPI_Type *regs;
0313 
0314   bus = arg;
0315   regs = bus->regs;
0316 
0317   imxrt_lpspi_pull_data_from_rx_fifo(bus, regs);
0318   imxrt_lpspi_fill_tx_fifo(bus, regs);
0319 
0320   if (bus->tx_msg_todo > 0 || bus->remaining_tx_size > 0) {
0321     regs->IER = LPSPI_IER_TDIE_MASK;
0322   } else if (bus->rx_msg_todo > 0 || bus->remaining_rx_size > 0) {
0323     regs->IER = LPSPI_IER_RDIE_MASK;
0324   } else {
0325     regs->IER = 0;
0326     rtems_binary_semaphore_post(&bus->sem);
0327   }
0328 }
0329 
0330 static inline int imxrt_lpspi_settings_ok(
0331   struct imxrt_lpspi_bus *bus,
0332   const spi_ioc_transfer *msg,
0333   const spi_ioc_transfer *prev_msg
0334 )
0335 {
0336   /* most of this is currently just not implemented */
0337   if (msg->speed_hz > bus->base.max_speed_hz ||
0338       msg->delay_usecs != 0 ||
0339       (msg->mode & ~(SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST | SPI_NO_CS)) != 0 ||
0340       msg->bits_per_word != word_size) {
0341     return -EINVAL;
0342   }
0343 
0344 #if IMXRT_LPSPI_MAX_CS == 0
0345   if (msg->cs > 3 || (msg->mode & SPI_NO_CS) != 0) {
0346     return -EINVAL;
0347   }
0348 #else /* IMXRT_LPSPI_MAX_CS != 0 */
0349   /*
0350    * Chip select is a bit tricky. This depends on whether it's a native or a
0351    * GPIO chip select.
0352    */
0353   if (msg->cs > IMXRT_LPSPI_MAX_CS) {
0354     return -EINVAL;
0355   }
0356   if (!bus->cs[msg->cs].is_gpio && msg->cs > 3) {
0357     return -EINVAL;
0358   }
0359   if ((msg->mode & SPI_NO_CS) != 0 && bus->dummy_cs < 0) {
0360     return -EINVAL;
0361   }
0362 #endif
0363 
0364   if (prev_msg != NULL && !prev_msg->cs_change) {
0365     /*
0366      * A lot of settings have to be the same in this case because the upper 8
0367      * bit of TCR can't be changed if it is a continuous transfer.
0368      */
0369     if (prev_msg->cs != msg->cs ||
0370         prev_msg->speed_hz != msg->speed_hz ||
0371         prev_msg->mode != msg->mode) {
0372       return -EINVAL;
0373     }
0374   }
0375 
0376   return 0;
0377 }
0378 
0379 static int imxrt_lpspi_check_messages(
0380   struct imxrt_lpspi_bus *bus,
0381   const spi_ioc_transfer *msg,
0382   uint32_t size
0383 )
0384 {
0385   const spi_ioc_transfer *prev_msg = NULL;
0386 
0387   while(size > 0) {
0388     int rv;
0389     rv = imxrt_lpspi_settings_ok(bus, msg, prev_msg);
0390     if (rv != 0) {
0391       return rv;
0392     }
0393 
0394     prev_msg = msg;
0395     ++msg;
0396     --size;
0397   }
0398 
0399   /*
0400    * Check whether cs_change is set on last message. Can't work without it
0401    * because the last received data is only put into the FIFO if it is the end
0402    * of a transfer or if another TX byte is put into the FIFO.
0403    *
0404    * In theory, a GPIO CS wouldn't need that limitation. But handling it
0405    * different for the GPIO CS would add complexity. So keep it as a driver
0406    * limitation for now.
0407    */
0408   if (!prev_msg->cs_change) {
0409     return -EINVAL;
0410   }
0411 
0412   return 0;
0413 }
0414 
0415 #if IMXRT_LPSPI_MAX_CS > 0
0416 /*
0417  * Check how many of the messages can be processed in one go. At the moment it
0418  * is necessary to pause on CS changes when GPIO CS are used.
0419  */
0420 static int imxrt_lpspi_check_howmany(
0421   struct imxrt_lpspi_bus *bus,
0422   const spi_ioc_transfer *msgs,
0423   uint32_t max
0424 )
0425 {
0426   int i;
0427 
0428   if (max == 0) {
0429     return max;
0430   }
0431 
0432   for (i = 0; i < max - 1; ++i) {
0433     const spi_ioc_transfer *msg = &msgs[i];
0434     const spi_ioc_transfer *next_msg = &msgs[i+1];
0435 
0436     bool cs_is_gpio = bus->cs[msg->cs].is_gpio;
0437     bool no_cs = msg->mode & SPI_NO_CS;
0438     bool no_cs_next = next_msg->mode & SPI_NO_CS;
0439 
0440     if (cs_is_gpio && msg->cs_change) {
0441       break;
0442     }
0443 
0444     if (no_cs != no_cs_next) {
0445       break;
0446     }
0447 
0448     if (cs_is_gpio && (msg->cs != next_msg->cs)) {
0449       break;
0450     }
0451   }
0452 
0453   return i+1;
0454 }
0455 #endif
0456 
0457 /*
0458  * Transfer some messages. CS must not change between messages if GPIO CS are
0459  * used.
0460  */
0461 static void imxrt_lpspi_transfer_some(
0462   struct imxrt_lpspi_bus *bus,
0463   const spi_ioc_transfer *msgs,
0464   uint32_t n
0465 )
0466 {
0467 #if IMXRT_LPSPI_MAX_CS > 0
0468   /*
0469    * Software chip select. Due to the checks in the
0470    * imxrt_lpspi_check_messages, the CS can't change in the middle of a
0471    * transfer. So we can just use the one from the first message.
0472    */
0473   if ((msgs[0].mode & SPI_NO_CS) == 0 && bus->cs[msgs[0].cs].is_gpio) {
0474     imx_gpio_set_output(&bus->cs[msgs[0].cs].gpio, bus->cs[msgs[0].cs].active);
0475   }
0476 #endif
0477 
0478   bus->tx_msg_todo = n;
0479   bus->tx_msg = &msgs[0];
0480   bus->rx_msg_todo = n;
0481   bus->rx_msg = &msgs[0];
0482   bus->cs_change_on_last_msg = true;
0483 
0484   imxrt_lpspi_next_rx_msg(bus, bus->regs);
0485   imxrt_lpspi_next_tx_msg(bus, bus->regs);
0486   /*
0487    * Enable the transmit FIFO empty interrupt which will cause an interrupt
0488    * instantly because there is no data in the transmit FIFO. The interrupt
0489    * will then fill the FIFO. So nothing else to do here.
0490    */
0491   bus->regs->IER = LPSPI_IER_TDIE_MASK;
0492   rtems_binary_semaphore_wait(&bus->sem);
0493 
0494 #if IMXRT_LPSPI_MAX_CS > 0
0495   if ((msgs[0].mode & SPI_NO_CS) == 0 && bus->cs[msgs[0].cs].is_gpio) {
0496     imx_gpio_set_output(&bus->cs[msgs[0].cs].gpio, ~bus->cs[msgs[0].cs].active);
0497   }
0498 #endif
0499 }
0500 
0501 static int imxrt_lpspi_transfer(
0502   spi_bus *base,
0503   const spi_ioc_transfer *msgs,
0504   uint32_t n
0505 )
0506 {
0507   struct imxrt_lpspi_bus *bus;
0508   int rv;
0509 
0510   bus = (struct imxrt_lpspi_bus *) base;
0511 
0512   rv = imxrt_lpspi_check_messages(bus, msgs, n);
0513 
0514   if (rv == 0) {
0515 #if IMXRT_LPSPI_MAX_CS > 0
0516     while (n > 0) {
0517       uint32_t howmany;
0518 
0519       howmany = imxrt_lpspi_check_howmany(bus, msgs, n);
0520       imxrt_lpspi_transfer_some(bus, msgs, howmany);
0521       n -= howmany;
0522       msgs += howmany;
0523     };
0524 #else
0525     imxrt_lpspi_transfer_some(bus, msgs, n);
0526 #endif
0527   };
0528 
0529   return rv;
0530 }
0531 
0532 static void imxrt_lpspi_sw_reset(volatile LPSPI_Type *regs)
0533 {
0534   regs->CR = LPSPI_CR_RST_MASK | LPSPI_CR_RRF_MASK | LPSPI_CR_RTF_MASK;
0535   regs->CR = 0;
0536 }
0537 
0538 static void imxrt_lpspi_destroy(spi_bus *base)
0539 {
0540   struct imxrt_lpspi_bus *bus;
0541   volatile LPSPI_Type *regs;
0542 
0543   bus = (struct imxrt_lpspi_bus *) base;
0544   regs = bus->regs;
0545   imxrt_lpspi_sw_reset(regs);
0546 
0547   CLOCK_DisableClock(bus->clock_ip);
0548 
0549   rtems_interrupt_handler_remove(bus->irq, imxrt_lpspi_interrupt, bus);
0550   spi_bus_destroy_and_free(&bus->base);
0551 }
0552 
0553 static int imxrt_lpspi_hw_init(struct imxrt_lpspi_bus *bus)
0554 {
0555   rtems_status_code sc;
0556   volatile LPSPI_Type *regs;
0557 
0558   regs = bus->regs;
0559 
0560   CLOCK_EnableClock(bus->clock_ip);
0561 
0562   imxrt_lpspi_sw_reset(regs);
0563 
0564   regs->CFGR1 |= LPSPI_CFGR1_MASTER_MASK;
0565   regs->FCR = LPSPI_FCR_TXWATER(0) | LPSPI_FCR_RXWATER(0);
0566   regs->CR |= LPSPI_CR_MEN_MASK;
0567 
0568   bus->fifo_size = 1 << ((regs->PARAM & LPSPI_PARAM_TXFIFO_MASK) >>
0569       LPSPI_PARAM_TXFIFO_SHIFT);
0570 
0571   sc = rtems_interrupt_handler_install(
0572     bus->irq,
0573     "LPSPI",
0574     RTEMS_INTERRUPT_UNIQUE,
0575     imxrt_lpspi_interrupt,
0576     bus
0577   );
0578   if (sc != RTEMS_SUCCESSFUL) {
0579     return EAGAIN;
0580   }
0581 
0582   return 0;
0583 }
0584 
0585 static int imxrt_lpspi_setup(spi_bus *base)
0586 {
0587   struct imxrt_lpspi_bus *bus;
0588   int rv;
0589   spi_ioc_transfer msg = {
0590     .cs_change = base->cs_change,
0591     .cs = base->cs,
0592     .bits_per_word = base->bits_per_word,
0593     .mode = base->mode,
0594     .speed_hz = base->speed_hz,
0595     .delay_usecs = base->delay_usecs,
0596     .rx_buf = NULL,
0597     .tx_buf = NULL,
0598   };
0599 
0600   bus = (struct imxrt_lpspi_bus *) base;
0601 
0602   rv = imxrt_lpspi_settings_ok(bus, &msg, NULL);
0603 
0604   /*
0605    * Nothing to do besides checking.
0606    * Every transfer will later overwrite the settings anyway.
0607    */
0608 
0609   return rv;
0610 }
0611 
0612 static uint32_t imxrt_lpspi_get_src_freq(clock_ip_name_t clock_ip)
0613 {
0614   uint32_t freq;
0615 #if IMXRT_IS_MIMXRT10xx
0616   uint32_t mux;
0617   uint32_t divider;
0618 
0619   (void) clock_ip; /* Not necessary for i.MXRT1050 */
0620 
0621   mux = CLOCK_GetMux(kCLOCK_LpspiMux);
0622 
0623   switch (mux) {
0624   case 0: /* PLL3 PFD1 */
0625     freq = CLOCK_GetFreq(kCLOCK_Usb1PllPfd1Clk);
0626     break;
0627   case 1: /* PLL3 PFD0 */
0628     freq = CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk);
0629     break;
0630   case 2: /* PLL2 */
0631     freq = CLOCK_GetFreq(kCLOCK_SysPllClk);
0632     break;
0633   case 3: /* PLL2 PFD2 */
0634     freq = CLOCK_GetFreq(kCLOCK_SysPllPfd2Clk);
0635     break;
0636   default:
0637     freq = 0;
0638   }
0639 
0640   divider = CLOCK_GetDiv(kCLOCK_LpspiDiv) + 1;
0641   freq /= divider;
0642 #elif IMXRT_IS_MIMXRT11xx
0643   /*
0644    * FIXME: A future version of the mcux_sdk might provide a better method to
0645    * get the clock instead of this hack.
0646    */
0647   clock_root_t clock_root = clock_ip + kCLOCK_Root_Lpspi1 - kCLOCK_Lpspi1;
0648 
0649   freq = CLOCK_GetRootClockFreq(clock_root);
0650 #else
0651   #error Getting SPI frequency is not implemented for this chip.
0652 #endif
0653 
0654   return freq;
0655 }
0656 
0657 static clock_ip_name_t imxrt_lpspi_clock_ip(volatile LPSPI_Type *regs)
0658 {
0659   LPSPI_Type *const base_addresses[] = LPSPI_BASE_PTRS;
0660   static const clock_ip_name_t lpspi_clocks[] = LPSPI_CLOCKS;
0661   size_t i;
0662 
0663   for (i = 0; i < RTEMS_ARRAY_SIZE(base_addresses); ++i) {
0664     if (base_addresses[i] == regs) {
0665       return lpspi_clocks[i];
0666     }
0667   }
0668 
0669   return kCLOCK_IpInvalid;
0670 }
0671 
0672 static int imxrt_lpspi_ioctl(spi_bus *base, ioctl_command_t command, void *arg)
0673 {
0674   struct imxrt_lpspi_bus *bus;
0675   bus = (struct imxrt_lpspi_bus *) base;
0676   int err = 0;
0677 
0678   switch (command) {
0679     case IMXRT_LPSPI_GET_REGISTERS:
0680       *(volatile LPSPI_Type**)arg = bus->regs;
0681       break;
0682     default:
0683       err = -EINVAL;
0684       break;
0685   }
0686 
0687   return err;
0688 }
0689 
0690 void imxrt_lpspi_init(void)
0691 {
0692   const void *fdt;
0693   int node;
0694 
0695   fdt = bsp_fdt_get();
0696   node = -1;
0697 
0698   do {
0699     node = fdt_node_offset_by_compatible(fdt, node, "nxp,imxrt-lpspi");
0700 
0701     if (node >= 0 && imxrt_fdt_node_is_enabled(fdt, node)) {
0702       struct imxrt_lpspi_bus *bus;
0703       int eno;
0704       const char *bus_path;
0705 #if IMXRT_LPSPI_MAX_CS != 0
0706       const uint32_t *val;
0707 #endif
0708 
0709       bus = (struct imxrt_lpspi_bus*) spi_bus_alloc_and_init(sizeof(*bus));
0710       if (bus == NULL) {
0711         bsp_fatal(IMXRT_FATAL_LPSPI_ALLOC_FAILED);
0712       }
0713 
0714       rtems_binary_semaphore_init(&bus->sem, "LPSPI");
0715 
0716       bus->regs = imx_get_reg_of_node(fdt, node);
0717       if (bus->regs == NULL) {
0718         bsp_fatal(IMXRT_FATAL_LPSPI_INVALID_FDT);
0719       }
0720 
0721       bus->irq = imx_get_irq_of_node(fdt, node, 0);
0722       if (bus->irq == BSP_INTERRUPT_VECTOR_INVALID) {
0723         bsp_fatal(IMXRT_FATAL_LPSPI_INVALID_FDT);
0724       }
0725 
0726       bus_path = fdt_getprop(fdt, node, "rtems,path", NULL);
0727       if (bus_path == NULL) {
0728         bsp_fatal(IMXRT_FATAL_LPSPI_INVALID_FDT);
0729       }
0730 
0731 #if IMXRT_LPSPI_MAX_CS != 0
0732       bus->dummy_cs = -1;
0733       val = fdt_getprop(fdt, node, "num-cs", NULL);
0734       /* If num-cs is not set: Just assume we only have hardware CS pins */
0735       if (val != NULL) {
0736         uint32_t num_cs;
0737         size_t i;
0738         int len;
0739         const uint32_t *val_end;
0740 
0741         num_cs = fdt32_to_cpu(val[0]);
0742         if (num_cs > IMXRT_LPSPI_MAX_CS) {
0743           bsp_fatal(IMXRT_FATAL_LPSPI_INVALID_FDT);
0744         }
0745 
0746         val = fdt_getprop(fdt, node, "cs-gpios", &len);
0747         if (val == NULL) {
0748           bsp_fatal(IMXRT_FATAL_LPSPI_INVALID_FDT);
0749         }
0750         val_end = val + len;
0751 
0752         for (i = 0; i < num_cs; ++i) {
0753           if (val >= val_end) {
0754             /* Already reached the end. But still pins to process. */
0755             bsp_fatal(IMXRT_FATAL_LPSPI_INVALID_FDT);
0756           }
0757           if (fdt32_to_cpu(val[0]) == 0) {
0758             /* phandle == 0; this is a native CS */
0759             bus->cs[i].is_gpio = false;
0760             ++val;
0761           } else {
0762             /*
0763              * phandle is something. Assume an imx_gpio. Other GPIO controllers
0764              * are not supported.
0765              */
0766             rtems_status_code sc;
0767 
0768             if (bus->dummy_cs < 0) {
0769               bus->dummy_cs = i;
0770             }
0771             bus->cs[i].is_gpio = true;
0772             /*
0773              * According to Linux device tree documentation, the bit 0 of the
0774              * flag bitfield in the last cell is 0 for an active high and 1 for
0775              * an active low pin. Usually the defines GPIO_ACTIVE_HIGH and
0776              * GPIO_ACTIVE_LOW would be used for that. But we don't have them.
0777              */
0778             bus->cs[i].active = (~fdt32_to_cpu(val[2])) & 0x1;
0779             sc = imx_gpio_init_from_fdt_property_pointer(&bus->cs[i].gpio, val,
0780                 IMX_GPIO_MODE_OUTPUT, &val);
0781             if (sc != RTEMS_SUCCESSFUL || val > val_end) {
0782               bsp_fatal(IMXRT_FATAL_LPSPI_INVALID_FDT);
0783             }
0784 
0785             /* Set to idle state */
0786             imx_gpio_set_output(&bus->cs[i].gpio, ~bus->cs[i].active);
0787           }
0788         }
0789 
0790         /*
0791          * All pins are processed. Check dummy_cs. If it is still <0, no GPIO is
0792          * used. That's OK. But if it is set, at least one GPIO CS is set and in
0793          * this case one of the native CS pins has to be reserved for the
0794          * dummy_cs.
0795          */
0796         if (bus->dummy_cs > 3) {
0797           bsp_fatal(IMXRT_FATAL_LPSPI_INVALID_FDT);
0798         }
0799       }
0800 #endif
0801 
0802       bus->clock_ip = imxrt_lpspi_clock_ip(bus->regs);
0803       bus->src_clock_hz = imxrt_lpspi_get_src_freq(bus->clock_ip);
0804       /* Absolut maximum is 30MHz according to electrical characteristics */
0805       bus->base.max_speed_hz = MIN(bus->src_clock_hz / 2, 30000000);
0806       bus->base.delay_usecs = 0;
0807 
0808       eno = imxrt_lpspi_hw_init(bus);
0809       if (eno != 0) {
0810         bsp_fatal(IMXRT_FATAL_LPSPI_HW_INIT_FAILED);
0811       }
0812 
0813       bus->base.transfer = imxrt_lpspi_transfer;
0814       bus->base.destroy = imxrt_lpspi_destroy;
0815       bus->base.setup = imxrt_lpspi_setup;
0816       bus->base.ioctl = imxrt_lpspi_ioctl;
0817 
0818       eno = spi_bus_register(&bus->base, bus_path);
0819       if (eno != 0) {
0820         bsp_fatal(IMXRT_FATAL_LPSPI_REGISTER_FAILED);
0821       }
0822     }
0823   } while (node >= 0);
0824 }