/********************************************************************************* * Copyright: (C) 2019 LingYun IoT System Studio * All rights reserved. * * Filename: spidev.c * Description: This file is spidev user space API. * * Version: 1.0.0(2019年08月19日) * Author: Guo Wenxue * ChangeLog: 1, Release initial version on "2019年08月19日 23时18分54秒" * ********************************************************************************/ #include #include #include #include #include #include "spidev.h" int spi_init(spidev_t *spi, char *spidev, uint8_t bpw, uint32_t speed, uint32_t delay, uint32_t mode) { int rv = 0; if( !spi || !spidev ) { spi_dbg("Invalid input arguments\n"); return -1; } memset(spi, 0, sizeof(*spi)); strncpy(spi->devname, spidev, DEVNAME_LEN); spi->bits = bpw; spi->speed = speed*1000; /* speed unit is KHz */ spi->delay = delay; spi->mode = mode; spi->fd = open(spidev, O_RDWR); if( spi->fd < 0) { spi_dbg("Open SPI device '%s' failure: %s\n", spidev, strerror(errno)); rv = -2; goto cleanup; } /* set bits per word */ if( ioctl(spi->fd, SPI_IOC_WR_BITS_PER_WORD, &bpw) < 0 ) { spi_dbg("Set SPI '%s' bit per words to [%d] failure: %s\n", spidev, bpw, strerror(errno)); rv = -3; goto cleanup; } /* set bits per word */ if( ioctl(spi->fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi->speed) < 0 ) { spi_dbg("Set SPI '%s' speed to %dKHz failure: %s\n", spidev, speed, strerror(errno)); rv = -4; goto cleanup; } /* set spi mode */ if( ioctl(spi->fd, SPI_IOC_WR_MODE32, &mode) < 0 ) { spi_dbg("Set SPI '%s' mode to [0x%0x] failure: %s\n", spidev, mode, strerror(errno)); rv = -5; goto cleanup; } spi_dbg("Open SPI '%s' fd=%d\n", spi->devname, spi->fd); cleanup: if( rv < 0 ) { close(spi->fd); } return rv; } int spi_read(spidev_t *spi, char *buf, int size) { int rv = 0; void *dummy_buf; struct spi_ioc_transfer tr = { .rx_buf = (unsigned long)buf, .len = size, .delay_usecs = spi->delay, .speed_hz = spi->speed, .bits_per_word = spi->bits, }; if( !spi || !buf || size<=0 ) { spi_dbg("Invalid input arguments\n"); return -1; } if( ! (dummy_buf=malloc(tr.len)) ) { spi_dbg("spi_read malloc failure: %s\n", strerror(errno)); return -2; } tr.tx_buf = (unsigned long)dummy_buf; if ( spi->mode & (SPI_TX_QUAD|SPI_RX_QUAD) ) tr.tx_nbits = 4; if ( spi->mode & (SPI_TX_DUAL|SPI_RX_DUAL) ) tr.tx_nbits = 2; if (!(spi->mode & SPI_LOOP)) { if (spi->mode & (SPI_TX_QUAD|SPI_TX_DUAL)) tr.rx_buf = 0; else if (spi->mode & (SPI_RX_QUAD|SPI_RX_DUAL)) tr.tx_buf = 0; } if( ioctl(spi->fd, SPI_IOC_MESSAGE(1), &tr) < 0) { spi_dbg("spi_read SPI_IOC_MESSAGE failure: %s\n", strerror(errno)); rv = -3; goto cleanup; } cleanup: if( dummy_buf ) { free( dummy_buf ); } return rv; } int spi_write(spidev_t *spi, char *data, int nbytes) { int rv = 0; void *dummy_buf; struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)data, .len = nbytes, .delay_usecs = spi->delay, .speed_hz = spi->speed, .bits_per_word = spi->bits, }; if( !spi || !data || nbytes<= 0) { spi_dbg("Invalid input arguments\n"); return -1; } if( ! (dummy_buf=malloc(tr.len)) ) { spi_dbg("spi_read malloc failure: %s\n", strerror(errno)); return -1; } tr.rx_buf = (unsigned long)dummy_buf; if ( spi->mode & (SPI_TX_QUAD|SPI_RX_QUAD) ) tr.tx_nbits = 4; if ( spi->mode & (SPI_TX_DUAL|SPI_RX_DUAL) ) tr.tx_nbits = 2; if (!(spi->mode & SPI_LOOP)) { if (spi->mode & (SPI_TX_QUAD|SPI_TX_DUAL)) tr.rx_buf = 0; else if (spi->mode & (SPI_RX_QUAD|SPI_RX_DUAL)) tr.tx_buf = 0; } if( ioctl(spi->fd, SPI_IOC_MESSAGE(1), &tr) < 0) { spi_dbg("spi_read SPI_IOC_MESSAGE failure: %s\n", strerror(errno)); rv = -2; goto cleanup; } cleanup: if( dummy_buf ) { free( dummy_buf ); } return rv; } int spi_rdwr(spidev_t *spi, char *data, char *rbuf, int nbytes) { int rv = 0; struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)data, .rx_buf = (unsigned long)rbuf, .len = nbytes, .delay_usecs = spi->delay, .speed_hz = spi->speed, .bits_per_word = spi->bits, }; if( !spi || !data || nbytes<=0 ) { spi_dbg("Invalid input arguments\n"); return -1; } if ( spi->mode & (SPI_TX_QUAD|SPI_RX_QUAD) ) tr.tx_nbits = 4; if ( spi->mode & (SPI_TX_DUAL|SPI_RX_DUAL) ) tr.tx_nbits = 2; if (!(spi->mode & SPI_LOOP)) { if (spi->mode & (SPI_TX_QUAD|SPI_TX_DUAL)) tr.rx_buf = 0; else if (spi->mode & (SPI_RX_QUAD|SPI_RX_DUAL)) tr.tx_buf = 0; } if( ioctl(spi->fd, SPI_IOC_MESSAGE(1), &tr) < 0) { spi_dbg("spi_read SPI_IOC_MESSAGE failure: %s\n", strerror(errno)); rv = -3; } return rv; } int spi_term(spidev_t *spi) { if( !spi ) { spi_dbg("Invalid input arguments\n"); return -1; } if(spi->fd) { spi_dbg("close spi device '%s'\n", spi->devname); close(spi->fd); } memset(spi, 0, sizeof(*spi)); spi->fd = -1; }