File indexing completed on 2025-05-11 08:23:02
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/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
0074
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
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
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
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
0210
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
0243
0244
0245
0246
0247
0248
0249
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
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
0349
0350
0351
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
0367
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
0401
0402
0403
0404
0405
0406
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
0418
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
0459
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
0470
0471
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
0488
0489
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
0606
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;
0620
0621 mux = CLOCK_GetMux(kCLOCK_LpspiMux);
0622
0623 switch (mux) {
0624 case 0:
0625 freq = CLOCK_GetFreq(kCLOCK_Usb1PllPfd1Clk);
0626 break;
0627 case 1:
0628 freq = CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk);
0629 break;
0630 case 2:
0631 freq = CLOCK_GetFreq(kCLOCK_SysPllClk);
0632 break;
0633 case 3:
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
0645
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
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
0755 bsp_fatal(IMXRT_FATAL_LPSPI_INVALID_FDT);
0756 }
0757 if (fdt32_to_cpu(val[0]) == 0) {
0758
0759 bus->cs[i].is_gpio = false;
0760 ++val;
0761 } else {
0762
0763
0764
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
0774
0775
0776
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
0786 imx_gpio_set_output(&bus->cs[i].gpio, ~bus->cs[i].active);
0787 }
0788 }
0789
0790
0791
0792
0793
0794
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
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 }