Back to home page

LXR

 
 

    


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

0001 /**
0002  * @file
0003  *
0004  * @ingroup arm_beagle
0005  *
0006  * @brief BeagleBoard SPI bus initialization and API Support.
0007  *
0008  * Based on bsps/m68k/gen68360/spi/m360_spi.c
0009  */
0010 
0011 /*
0012  * Copyright (c) 2018 Pierre-Louis Garnier <garnie_a@epita.fr>
0013  *
0014  * The license and distribution terms for this file may be
0015  * found in the file LICENSE in this distribution or at
0016  * http://www.rtems.org/license/LICENSE.
0017  */
0018 #include <bsp.h>
0019 #include <bsp/bbb-gpio.h>
0020 #include <bsp/spi.h>
0021 #include <errno.h>
0022 #include <rtems/bspIo.h>
0023 #include <rtems/error.h>
0024 #include <rtems/libi2c.h>
0025 #include <stdio.h>
0026 #include <stdlib.h>
0027 
0028 // #define DEBUG
0029 // #define TRACE
0030 
0031 #define EVENT_TXEMPTY     RTEMS_EVENT_0
0032 #define EVENT_RXFULL      RTEMS_EVENT_1
0033 
0034 static void SPI0ModuleClkConfig(void)
0035 {
0036   /* Writing to MODULEMODE field of AM335X_CM_PER_SPI0_CLKCTRL register. */
0037   REG( AM335X_CM_PER_ADDR + AM335X_CM_PER_SPI0_CLKCTRL ) |=
0038     AM335X_CM_PER_SPI0_CLKCTRL_MODULEMODE_ENABLE;
0039 
0040   /* Waiting for MODULEMODE field to reflect the written value. */
0041   while ( AM335X_CM_PER_SPI0_CLKCTRL_MODULEMODE_ENABLE !=
0042           ( REG( AM335X_CM_PER_ADDR + AM335X_CM_PER_SPI0_CLKCTRL ) &
0043             AM335X_CM_PER_SPI0_CLKCTRL_MODULEMODE ) )
0044     continue;
0045 
0046   /*
0047    * Waiting for IDLEST field in AM335X_CM_PER_SPI0_CLKCTRL
0048    * register to attain desired value.
0049    */
0050   while ( ( AM335X_CM_PER_CONTROL_CLKCTRL_IDLEST_FUNC <<
0051             AM335X_CM_PER_CONTROL_CLKCTRL_IDLEST_SHIFT ) !=
0052           ( REG( AM335X_CM_PER_ADDR + AM335X_CM_PER_SPI0_CLKCTRL ) &
0053             AM335X_CM_PER_CONTROL_CLKCTRL_IDLEST ) )
0054     continue;
0055 }
0056 
0057 static inline void am335x_spi_clear_irqstatus(uint32_t reg_base, uint32_t irqs)
0058 {
0059   REG(reg_base + AM335X_SPI_SYST) &= ~AM335X_SPI_SYST_SSB;
0060   REG(reg_base + AM335X_SPI_IRQSTATUS) = irqs;
0061 }
0062 
0063 static void am335x_spi0_pinmux(void)
0064 {
0065   REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_SCLK) =
0066     (BBB_RXACTIVE | BBB_SLEWCTRL | BBB_PU_EN);
0067 
0068   REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_D0) =
0069     (BBB_RXACTIVE | BBB_SLEWCTRL | BBB_PU_EN);
0070 
0071   REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_D1) =
0072     (BBB_RXACTIVE | BBB_SLEWCTRL | BBB_PU_EN);
0073 
0074   REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_CS0) =
0075     (BBB_RXACTIVE | BBB_PU_EN);
0076 }
0077 
0078 static void am335x_spi_reset(uint32_t reg_base)
0079 {
0080   int timeout = BBB_SPI_TIMEOUT;
0081 
0082   REG(reg_base + AM335X_SPI_SYSCONFIG) |= AM335X_SPI_SYSCONFIG_SOFTRESET;
0083 
0084   while ((REG(reg_base + AM335X_SPI_SYSSTATUS) & AM335X_SPI_SYSSTATUS_RESETDONE) == 0 && timeout--) {
0085     if (timeout <= 0) {
0086       puts("ERROR: Timeout in soft-reset\n");
0087 
0088       return;
0089     }
0090 
0091     udelay(1000);
0092   }
0093 }
0094 
0095 static void beagle_spi_irq_handler(void *arg)
0096 {
0097   const uint32_t handled_irqs = AM335X_SPI_IRQSTATUS_TX0_EMPTY | AM335X_SPI_IRQSTATUS_RX0_FULL;
0098 
0099   beagle_spi_softc_t *softc_ptr = arg;
0100 
0101   rtems_status_code sc = -1;
0102 
0103   uint32_t irq = 0;
0104   uint32_t events = 0;
0105 
0106   uint32_t tmp;
0107   while ((tmp = (REG(softc_ptr->regs_base + AM335X_SPI_IRQSTATUS)) & handled_irqs) != 0) {
0108     irq |= tmp;
0109     am335x_spi_clear_irqstatus(softc_ptr->regs_base, tmp);
0110   }
0111 
0112 #if defined(TRACE)
0113     printk("beagle_spi_irq_handler: AM335X_SPI_IRQSTATUS = 0x%04lx\r\n", irq);
0114 #endif
0115 
0116   if (irq & AM335X_SPI_IRQSTATUS_TX0_EMPTY) {
0117 #if defined(TRACE)
0118     printk("beagle_spi_irq_handler: sending event TXEMPTY to task_id = %ld\r\n", softc_ptr->task_id);
0119 #endif
0120 
0121     events |= EVENT_TXEMPTY;
0122   }
0123 
0124   if (irq & AM335X_SPI_IRQSTATUS_RX0_FULL) {
0125 #if defined(TRACE)
0126     printk("beagle_spi_irq_handler: sending event RXFULL to task_id = %ld\r\n", softc_ptr->task_id);
0127 #endif
0128 
0129     events |= EVENT_RXFULL;
0130   }
0131 
0132   sc = rtems_event_send(softc_ptr->task_id, events);
0133   _Assert(sc == RTEMS_SUCCESSFUL);
0134   (void)sc;
0135 }
0136 
0137 /* Initialize the driver
0138  *
0139  * Returns: o = ok or error code
0140  */
0141 rtems_status_code beagle_spi_init
0142 (
0143  rtems_libi2c_bus_t *bh                  /* bus specifier structure        */
0144 )
0145 {
0146   beagle_spi_softc_t *softc_ptr = &(((beagle_spi_desc_t *)(bh))->softc);
0147 
0148   rtems_status_code rc = RTEMS_SUCCESSFUL;
0149 
0150 #if defined(DEBUG)
0151   printk("beagle_spi_init called...\r\n");
0152 #endif
0153 
0154   SPI0ModuleClkConfig();
0155   am335x_spi0_pinmux();
0156   am335x_spi_reset(softc_ptr->regs_base);
0157 
0158   REG(softc_ptr->regs_base + AM335X_SPI_MODULCTRL) &= ~AM335X_SPI_MODULCTRL_PIN34;
0159   REG(softc_ptr->regs_base + AM335X_SPI_MODULCTRL) &= ~AM335X_SPI_MODULCTRL_MS; // Master mode
0160   REG(softc_ptr->regs_base + AM335X_SPI_MODULCTRL) |= AM335X_SPI_MODULCTRL_SINGLE; // Single channel
0161   REG(softc_ptr->regs_base + AM335X_SPI_MODULCTRL) &= ~AM335X_SPI_MODULCTRL_PIN34; // SPIEN is usedas a chip select
0162   // REG(softc_ptr->regs_base + AM335X_SPI_MODULCTRL) |= (1 << 3); // Test mode
0163 
0164   // REG(softc_ptr->regs_base + AM335X_SPI_SYST) |= AM335X_SPI_SYST_SPIEN_0; // Not sure about this
0165   // REG(softc_ptr->regs_base + AM335X_SPI_SYST) |= AM335X_SPI_SYST_SPIDATDIR0; // Input
0166   // REG(softc_ptr->regs_base + AM335X_SPI_SYST) &= ~AM335X_SPI_SYST_SPIDATDIR1; // Output
0167 
0168   REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_TRM_MASK;
0169   REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_DPE0;
0170   REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_DPE1;
0171   REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_IS;
0172 
0173   // REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_FFEW;
0174   // REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_FFER;
0175   REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_WL(8 - 1);
0176 
0177   REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_PHA;
0178   REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_POL;
0179 
0180   REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_EPOL;
0181   REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_CLKD(0x1);
0182 
0183 
0184   // Setup interrupt
0185   rc = rtems_interrupt_handler_install(
0186     softc_ptr->irq,
0187     NULL,
0188     RTEMS_INTERRUPT_UNIQUE,
0189     (rtems_interrupt_handler)beagle_spi_irq_handler,
0190     softc_ptr
0191   );
0192 
0193 #if defined(DEBUG)
0194   printk("beagle_spi_init done\r\n");
0195 #endif
0196 
0197   if (rc == RTEMS_SUCCESSFUL) {
0198     softc_ptr->initialized = TRUE;
0199   }
0200 
0201   return rc;
0202 }
0203 
0204 static int beagle_spi_read_write_bytes(
0205  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0206  unsigned char *rx_buf,                  /* buffer to store bytes          */
0207  unsigned char *tx_buf,                  /* buffer to send                 */
0208  int len                                 /* number of bytes to send        */
0209 )
0210 {
0211   beagle_spi_softc_t *softc_ptr = &(((beagle_spi_desc_t *)(bh))->softc);
0212 
0213   rtems_status_code sc;
0214   rtems_event_set received_events;
0215 
0216 #if defined(TRACE)
0217   printk("beagle_spi_read_write_bytes called...\r\n");
0218 #endif
0219 
0220   softc_ptr->task_id = rtems_task_self();
0221 
0222   // Enable IRQs
0223 
0224   if (rx_buf) {
0225     am335x_spi_clear_irqstatus(softc_ptr->regs_base, AM335X_SPI_IRQSTATUS_RX0_FULL);
0226     REG(softc_ptr->regs_base + AM335X_SPI_IRQENABLE) |= AM335X_SPI_IRQENABLE_RX0_FULL;
0227   }
0228 
0229   if (tx_buf) {
0230     am335x_spi_clear_irqstatus(softc_ptr->regs_base, AM335X_SPI_IRQSTATUS_TX0_EMPTY);
0231     REG(softc_ptr->regs_base + AM335X_SPI_IRQENABLE) |= AM335X_SPI_IRQENABLE_TX0_EMPTY;
0232   }
0233 
0234   // Enable Channel
0235   REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_FORCE;
0236   REG(softc_ptr->regs_base + AM335X_SPI_CH0CTRL) |= AM335X_SPI_CH0CTRL_EN;
0237 
0238   // Main loop
0239   for (int i = 0; i < len; i++) {
0240     received_events = 0;
0241 
0242     if (tx_buf) {
0243       // Wait for IRQ to wake us up (room in TX FIFO)
0244 #if defined(TRACE)
0245       printk("beagle_spi_read_write_bytes: waiting (task_id = %ld)\r\n", softc_ptr->task_id);
0246 #endif
0247 
0248       sc = rtems_event_receive(EVENT_TXEMPTY, RTEMS_WAIT, BBB_SPI_TIMEOUT, &received_events);
0249       if (sc != RTEMS_SUCCESSFUL) {
0250         printk("ERROR: beagle_spi_read_write_bytes timed out on tx byte number %d\n", i);
0251         return i > 0 ? i : -RTEMS_TIMEOUT;
0252       }
0253 
0254       _Assert(received_events == EVENT_TXEMPTY);
0255 
0256 #if defined(TRACE)
0257       printk("beagle_spi_read_write_bytes: sending byte: i = %d, tx_buf[i] = 0x%x\r\n", i, tx_buf[i]);
0258 #endif
0259 
0260       REG(softc_ptr->regs_base + AM335X_SPI_TX0) = tx_buf[i];
0261     }
0262 
0263     if (rx_buf) {
0264       // Wait for IRQ to wake us up (data in RX FIFO)
0265       if ((received_events & EVENT_RXFULL) == 0) {
0266         sc = rtems_event_receive(EVENT_RXFULL, RTEMS_WAIT, BBB_SPI_TIMEOUT, &received_events);
0267         if (sc != RTEMS_SUCCESSFUL) {
0268           printk("ERROR: beagle_spi_read_write_bytes timed out on rx byte number %d\n", i);
0269           return i > 0 ? i : -RTEMS_TIMEOUT;
0270         }
0271 
0272         _Assert(received_events == EVENT_RXFULL);
0273       }
0274 
0275       rx_buf[i] = REG(softc_ptr->regs_base + AM335X_SPI_RX0);
0276 
0277 #if defined(TRACE)
0278       printk("beagle_spi_read_write_bytes: received byte: i = %d, rx_buf[i] = 0x%x\r\n", i, rx_buf[i]);
0279 #endif
0280     }
0281   }
0282 
0283   // REG(softc_ptr->regs_base + AM335X_SPI_IRQENABLE) &= ~AM335X_SPI_IRQENABLE_RX0_FULL;
0284   // REG(softc_ptr->regs_base + AM335X_SPI_IRQENABLE) &= ~AM335X_SPI_IRQENABLE_TX0_EMPTY;
0285 
0286   REG(softc_ptr->regs_base + AM335X_SPI_CH0CTRL) &= ~AM335X_SPI_CH0CTRL_EN;
0287   REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_FORCE;
0288 
0289 #if defined(TRACE)
0290   printk("beagle_spi_read_write_bytes done\r\n");
0291 #endif
0292 
0293   return len;
0294 }
0295 
0296 /*
0297  * Receive some bytes from SPI device
0298  *
0299  * Returns: number of bytes received or (negative) error code
0300  */
0301 int beagle_spi_read_bytes
0302 (
0303  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0304  unsigned char *buf,                     /* buffer to store bytes          */
0305  int len                                 /* number of bytes to receive     */
0306 )
0307 {
0308   // FIXME
0309 #if defined(DEBUG)
0310   printk("beagle_spi_read_bytes called...\r\n");
0311 #endif
0312 
0313   int n = beagle_spi_read_write_bytes(bh, buf, NULL, len);
0314 
0315 #if defined(DEBUG)
0316   printk("beagle_spi_read_bytes done\r\n");
0317 #endif
0318 
0319   return n;
0320 }
0321 
0322 /*
0323  * Send some bytes to SPI device
0324  *
0325  * Returns: number of bytes sent or (negative) error code
0326  */
0327 int beagle_spi_write_bytes
0328 (
0329  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0330  unsigned char *buf,                     /* buffer to send                 */
0331  int len                                 /* number of bytes to send        */
0332 )
0333 {
0334 #if defined(DEBUG)
0335   printk("beagle_spi_write_bytes called...\r\n");
0336 #endif
0337 
0338   int n = beagle_spi_read_write_bytes(bh, NULL, buf, len);
0339 
0340 #if defined(DEBUG)
0341   printk("beagle_spi_write_bytes done\r\n");
0342 #endif
0343 
0344   return n;
0345 }
0346 
0347 /*
0348  * Perform selected ioctl function for SPI
0349  *
0350  * Returns: rtems_status_code
0351  */
0352 int beagle_spi_ioctl
0353 (
0354  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0355  int                 cmd,                /* ioctl command code             */
0356  void               *arg                 /* additional argument array      */
0357 )
0358 {
0359   int ret_val = -1;
0360 
0361 #if defined(DEBUG)
0362   printk("beagle_spi_ioctl called...\r\n");
0363 #endif
0364 
0365   switch(cmd) { // FIXME: other ioctls
0366   case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
0367 #if defined(TRACE)
0368     printk("cmd == RTEMS_LIBI2C_IOCTL_SET_TFRMODE\r\n");
0369 #endif
0370     // FIXME
0371     // ret_val =
0372     //   -m360_spi_set_tfr_mode(bh,
0373     //     (const rtems_libi2c_tfr_mode_t *)arg);
0374     break;
0375   case RTEMS_LIBI2C_IOCTL_READ_WRITE: {
0376 #if defined(TRACE)
0377     printk("cmd == RTEMS_LIBI2C_IOCTL_READ_WRITE\r\n");
0378 #endif
0379     const rtems_libi2c_read_write_t *cmd = (const rtems_libi2c_read_write_t *)arg;
0380 
0381     ret_val = beagle_spi_read_write_bytes(
0382       bh,
0383       (unsigned char *)cmd->rd_buf,
0384       (unsigned char *)cmd->wr_buf,
0385       cmd->byte_cnt
0386     );
0387     break;
0388   }
0389   default:
0390     ret_val = -RTEMS_NOT_DEFINED;
0391     break;
0392   }
0393 
0394 #if defined(DEBUG)
0395   printk("beagle_spi_ioctl done\r\n");
0396 #endif
0397 
0398   return ret_val;
0399 }
0400 
0401 /*=========================================================================*\
0402 | Board-specific adaptation functions                                       |
0403 \*=========================================================================*/
0404 
0405 /*
0406  * Address a slave device on the bus
0407  *
0408  * Returns: o = ok or error code
0409  */
0410 static rtems_status_code bsp_spi_sel_addr
0411 (
0412  rtems_libi2c_bus_t *bh,                 /* bus specifier structure        */
0413  uint32_t addr,                          /* address to send on bus         */
0414  int rw                                  /* 0=write,1=read                 */
0415 )
0416 {
0417   if (addr != 0)
0418     return RTEMS_NOT_IMPLEMENTED;
0419 
0420   return  RTEMS_SUCCESSFUL;
0421 }
0422 
0423 /*
0424  * Dummy function, SPI has no start condition
0425  *
0426  * Returns: o = ok or error code
0427  */
0428 static rtems_status_code bsp_spi_send_start_dummy
0429 (
0430  rtems_libi2c_bus_t *bh                  /* bus specifier structure        */
0431 )
0432 {
0433 #if defined(DEBUG)
0434   printk("bsp_spi_send_start_dummy OK\r\n");
0435 #endif
0436 
0437   return 0;
0438 }
0439 
0440 /*
0441  * Deselect SPI
0442  *
0443  * Returns: o = ok or error code
0444  */
0445 static rtems_status_code bsp_spi_send_stop
0446 (
0447  rtems_libi2c_bus_t *bh                  /* bus specifier structure        */
0448 )
0449 {
0450 #if defined(DEBUG)
0451   printk("bsp_spi_send_stop called... ");
0452 #endif
0453 
0454   // FIXME
0455 
0456 #if defined(DEBUG)
0457   printk("... exit OK\r\n");
0458 #endif
0459   return 0;
0460 }
0461 
0462 /*=========================================================================*\
0463 | list of handlers                                                          |
0464 \*=========================================================================*/
0465 
0466 rtems_libi2c_bus_ops_t bsp_spi_ops = {
0467   init:             beagle_spi_init,
0468   send_start:       bsp_spi_send_start_dummy,
0469   send_stop:        bsp_spi_send_stop,
0470   send_addr:        bsp_spi_sel_addr,
0471   read_bytes:       beagle_spi_read_bytes,
0472   write_bytes:      beagle_spi_write_bytes,
0473   ioctl:            beagle_spi_ioctl
0474 };
0475 
0476 static beagle_spi_desc_t bsp_spi_bus_desc = {
0477   {/* public fields */
0478     ops:    &bsp_spi_ops,
0479     size:   sizeof(bsp_spi_bus_desc)
0480   },
0481   { /* our private fields */
0482     initialized: FALSE,
0483   }
0484 };
0485 
0486 /*=========================================================================*\
0487 | initialization                                                            |
0488 \*=========================================================================*/
0489 
0490 /*
0491  * Register SPI bus and devices
0492  *
0493  * Returns: Bus number or error code
0494  */
0495 rtems_status_code bsp_register_spi
0496 (
0497   const char         *bus_path,
0498   uintptr_t           register_base,
0499   rtems_vector_number irq
0500 )
0501 {
0502   int ret_code;
0503   int spi_busno;
0504 
0505   beagle_spi_softc_t *softc_ptr = &bsp_spi_bus_desc.softc;
0506 
0507   if (softc_ptr->initialized) {
0508     printk("ERROR: Only one SPI bus at a time is supported\n");
0509     return -RTEMS_RESOURCE_IN_USE;
0510   }
0511 
0512   softc_ptr->regs_base = register_base;
0513   softc_ptr->irq = irq;
0514 
0515   /*
0516    * init I2C library (if not already done)
0517    */
0518   rtems_libi2c_initialize();
0519 
0520   /*
0521    * register SPI bus
0522    */
0523   ret_code = rtems_libi2c_register_bus(bus_path,
0524                        &(bsp_spi_bus_desc.bus_desc));
0525   if (ret_code < 0) {
0526     return -ret_code;
0527   }
0528   spi_busno = ret_code;
0529 
0530 #if IS_AM335X
0531   // TODO: register board devices
0532 #endif
0533 
0534   return spi_busno;
0535 }