SPIdev

The SPI bus (or Serial Peripheral Interface bus) is a synchronous serial data link originally created by motorola.

For more information about SPI please refer to this link: http://en.wikipedia.org/wiki/Serial_Peripheral_Interface

In the linux kernel the SPI works only in master mode.

There is a way of using the spi kernel driver to work as a device in the userspace. It's called SPIdev.

=Configuring your kernel= For using it you will have to enable this options in your defconfig or manually in your kernel:

CONFIG_SPI_SUN4I=y

CONFIG_SPI=y

CONFIG_SPI_MASTER=y

CONFIG_EXPERIMENTAL=y

CONFIG_SPI_SPIDEV=y

=More information= For more information about using SPIdev in the userspace please refer to (Documentation/spi/): http://lxr.free-electrons.com/source/Documentation/spi/

You will find there:

spidev (contains the documentantion about the spidev)

spidev_fdx.c (contains a simple example in C of a full duplex communication)

spidev_test.c (contains a simple example in C of a half duplex communication)

=Configuring your FEX= It is important to configure your .fex file to be able to do so:

(if you are using spi0)

 [spi0_para] spi_used = 1 spi_cs_bitmap = 1 spi_cs0 = port:PI10<2> spi_sclk = port:PI11<2> spi_mosi = port:PI12<2> spi_miso = port:PI13<2> (here you will specify the number of spi devices your card will have, if you plan only to use the spidev just put 1):  [spi_devices] spi_dev_num = 1 (here you will have to put in the modalias "spidev")  [spi_board0] modalias = "spidev" max_speed_hz = 12000000 bus_num = 0 chip_select = 0 mode = 0 full_duplex = 1 manual_cs = 0 For more information about editing the fex file: http://linux-sunxi.org/Fex_Guide

=Using the SPI bus= Once you will have this set you can boot your sunxi device and you will have in your dev in /dev/spidev0.0

Known problems: Using the spidev_test.c example you will receive [spi]: drivers/spi/spi_sunxi.c(L1025) cpu tx data time out!

Using the spidev_fdx.c method it works like a charm! :)

I've made a user friendlier library (C functions) to comunicate using SPIdev:

(Note, this library supose the read and write address to be 2 bytes)  /*   spidevlib.c - A user-space program to comunicate using spidev. Gustavo Zamboni
 * 1) include 
 * 2) include 
 * 3) include 
 * 4) include 
 * 5) include 
 * 6) include 
 * 7) include 
 * 8) include 
 * 9) include 
 * 1) include 

char buf[10]; char buf2[10]; extern int com_serial; extern int failcount;

struct spi_ioc_transfer xfer[2];

////////// // Init SPIdev ////////// int spi_init(char filename[40]) {   	int file; __u8	mode, lsb, bits; __u32 speed=2500000;

if ((file = open(filename,O_RDWR)) < 0) {       	printf("Failed to open the bus."); /* ERROR HANDLING; you can check errno to see what went wrong */ com_serial=0; exit(1); }

///////////////		// Verifications ///////////////		//possible modes: mode |= SPI_LOOP; mode |= SPI_CPHA; mode |= SPI_CPOL; mode |= SPI_LSB_FIRST; mode |= SPI_CS_HIGH; mode |= SPI_3WIRE; mode |= SPI_NO_CS; mode |= SPI_READY; //multiple possibilities using | /*			if (ioctl(file, SPI_IOC_WR_MODE, &mode)<0)	{ perror("can't set spi mode"); return; }		*/

if (ioctl(file, SPI_IOC_RD_MODE, &mode) < 0) {				perror("SPI rd_mode"); return; }			if (ioctl(file, SPI_IOC_RD_LSB_FIRST, &lsb) < 0) {				perror("SPI rd_lsb_fist"); return; }		//sunxi supports only 8 bits /*			if (ioctl(file, SPI_IOC_WR_BITS_PER_WORD, 8)<0) {				perror("can't set bits per word"); return; }		*/			if (ioctl(file, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) {				perror("SPI bits_per_word"); return; }		/*			if (ioctl(file, SPI_IOC_WR_MAX_SPEED_HZ, &speed)<0) {				perror("can't set max speed hz"); return; }		*/			if (ioctl(file, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) {				perror("SPI max_speed_hz"); return; }

printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n",filename, mode, bits, lsb ? "(lsb first) " : "", speed);

//xfer[0].tx_buf = (unsigned long)buf; xfer[0].len = 3; /* Length of command to write*/ xfer[0].cs_change = 0; /* Keep CS activated */ xfer[0].delay_usecs = 0, //delay in us	xfer[0].speed_hz = 2500000, //speed xfer[0].bits_per_word = 8, // bites per word 8

//xfer[1].rx_buf = (unsigned long) buf2; xfer[1].len = 4; /* Length of Data to read */ xfer[1].cs_change = 0; /* Keep CS activated */ xfer[0].delay_usecs = 0; xfer[0].speed_hz = 2500000; xfer[0].bits_per_word = 8;

return file; }

////////// // Read n bytes from the 2 bytes add1 add2 address //////////

char * spi_read(int add1,int add2,int nbytes,int file) {	int status;

memset(buf, 0, sizeof buf); memset(buf2, 0, sizeof buf2); buf[0] = 0x01; buf[1] = add1; buf[2] = add2; xfer[0].tx_buf = (unsigned long)buf; xfer[0].len = 3; /* Length of command to write*/ xfer[1].rx_buf = (unsigned long) buf2; xfer[1].len = nbytes; /* Length of Data to read */ status = ioctl(file, SPI_IOC_MESSAGE(2), xfer); if (status < 0) {		perror("SPI_IOC_MESSAGE"); return; }	//printf("env: %02x %02x %02x\n", buf[0], buf[1], buf[2]); //printf("ret: %02x %02x %02x %02x\n", buf2[0], buf2[1], buf2[2], buf2[3]);

com_serial=1; failcount=0; return buf2; }

////////// // Write n bytes int the 2 bytes address add1 add2 ////////// void spi_write(int add1,int add2,int nbytes,char value[10],int file) {	unsigned char	buf[32], buf2[32]; int status;

memset(buf, 0, sizeof buf); memset(buf2, 0, sizeof buf2); buf[0] = 0x00; buf[1] = add1; buf[2] = add2; if (nbytes>=1) buf[3] = value[0]; if (nbytes>=2) buf[4] = value[1]; if (nbytes>=3) buf[5] = value[2]; if (nbytes>=4) buf[6] = value[3]; xfer[0].tx_buf = (unsigned long)buf; xfer[0].len = nbytes+3; /* Length of command to write*/ status = ioctl(file, SPI_IOC_MESSAGE(1), xfer); if (status < 0) {		perror("SPI_IOC_MESSAGE"); return; }	//printf("env: %02x %02x %02x\n", buf[0], buf[1], buf[2]); //printf("ret: %02x %02x %02x %02x\n", buf2[0], buf2[1], buf2[2], buf2[3]);

com_serial=1; failcount=0; }

Usage example:

 char *buffer; char buf[10];

file=spi_init("/dev/spidev0.0"); //dev

buf[0] = 0x41; buf[1] = 0xFF; spi_write(0xE6,0x0E,2,buf,file); //this will write value 0x41FF to the address 0xE60E

buffer=(char *)spi_read(0xE6,0x0E,4,file); //reading the address 0xE60E

close(file);

For info it is possible to use all the 12000000 Hz frequency limit transfers.