Soekris net4501/4801 GPIO and error LED driver

net4801 with LCD attached On this page, you'll find some utilities/documentation for using the Soekris net4501/4801 GPIO ports under linux.
This driver works with kernel 2.4 only - Stanislav Meduna has written a port to kernel 2.6, which is available at http://www.meduna.org/sw_gpio_en.html.

GPIO driver

Changelog:
1.2.0 2003-11-12 Removed 4801gpio.c from the tarball (it was not used at all)
1.2.1 2003-11-27 Bugfixes to reading error_led and gpio ports, thanks to Dave Johnson
1.3.0 2004-01-25 Added support for the voltage and temperature monitors on the 4801
Cleaned up proc handling
Added drivertest program, to make sure all functions still work after a code change
Reorganized the code so there's only one (somewhat bigger) module for 4801 and 45xx
1.3.1 2004-01-26 Since the previous release was not quite finished (but released to respond to an inquiry on the soekris-tech list) this release takes care of all open issues (documentation, test-program)
Fixed bug with writing to /dev/gpio1 (4801 only)
1.3.2 2004-02-24 Fixed warning "unresolved symbol __number_of_pins", that occurred if the module was stripped
Fixed (?) problem with MODVERSIONS enabled in the kernel
Corrected JP5 description in 4801gpio.h

Download: gpio-1.3.2.tar.gz

Here you can find a small driver to access the GPIO ports under linux. There are others available (especially a userland app which may serve your purpose better than my driver - you can find it in the soekris-tech-list archives, posted on 27 Feb 2003, the subject of the message is "Linux userland code for twiddling GPIO lines" - but note, this will only work for the net4501).

This driver is a kernel module, because the intended target platform does not allow userland applications to access to IO-ports (due to the grsecurity kernel patches).

For the driver to work on the net4801, you need at least BIOS release version 1.22 available here - the driver does not work with earlier versions of the BIOS.

Compiling the driver

Simply extract the archive to a directory of your choice, and then edit the makefile (sorry, creating an autoconf-setup for something as small as this sounds like overkill to me) so that the variable KERNELDIR points to the kernel source you want to compile the module against. Normally, this would be

/usr/src/linux-2.4/
Note that the variable is commented out by default (since the environment I compile the modules in automatically sets this value as an environment variable).

Once you're done, simply type

make
and hopefully you'll end up with a set of modules.

Note: please make sure that you're using the same version of gcc used to compile the kernel (important if you're running Fedora core for example - on Fedora, one needs to

"export CC=gcc32"
before running make).

You'll now have the following .o files in the gpio-1.3.1 directory:

4501driver.o
4801driver.o
gpio.o
writelcd.o
common.o
common_writelcd.o

Of these, only 2 are actual modules (the other ones are temporary object files, created during the compile) - namely

gpio.o
writelcd.o

The gpio.o file is the actual driver, the writelcd.o file is a simplistic LCD driver that will simply display "Booting..." on an HD44780 compatible LCD (see below).

The gpio.o module will work both on the Elan SC520 based Soekris boxes (namely on the net4501, net4511 and net4521) and the Geode SC1100 based net4801.

Using the GPIO driver

The GPIO drivers can be used in 3 different ways

The proc filesystem interface

This is the easiest to use (to set GPIO ports manually or via a shell script), but also the slowest method (I wouldn't want to drive an LCD using the proc filesystem). The driver registers 3 files in the proc filesystem:

  1. /proc/driver/soekris_error_led
  2. /proc/driver/soekris_gpio
  3. /proc/driver/soekris_io_settings

Error LED

To turn on the error LED:

echo 1 > /proc/driver/soekris_error_led

To turn off the error LED:

echo 0 > /proc/driver/soekris_error_led

To read the status of the error LED:

cat /proc/driver/soekris_error_led

GPIOs on the 45xx

To turn on GPIO5 and GPIO1:

echo 00100010 > /proc/driver/soekris_gpio

To turn on GPIO7 :

echo 10000000 > /proc/driver/soekris_gpio

To read the status of the GPIOs

cat /proc/driver/soekris_gpio

If a certain GPIO is set to input, writing a value to this GPIO will have no effect.

GPIOs on the 4801

Since the net4801 has 12 GPIO ports, the usage of the proc interface is slightly different.

To turn on GPIO5 and GPIO1:

echo 000000100010 > /proc/driver/soekris_gpio

To turn on GPIO7 :

echo 000010000000 > /proc/driver/soekris_gpio

To turn on GPIO11:

echo 100000000000 > /proc/driver/soekris_gpio

To read the status of the GPIOs

cat /proc/driver/soekris_gpio

If a certain GPIO is set to input, writing a value to this GPIO will have no effect.

Device driver

When loaded, the modules register a major number dynamically. This means that the modules do not have a fixed major number assigned to them, but rather use one that's assigned by the system.

After loading the module, you can find out which major number has been assigned with

cat /proc/devices

Creating the devices:
Once you know the major number that's been assigned to the driver (usually 254, but don't rely on it), you can create the corresponding device files with the following commands:

export major=254
mknod /dev/gpio0 c $major 0
mknod /dev/gpio1 c $major 1
mknod /dev/gpio254 c $major 254

Minor 0:
Controls GPIO ports 0 to 7. Each byte sent to/read from the device file represents a bit-mask for the 8 GPIO ports (bit 0 corresponds with GPIO0 and so on).

Minor 1:
Controls GPIO ports 0 to 11 (net4801 only). Each word sent to/read from the device file (low byte first) represents a bit-mask for the 12 GPIO ports (bit 0 corresponds with GPIO0 and so on).

Minor 254:
Controls the error LED. Sending a value of 0 turns the led off, sending anything else turns the LED on (the same applies for when data is read from the device).

IOCTL calls

The following IOCTL commands are supported by the device driver:

GPIORDDIRECTION,GPIOWRDIRECTION

Expects a pointer to an unsigned int. Sets/returns the direction of the given gpio ports according to the value given (bit=1 means output, bit=0 means input).

GPIORDDATA,GPIOWRDATA

net4501:
Expects a pointer to an unsigned int. Sets/returns the value of the gpio ports 0 to 7.

net4801
Expects a pointer to an unsigned int. Sets/returns the value of the gpio ports 0 to 11.

The driver also implements some IOCTL calls from ppdev - mainly so that the GPIO ports could be used as a simple replacement for driving an LCD display (see below).

PPCLAIM, PPRELEASE, PPFCONTROL

These don't do anything, but don't cause an error either

PPDATADIR

Data line direction for GPIO0-3: non-zero for input mode (note - this is reversed from the logic used in GPIORDDIRECTION and GPIOWRDIRECTION). This is not "generic" at all, but very much hard-wired towards being able to use an HD44780 LCD on the GPIO pins (in 4-bit mode) and being able to do so using generic ppdev instructions
So, GPIO4-GPIO7 will _always_ be set to output after this call, only GPIO0-GPIO3 are changed

PPWDATA,PPRDATA

Reads/writes to the gpio0-7 (minor 0) or the error led (minor 254)

Accessing the termperature sensors (Net4801 only)

cat /proc/driver/soekris_temp
Should show something like this:
Temp 0 0xcd 127 C
Temp 1 0xcd 127 C
Temp 2 0x81 46 C
It seems that Temp 0 and 1 are not connected (they always show 127 C) The first value in hex is the contents of the "Temperature Channel Configuration and Status Register". See the readme or the the PC87366 spec for the meaning of the contents of this register The second value is the temperature in Celsius

Accessing the voltage monitors (Net4801 only)

cat /proc/driver/soekris_voltage
Should show something like this:
avi0 3.01 V
avi1 2.04 V
VCC 5.08 V
VPWR 12.29 V
avi4 2.54 V
avi5 2.54 V
avi6 0.00 V
Vsb 3.33 V
Vdd 3.35 V
Vbat 3.01 V
AVdd 3.33 V
ts0 1.56 V
ts1 1.58 V
ts2 1.50 V
The mapping of the different values to avi0 and so on is taken from http://phk.freebsd.dk/soekris/env4801/ - until Soekris Engineering releases some official specifications.

Samples

Todo: add sample code/scripts (contributions welcome)

Using the GPIO ports to control an LCD

I use the driver described above to run an HD44780 compatible LCD connected to my soekris boxes. The software used to control the LCD is lcd4linux.

The wiring used is the 4-Bit wiring (since the net4501 doesn't have enough GPIO ports for anything else).

Wiring between the Soekris and the LCD
Do not connect the backlight pins to the Soekris 5V or 3.3V pins!

Sample config file for lcd4linux (this is what was used on the picture above):

Display HD44780
Port /dev/gpio0
Size 20x4
GPOs 0

# 4 Bit protocol/wiring
Bits 4
Wire.RS "DB4"
Wire.RW "DB5"
Wire.ENABLE "DB6"
Wire.GPO "GND"

#---------------------------------------
# display config

Row1 \040\040\040 %o %v \040\040&1
Row2 CPU   %cb%%$r10cb
Row3 Net %nm $R10nr+nw
Row4 Load%l1 $r10cs+cb
Row5 \040\040\040 %o %v \040\040&1
Row6 CPU  %cb%% $r10cb
Row7 Net %nm $R10nr+nw
Row8 PPP %ti $R8ti+to %to

Rows 8
Scroll 4
Turn 5000
Tick.Text 400
Tick.Bar  100
Tick.Icon 250
Tick.GPO  100
Overload 2.0
Icons 1
Icon1.Bitmap1 .....|.....|.....
Icon1.Bitmap2 .*.*.|.*.*.|.....
Icon1.Bitmap3 *****|*****|.*.*.
Icon1.Bitmap4 *****|*****|.***.
Icon1.Bitmap5 .***.|.***.|.***.
Icon1.Bitmap6 .***.|.***.|..*..
Icon1.Bitmap7 ..*..|..*..|.....
Icon1.Bitmap8 .....|.....|.....

Feedback

The driver works well on my test-boxes - net4501 and net4801 running linux (Bering uClibc) with a 2.4.26 kernel, but it hasn't received any widespread testing yet (especially the functions that are not needed for controlling an LCD). So chances are that you will find some bugs when using the modules.

Error reports, suggestions and especially patches are greatly appreciated and should be sent to linux@hejl.de


Last change: 2010-06-16