SAMA5D4 Xplained Ultra Board BSP
guowenxue
2019-08-27 03ada50f4e3993fc9e3d4c17e952f12bb67d7d98
add AT91 GPIO AND spi library
5 files added
823 ■■■■■ changed files
program/lylib/at91_sysGpio.c 210 ●●●●● patch | view | raw | blame | history
program/lylib/at91_sysGpio.h 62 ●●●●● patch | view | raw | blame | history
program/lylib/at91_sysGpioDef.h 221 ●●●●● patch | view | raw | blame | history
program/lylib/spidev.c 255 ●●●●● patch | view | raw | blame | history
program/lylib/spidev.h 75 ●●●●● patch | view | raw | blame | history
program/lylib/at91_sysGpio.c
New file
@@ -0,0 +1,210 @@
/*********************************************************************************
 *      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);
}
program/lylib/at91_sysGpio.h
New file
@@ -0,0 +1,62 @@
/*********************************************************************************
 *      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_  ----- */
program/lylib/at91_sysGpioDef.h
New file
@@ -0,0 +1,221 @@
/********************************************************************************
 *      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_  ----- */
program/lylib/spidev.c
New file
@@ -0,0 +1,255 @@
/*********************************************************************************
 *      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;
}
program/lylib/spidev.h
New file
@@ -0,0 +1,75 @@
/*********************************************************************************
 *      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_  ----- */