add AT91 GPIO AND spi library
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2019 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: at91_sysGpio.c |
| | | * Description: This file si GPIO API operatore on /sys/class/gpio/xxx |
| | | * |
| | | * Version: 1.0.0(2019年08月26日) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2019年08月26日 22时28分19秒" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include <stdio.h> |
| | | #include <unistd.h> |
| | | #include <sys/types.h> |
| | | #include <sys/stat.h> |
| | | #include <fcntl.h> |
| | | #include <string.h> |
| | | #include <errno.h> |
| | | |
| | | #include "at91_sysGpio.h" |
| | | |
| | | |
| | | /* export $port in /sys/class/gpio/export */ |
| | | int gpio_export(const char *port) |
| | | { |
| | | char fpath[SYSFILE_LEN]; |
| | | FILE *fp; |
| | | int pin; |
| | | |
| | | if(!port) |
| | | { |
| | | gpio_print("invalid input arguments\n"); |
| | | return -1; |
| | | } |
| | | |
| | | snprintf(fpath, SYSFILE_LEN, "%s/%s", SYSGPIO_PATH, port); |
| | | |
| | | /* GPIO port already export */ |
| | | if( !access(fpath, F_OK) ) |
| | | { |
| | | gpio_print("%s already export\n", port); |
| | | return 0; |
| | | } |
| | | |
| | | if( !(fp=fopen(SYSGPIO_EXPORT_PATH, "w")) ) |
| | | { |
| | | gpio_print("open '%s' failure: %s\n", SYSGPIO_EXPORT_PATH, strerror(errno)); |
| | | return -2; |
| | | } |
| | | |
| | | pin = at91_port2pin(port); |
| | | fprintf(fp, "%d", pin); |
| | | |
| | | fclose(fp); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | /* unexport $port in /sys/class/gpio/unexport */ |
| | | int gpio_unexport(const char *port) |
| | | { |
| | | char fpath[SYSFILE_LEN]; |
| | | FILE *fp; |
| | | int pin; |
| | | |
| | | if(!port) |
| | | { |
| | | gpio_print("invalid input arguments\n"); |
| | | return -1; |
| | | } |
| | | |
| | | snprintf(fpath, SYSFILE_LEN, "%s/%s", SYSGPIO_PATH, port); |
| | | |
| | | /* GPIO port not export */ |
| | | if( access(fpath, F_OK) ) |
| | | { |
| | | gpio_print("%s not export\n", port); |
| | | return 0; |
| | | } |
| | | |
| | | if( !(fp=fopen(SYSGPIO_UNEXPORT_PATH, "w")) ) |
| | | { |
| | | gpio_print("open '%s' failure: %s\n", SYSGPIO_EXPORT_PATH, strerror(errno)); |
| | | return -2; |
| | | } |
| | | |
| | | pin = at91_port2pin(port); |
| | | fprintf(fp, "%d", pin); |
| | | |
| | | fclose(fp); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | /* configure $port direction as $mode */ |
| | | int gpio_config(const char *port, const char *mode) |
| | | { |
| | | char fpath[SYSFILE_LEN]; |
| | | FILE *fp; |
| | | int size; |
| | | |
| | | if(!port) |
| | | { |
| | | gpio_print("invalid input arguments\n"); |
| | | return 0; |
| | | } |
| | | |
| | | snprintf(fpath, SYSFILE_LEN, "%s/%s", SYSGPIO_PATH, port); |
| | | |
| | | if( access(fpath, F_OK) ) /* GPIO port not export */ |
| | | { |
| | | if( gpio_export(port) < 0 ) |
| | | return -1; |
| | | } |
| | | |
| | | size = SYSFILE_LEN-strlen(fpath); |
| | | strncat(fpath, "/direction", size); |
| | | if( !(fp=fopen(fpath, "w")) ) |
| | | { |
| | | gpio_print("open '%s' failure: %s\n", fpath, strerror(errno)); |
| | | return -1; |
| | | } |
| | | |
| | | fputs(mode, fp); |
| | | |
| | | fclose(fp); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | |
| | | /* write $value into GPIO $port */ |
| | | int gpio_write(const char *port, const char *value) |
| | | { |
| | | char fpath[SYSFILE_LEN]; |
| | | FILE *fp; |
| | | int size; |
| | | |
| | | if(!port) |
| | | { |
| | | gpio_print("invalid input arguments\n"); |
| | | return 0; |
| | | } |
| | | |
| | | snprintf(fpath, SYSFILE_LEN, "%s/%s", SYSGPIO_PATH, port); |
| | | |
| | | if( access(fpath, F_OK) ) /* GPIO port not export */ |
| | | { |
| | | if( gpio_export(port) < 0 ) |
| | | return -1; |
| | | } |
| | | |
| | | size = SYSFILE_LEN-strlen(fpath); |
| | | strncat(fpath, "/value", size); |
| | | if( !(fp=fopen(fpath, "w")) ) |
| | | { |
| | | gpio_print("open '%s' failure: %s\n", fpath, strerror(errno)); |
| | | return -1; |
| | | } |
| | | |
| | | fputs(value, fp); |
| | | |
| | | fclose(fp); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | /* read gpio value from $port */ |
| | | int gpio_read(const char *port) |
| | | { |
| | | char fpath[SYSFILE_LEN]; |
| | | FILE *fp; |
| | | int size; |
| | | char v_str[32]; |
| | | |
| | | if(!port) |
| | | { |
| | | gpio_print("invalid input arguments\n"); |
| | | return 0; |
| | | } |
| | | |
| | | snprintf(fpath, SYSFILE_LEN, "%s/%s", SYSGPIO_PATH, port); |
| | | |
| | | if( access(fpath, F_OK) ) /* GPIO port not export */ |
| | | { |
| | | return -1; |
| | | } |
| | | |
| | | size = SYSFILE_LEN-strlen(fpath); |
| | | strncat(fpath, "/value", size); |
| | | if( !(fp=fopen(fpath, "r")) ) |
| | | { |
| | | gpio_print("open '%s' failure: %s\n", fpath, strerror(errno)); |
| | | return -1; |
| | | } |
| | | |
| | | memset(v_str, 0, sizeof(v_str)); |
| | | fgets(v_str, sizeof(v_str), fp); |
| | | |
| | | fclose(fp); |
| | | |
| | | return atoi(v_str); |
| | | } |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2019 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: at91_sysGpio.h |
| | | * Description: This file si GPIO API operatore on /sys/class/gpio/xxx |
| | | * |
| | | * Version: 1.0.0(2019年08月26日) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2019年08月26日 22时28分19秒" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #ifndef _AT91_SYSGPIO_H_ |
| | | #define _AT91_SYSGPIO_H_ |
| | | |
| | | #include "at91_sysGpioDef.h" |
| | | |
| | | #define SYSFILE_LEN 64 |
| | | |
| | | #define SYSGPIO_PATH "/sys/class/gpio/" |
| | | |
| | | #define SYSGPIO_EXPORT_PATH SYSGPIO_PATH"export" |
| | | #define SYSGPIO_UNEXPORT_PATH SYSGPIO_PATH"unexport" |
| | | |
| | | //#define GPIO_DEBUG_PRINT |
| | | |
| | | #ifdef GPIO_DEBUG_PRINT |
| | | #define gpio_print(format,args...) printf(format, ##args) |
| | | #else |
| | | #define gpio_print(format,args...) do{} while(0); |
| | | #endif |
| | | |
| | | |
| | | /* export $port in /sys/class/gpio/export */ |
| | | extern int gpio_export(const char *port); |
| | | |
| | | |
| | | /* unexport $port in /sys/class/gpio/unexport */ |
| | | extern int gpio_unexport(const char *port); |
| | | |
| | | |
| | | #define M_IN "in" /* set GPIO as input mode */ |
| | | #define M_OUT "out" /* set GPIO as output mode */ |
| | | #define M_HIGH "high" /* set GPIO as output mode and value be high<1> */ |
| | | #define M_LOW "low" /* set GPIO as output mode and value be low<0> */ |
| | | /* configure $port direction as $mode */ |
| | | extern int gpio_config(const char *port, const char *mode); |
| | | |
| | | |
| | | #define V_HIGH "1" |
| | | #define V_LOW "0" |
| | | /* write $value into GPIO $port */ |
| | | extern int gpio_write(const char *port, const char *value); |
| | | |
| | | |
| | | /* read gpio value from $port */ |
| | | extern int gpio_read(const char *port); |
| | | |
| | | #endif /* ----- #ifndef _AT91_SYSGPIO_H_ ----- */ |
| | | |
| | | |
New file |
| | |
| | | /******************************************************************************** |
| | | * Copyright: (C) 2019 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: at91_sysGpioDef.h |
| | | * Description: This head file |
| | | * |
| | | * Version: 1.0.0(2019年08月26日) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2019年08月26日 21时46分02秒" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #ifndef _AT91_SYSGPIODEF_H_ |
| | | #define _AT91_SYSGPIODEF_H_ |
| | | |
| | | #include <ctype.h> |
| | | #include <stdlib.h> |
| | | |
| | | #define PA(x) "pioA"#x |
| | | #define PB(x) "pioB"#x |
| | | #define PC(x) "pioC"#x |
| | | #define PD(x) "pioD"#x |
| | | #define PE(x) "pioE"#x |
| | | |
| | | /* SAMA5D44 devided all GPIOs into 5 groups(PA,PB,PC,PD,PE), and each group control 32 Pins |
| | | * |
| | | * This macro used convert PAx,PBx...,PEx to Pin number: 0~158 |
| | | * s should be: PA0-PA31, PB0-PB31, PC0-PC31, PD0-PD31, PE0-PE30(158) |
| | | */ |
| | | #define at91_port2pin(p) ((tolower(p[3])-'a')*32 + atoi(p+4) ) |
| | | |
| | | |
| | | /*+-----------------------------------------------------+ |
| | | *| GPIO PortA: PA0~PA31 defined as "pioA0"-"pioA31" | |
| | | *+-----------------------------------------------------+*/ |
| | | |
| | | #define PA0 PA(0) |
| | | #define PA1 PA(1) |
| | | #define PA2 PA(2) |
| | | #define PA3 PA(3) |
| | | #define PA4 PA(4) |
| | | #define PA5 PA(5) |
| | | #define PA6 PA(6) |
| | | #define PA7 PA(7) |
| | | #define PA8 PA(8) |
| | | #define PA9 PA(9) |
| | | #define PA10 PA(10) |
| | | #define PA11 PA(11) |
| | | #define PA12 PA(12) |
| | | #define PA13 PA(13) |
| | | #define PA14 PA(14) |
| | | #define PA15 PA(15) |
| | | #define PA16 PA(16) |
| | | #define PA17 PA(17) |
| | | #define PA18 PA(18) |
| | | #define PA19 PA(19) |
| | | #define PA20 PA(20) |
| | | #define PA21 PA(21) |
| | | #define PA22 PA(22) |
| | | #define PA23 PA(23) |
| | | #define PA24 PA(24) |
| | | #define PA25 PA(25) |
| | | #define PA26 PA(26) |
| | | #define PA27 PA(27) |
| | | #define PA28 PA(28) |
| | | #define PA29 PA(29) |
| | | #define PA30 PA(30) |
| | | #define PA31 PA(31) |
| | | |
| | | |
| | | /*+-----------------------------------------------------+ |
| | | *| GPIO PortB: PB0~PB31 defined as "pioB0"-"pioB31" | |
| | | *+-----------------------------------------------------+*/ |
| | | |
| | | #define PB0 PB(0) |
| | | #define PB1 PB(1) |
| | | #define PB2 PB(2) |
| | | #define PB3 PB(3) |
| | | #define PB4 PB(4) |
| | | #define PB5 PB(5) |
| | | #define PB6 PB(6) |
| | | #define PB7 PB(7) |
| | | #define PB8 PB(8) |
| | | #define PB9 PB(9) |
| | | #define PB10 PB(10) |
| | | #define PB11 PB(11) |
| | | #define PB12 PB(12) |
| | | #define PB13 PB(13) |
| | | #define PB14 PB(14) |
| | | #define PB15 PB(15) |
| | | #define PB16 PB(16) |
| | | #define PB17 PB(17) |
| | | #define PB18 PB(18) |
| | | #define PB19 PB(19) |
| | | #define PB20 PB(20) |
| | | #define PB21 PB(21) |
| | | #define PB22 PB(22) |
| | | #define PB23 PB(23) |
| | | #define PB24 PB(24) |
| | | #define PB25 PB(25) |
| | | #define PB26 PB(26) |
| | | #define PB27 PB(27) |
| | | #define PB28 PB(28) |
| | | #define PB29 PB(29) |
| | | #define PB30 PB(30) |
| | | #define PB31 PB(31) |
| | | |
| | | /*+-----------------------------------------------------+ |
| | | *| GPIO PortC: PC0~PC31 defined as "pioC0"-"pioC31" | |
| | | *+-----------------------------------------------------+*/ |
| | | |
| | | #define PC0 PC(0) |
| | | #define PC1 PC(1) |
| | | #define PC2 PC(2) |
| | | #define PC3 PC(3) |
| | | #define PC4 PC(4) |
| | | #define PC5 PC(5) |
| | | #define PC6 PC(6) |
| | | #define PC7 PC(7) |
| | | #define PC8 PC(8) |
| | | #define PC9 PC(9) |
| | | #define PC10 PC(10) |
| | | #define PC11 PC(11) |
| | | #define PC12 PC(12) |
| | | #define PC13 PC(13) |
| | | #define PC14 PC(14) |
| | | #define PC15 PC(15) |
| | | #define PC16 PC(16) |
| | | #define PC17 PC(17) |
| | | #define PC18 PC(18) |
| | | #define PC19 PC(19) |
| | | #define PC20 PC(20) |
| | | #define PC21 PC(21) |
| | | #define PC22 PC(22) |
| | | #define PC23 PC(23) |
| | | #define PC24 PC(24) |
| | | #define PC25 PC(25) |
| | | #define PC26 PC(26) |
| | | #define PC27 PC(27) |
| | | #define PC28 PC(28) |
| | | #define PC29 PC(29) |
| | | #define PC30 PC(30) |
| | | #define PC31 PC(31) |
| | | |
| | | /*+-----------------------------------------------------+ |
| | | *| GPIO PortD: PD0~PD31 defined as "pioD0"-"pioD31" | |
| | | *+-----------------------------------------------------+*/ |
| | | |
| | | #define PD0 PD(0) |
| | | #define PD1 PD(1) |
| | | #define PD2 PD(2) |
| | | #define PD3 PD(3) |
| | | #define PD4 PD(4) |
| | | #define PD5 PD(5) |
| | | #define PD6 PD(6) |
| | | #define PD7 PD(7) |
| | | #define PD8 PD(8) |
| | | #define PD9 PD(9) |
| | | #define PD10 PD(10) |
| | | #define PD11 PD(11) |
| | | #define PD12 PD(12) |
| | | #define PD13 PD(13) |
| | | #define PD14 PD(14) |
| | | #define PD15 PD(15) |
| | | #define PD16 PD(16) |
| | | #define PD17 PD(17) |
| | | #define PD18 PD(18) |
| | | #define PD19 PD(19) |
| | | #define PD20 PD(20) |
| | | #define PD21 PD(21) |
| | | #define PD22 PD(22) |
| | | #define PD23 PD(23) |
| | | #define PD24 PD(24) |
| | | #define PD25 PD(25) |
| | | #define PD26 PD(26) |
| | | #define PD27 PD(27) |
| | | #define PD28 PD(28) |
| | | #define PD29 PD(29) |
| | | #define PD30 PD(30) |
| | | #define PD31 PD(31) |
| | | |
| | | /*+-----------------------------------------------------+ |
| | | *| GPIO PortE: PE0~PE30 defined as "pioE0"-"pioE30" | |
| | | *+-----------------------------------------------------+*/ |
| | | |
| | | #define PE0 PE(0) |
| | | #define PE1 PE(1) |
| | | #define PE2 PE(2) |
| | | #define PE3 PE(3) |
| | | #define PE4 PE(4) |
| | | #define PE5 PE(5) |
| | | #define PE6 PE(6) |
| | | #define PE7 PE(7) |
| | | #define PE8 PE(8) |
| | | #define PE9 PE(9) |
| | | #define PE10 PE(10) |
| | | #define PE11 PE(11) |
| | | #define PE12 PE(12) |
| | | #define PE13 PE(13) |
| | | #define PE14 PE(14) |
| | | #define PE15 PE(15) |
| | | #define PE16 PE(16) |
| | | #define PE17 PE(17) |
| | | #define PE18 PE(18) |
| | | #define PE19 PE(19) |
| | | #define PE20 PE(20) |
| | | #define PE21 PE(21) |
| | | #define PE22 PE(22) |
| | | #define PE23 PE(23) |
| | | #define PE24 PE(24) |
| | | #define PE25 PE(25) |
| | | #define PE26 PE(26) |
| | | #define PE27 PE(27) |
| | | #define PE28 PE(28) |
| | | #define PE29 PE(29) |
| | | #define PE30 PE(30) |
| | | |
| | | |
| | | #endif /* ----- #ifndef _AT91_SYSGPIODEF_H_ ----- */ |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * 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 <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; |
| | | } |
| | | |
| | | 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; |
| | | } |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2019 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: spidev.h |
| | | * 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秒" |
| | | * |
| | | ********************************************************************************/ |
| | | #ifndef _SPIDEV_H_ |
| | | #define _SPIDEV_H_ |
| | | |
| | | #include <stdint.h> |
| | | #include <fcntl.h> |
| | | #include <sys/ioctl.h> |
| | | #include <linux/ioctl.h> |
| | | #include <sys/stat.h> |
| | | #include <linux/types.h> |
| | | #include <linux/spi/spidev.h> |
| | | |
| | | #define DEVNAME_LEN 64 |
| | | |
| | | #define DEF_SPI_BPW 8 /* bits per word */ |
| | | #define DEF_SPI_SPEED 500 /* unit kHZ */ |
| | | #define DEF_SPI_MODE SPI_CPHA |
| | | |
| | | //#define SPI_DEBUG |
| | | #ifdef SPI_DEBUG |
| | | #define spi_dbg(format,args...) printf(format, ##args) |
| | | #else |
| | | #define spi_dbg(format,args...) do{} while(0); |
| | | #endif |
| | | |
| | | typedef struct spidev_s |
| | | { |
| | | char devname[DEVNAME_LEN]; |
| | | int fd; |
| | | uint8_t bits; /* bits per word */ |
| | | uint32_t speed; /* max speed in HZ */ |
| | | uint32_t delay; /* delay usecs */ |
| | | |
| | | /* mode: SPI_CPHA,SPI_CPOL => <SPI_MODE_0,SPI_MODE_1,SPI_MODE_2,SPI_MODE_3> |
| | | * SPI_CS_HIGH | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP | SPI_NO_CS |
| | | * | SPI_READY | SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD */ |
| | | uint32_t mode; |
| | | } spidev_t; |
| | | |
| | | |
| | | /* initialise and open spidev context |
| | | * NOTE: $speed unit is KHz |
| | | */ |
| | | extern int spi_init(spidev_t *spi, char *spidev, uint8_t bpw, uint32_t speed, uint32_t delay, uint32_t mode); |
| | | |
| | | |
| | | /* read size bytes from SPI slave */ |
| | | extern int spi_read(spidev_t *spi, char *buf, int size); |
| | | |
| | | |
| | | /* write nbytes to SPI slave */ |
| | | extern int spi_write(spidev_t *spi, char *data, int nbytes); |
| | | |
| | | |
| | | /* write nbytes and read nbytes to/from SPI slave */ |
| | | extern int spi_rdwr(spidev_t *spi, char *data, char *rbuf, int nbytes); |
| | | |
| | | |
| | | /* terminate and close spidev context */ |
| | | extern int spi_term(spidev_t *spi); |
| | | |
| | | |
| | | #endif /* ----- #ifndef _SPIDEV_H_ ----- */ |
| | | |