/*********************************************************************************
|
* 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 <guowenxue@gmail.com>
|
* ChangeLog: 1, Release initial version on "2019年08月19日 23时18分54秒"
|
*
|
********************************************************************************/
|
#include <stdio.h>
|
#include <errno.h>
|
#include <unistd.h>
|
#include <stdlib.h>
|
#include <string.h>
|
#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;
|
}
|