SPI kernel driver howto

Continuing my previous post on writing an SPI driver for the BeagleBone, here’s a richly commented example C file to help implementing a generic kernel module driver for your chosen SPI device. The example is not only for the BeagleBone, you can use it for any host.

download (15.4 kb)

About the module

This example module shows you the following:

  1. How to probe and initialize your SPI device from the kernel module
  2. How to register and use interrupts on GPIO pins
  3. How to use workqueues
  4. How to communicate (read and write registers) with your SPI device
  5. How to use the GPIO pins and LEDs on the BeagleBone
  6. How to create and use sysfs files
  7. How to use FIFO and ringbuffers

After loading, the module creates the following sysfs files in the /sys/kernel/misc/spikernmodex/ directory:

  1. store: when you read this, the module pops and prints an entry from the ringbuffer, on writing it puts the data to a FIFO buffer and then tries to send the contents of the FIFO buffer to the SPI device
  2. somereg: on reading, it prints the value of the SPI device’s (example) SOMEREG register, on writing, it puts the value to the SPI device’s SOMEREG register
  3. clearringbuffer: on writing, it clears the module’s ringbuffer
  4. gpio19state: on reading, returns the state (0/1) of the GPIO19 pin
  5. gpio21state: on reading, returns the state (0/1) of the GPIO21 pin

The module sets an interrupt for a rising edge signal on the GPIO19 pin. When the interrupt occurs, it queues the work called READ, which reads some data from the SPI device and pushes it to the ringbuffer. When you read the sysfs file called “store”, you will get one entry from the ringbuffer (or nothing, if the ringbuffer is empty).

The reason why a workqueue is used is that the SPI commands are blocking, and we must return from an interrupt as quickly as possible (and also we can’t call a method from an interrupt which can sleep, like spi_sync()).

Notice: this module is only an example, it can be compiled and loaded as a kernel module, but it won’t do much by itself.

Installing the module

Here’s how to install the kernel module:

  1. Copy spikernmodex.c to your kernel source’s drivers/misc folder.
  2. Edit the folder’s Makefile, add this after the last line:

    1
    obj-$(CONFIG_SPIKERNMODEX) += spikernmodex.o
  3. Edit the folder’s Kconfig file, add this somewhere:

    1
    2
    3
    4
    5
    config SPIKERNMODEX
        tristate "Example SPI driver by Nonoo (www.nonoo.hu)"
        depends on SPI && SYSFS
        help
            http://dp.nonoo.hu/spi-kernel-driver-howto/
  4. Compile your kernel and say “m” when the configuration script asks for building CONFIG_SPIKERNMODEX as a module or build into the kernel (or manually add CONFIG_SPIKERNMODEX=m to the end of your kernel’s .config file.
Proyecto 2013-02-20 14:09:05

Hi,

This is a very interesting post. I’m working with the SPI device in the MSC-EXM32 board, similar to the beagle board, but it’s microprocessor is a Freescale iMX35.

The problem we are stuck with is that the device doesn’t appear in the /dev/ directory. And we don’t know why.

Do you think your module could work on my board?

Thanks in advance.

Nonoo 2013-02-20 14:15:37

If you want to have a device in /dev then you have to use the spidev interface/kernel module. My solution doesn’t create a device in /dev, it creates sysfs files in /sys.

 
 
sanjeev sharma 2013-08-29 08:21:32

Hi Nonno,

Is this similar to spidev driver?

 
sanjeev sharma 2013-08-29 08:23:08

Do you have any idea if we need to implement buffering in spidev driver then can we leverage this ring buffer implementation out of it if SPI is sending data continuously ?

Nonoo 2013-08-29 08:53:58

spidev is a generic kernel mode driver for SPI devices. By using it, you have to communicate with your devices fully from userspace. My kernel driver handles SPI communication in kernel space, only the processed data is forwarded to userspace, so this solution is much faster (and more complicated of course).

 
 
sanjeev sharma 2013-09-02 09:09:43

Hey,Got it,

So this is an similar to spidev which is talking to controller driver ? can you through some light on below question

Do you have any idea if we need to implement buffering in spidev driver then can we leverage this ring buffer implementation out of it if SPI is sending data continuously

my intention is to read data continuously from controller driver in spi dev driver i.e protocol driver and copy that incoming data into kernel buffer and do some operation on that data and then send valid data to userspace ?

Please let me know if this is not clear

Nonoo 2013-09-02 09:16:13

You must implement a ring buffer in your driver because interacting with the device from userspace will be slow. Your solution is correct, you have to read the data in your driver to a ring buffer, then read this ring buffer from userspace.

sanjeev sharma 2013-09-05 06:41:56

Any reference code of ring buffer do you have in Kernel Space ?

Nonoo 2013-09-05 09:25:26

As far as I remember, the example code doesn’t have ring buffer example code, but I’m sure you’ll find some on the net. Check out Wikipedia for example: http://en.wikipedia.org/wiki/Circular_buffer

 
 
 
 
sanjeev sharma 2013-09-02 09:10:19

your comment/feedback would be apprenticed

 
Siddharth 2014-08-21 13:29:29

Hi Nonoo,

I have had a read through your spi module and I see you are using interrupts with gpio pins. If I am to service interrupts when data gets transmitted or received through SPI how do I do that? Any help would be very useful

 
Name (required)
E-mail (required - never shown publicly)
Webpage URL
Comment:
You may use <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> in your comment.

Trackback responses to this post

About me

Nonoo
I'm Nonoo. This is my blog about music, sounds, filmmaking, amateur radio, computers, programming, electronics and other things I'm obsessed with. ... »

Twitter

Listening now

My favorite artists