Generic gpio driver

Discussion around AT91RM9200 and SAM9 Series Products.

Moderator: nferre

haizaar
Posts: 5
Joined: Thu Aug 07, 2008 8:56 am

Generic gpio driver

Tue Dec 23, 2008 8:38 pm

Good day!
I've adapted (from OpenWRT project) generic gpio driver to set/clear desired gpio pins and their directions via gpioctl util.
This tool was very handy for me to read dip switches status, flash leds, etc.

Usage:
gpioctl dirin|dirout|get|set|clear gpio
where gpio number is calculated like this:
a. Board pins are named ins the form: P<letter><number>, for example: PA06, PB20
b. gpio=<letter>*32+<number>, where <letter> is casted to integer like
this: A=32, B=64, C=96, etc... For example: PA06=1*32+6=38, PB20=2*32+20=84

Patch against linux-2.6.27.7 and sources for gpioctl tool are below. Ejoy!

kernel patch (bbcode break the patch layout, and I'm not allowed to attach .patch files :( )
===============================================

Code: Select all

This is an adaption of the module from OpenWRT progject:
https://dev.openwrt.org/browser/trunk/target/linux/generic-2.6/files-2.6.27/drivers/char/gpio_dev.c

I've converted it to use misc device class and removed mask. Also gpio_dev.h is now exported.

pin_name -> gpio_number is converted like this:
1. pin_name is in the from P<letter><number>, for example PA21
2. gpio_number=letter*32+number, where "letter" is A=1, B=2, C=3, etc...
3. examples: PA21=1*32+21=53, PB8=2*32+8=72

Author: Hai Zaar <haizaar@codefidence.com>

--- linux-2.6.27.2/drivers/char/gpio_dev.c.orig	2008-10-26 14:01:52.000000000 +0200
+++ linux-2.6.27.2/drivers/char/gpio_dev.c	2008-10-27 15:10:54.000000000 +0200
@@ -0,0 +1,137 @@
+/*
+ * character device wrapper for generic gpio layer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
+ *
+ * Feedback, Bugs...  blogic@openwrt.org
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/atomic.h>
+#include <linux/init.h>
+#include <linux/genhd.h>
+#include <linux/miscdevice.h>
+#include <linux/gpio_dev.h>
+
+#define DRVNAME		"gpiodev"
+#define DEVNAME		"gpio"
+
+static int dev_major;
+
+/* Counter is 1, if the device is not opened and zero (or less) if opened. */
+static atomic_t gpio_open_cnt = ATOMIC_INIT(1);
+
+static int
+gpio_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
+{
+	int retval = 0;
+
+	switch (cmd)
+	{
+	case GPIO_GET:
+		retval = gpio_get_value(arg);
+		break;
+
+	case GPIO_SET:
+		gpio_set_value(arg, 1);
+		break;
+
+	case GPIO_CLEAR:
+		gpio_set_value(arg, 0);
+		break;
+
+	case GPIO_DIR_IN:
+		gpio_direction_input(arg);
+		break;
+
+	case GPIO_DIR_OUT:
+		gpio_direction_output(arg, 0);
+		break;
+
+	default:
+		retval = -EINVAL;
+		break;
+	}
+
+	return retval;
+}
+
+static int
+gpio_open(struct inode *inode, struct file *file)
+{
+	int result = 0;
+	unsigned int dev_minor = MINOR(inode->i_rdev);
+
+	/* FIXME: We should really allow multiple applications to open the device
+	 *        at the same time, as long as the apps access different IO pins.
+	 *        The generic gpio-registration functions can be used for that.
+	 *        Two new IOCTLs have to be introduced for that. Need to check userspace
+	 *        compatibility first. --mb */
+	if (!atomic_dec_and_test(&gpio_open_cnt)) {
+		atomic_inc(&gpio_open_cnt);
+		printk(KERN_ERR DRVNAME ": Device with minor ID %d already in use\n", dev_minor);
+		result = -EBUSY;
+		goto out;
+	}
+
+out:
+	return result;
+}
+
+static int
+gpio_close(struct inode * inode, struct file * file)
+{
+	smp_mb__before_atomic_inc();
+	atomic_inc(&gpio_open_cnt);
+
+	return 0;
+}
+
+struct file_operations gpio_fops = {
+	.ioctl		= gpio_ioctl,
+	.open		= gpio_open,
+	.release	= gpio_close,
+};
+
+static struct miscdevice gpio_dev = {
+        .minor			= MISC_DYNAMIC_MINOR,
+        .name			= "gpio",                   
+        .fops			= &gpio_fops,
+};
+
+static int __init
+gpio_mod_init(void)
+{
+	return misc_register(&gpio_dev);
+}
+
+static void __exit
+gpio_mod_exit(void)
+{
+	misc_deregister(&gpio_dev);
+}
+
+module_init (gpio_mod_init);
+module_exit (gpio_mod_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin / OpenWrt");
+MODULE_DESCRIPTION("Character device for for generic gpio api");
--- linux-2.6.27.2/drivers/char/Makefile.orig	2008-10-26 14:10:35.000000000 +0200
+++ linux-2.6.27.2/drivers/char/Makefile	2008-10-27 15:10:59.000000000 +0200
@@ -9,6 +9,7 @@
 
 obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o 
 
+obj-y				+= gpio_dev.o
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
 obj-y				+= misc.o
--- linux-2.6.27.2/include/linux/gpio_dev.h.orig	2008-10-26 14:12:32.000000000 +0200
+++ linux-2.6.27.2/include/linux/gpio_dev.h	2008-10-26 14:12:24.000000000 +0200
@@ -0,0 +1,11 @@
+#ifndef _GPIODEV_H__
+#define _GPIODEV_H__
+
+#define IOC_GPIODEV_MAGIC  'B'
+#define GPIO_GET        _IO(IOC_GPIODEV_MAGIC, 10)
+#define GPIO_SET        _IO(IOC_GPIODEV_MAGIC, 11)
+#define GPIO_CLEAR      _IO(IOC_GPIODEV_MAGIC, 12)
+#define GPIO_DIR_IN     _IO(IOC_GPIODEV_MAGIC, 13)
+#define GPIO_DIR_OUT    _IO(IOC_GPIODEV_MAGIC, 14)
+
+#endif
--- linux-2.6.27.2/include/linux/Kbuild.orig	2008-10-27 17:03:24.000000000 +0200
+++ linux-2.6.27.2/include/linux/Kbuild	2008-10-27 17:03:48.000000000 +0200
@@ -74,6 +74,7 @@
 header-y += gen_stats.h
 header-y += gfs2_ondisk.h
 header-y += gigaset_dev.h
+header-y += gpio_dev.h
 header-y += hysdn_if.h
 header-y += i2o-dev.h
 header-y += i8k.h
gpioctl.c
=============================

Code: Select all

/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
*
* Feedback, Bugs...  blogic@openwrt.org 
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/ioctl.h>
#include <linux/gpio_dev.h>

void
print_usage()
{
	printf("gpioctl dirin|dirout|get|set|clear gpio\n");
	exit(0);
}

int
main(int argc, char **argv)
{
	int gpio_pin;
	int fd;
	int result = 0;

	if (argc != 3)
	{
		print_usage();
	}

	if ((fd = open("/dev/gpio", O_RDWR)) < 0)
	{
        printf("Error whilst opening /dev/gpio\n");
        return -1;
	}

	gpio_pin = atoi(argv[2]);

	printf("using gpio pin %d\n", gpio_pin);

	if (!strcmp(argv[1], "dirin"))
	{
		ioctl(fd, GPIO_DIR_IN, gpio_pin);
	} else if (!strcmp(argv[1], "dirout"))
	{
		ioctl(fd, GPIO_DIR_OUT, gpio_pin);
	} else if (!strcmp(argv[1], "get"))
	{
		result = ioctl(fd, GPIO_GET, gpio_pin);
		printf("Pin %d is %s\n", gpio_pin, (result ? "HIGH" : "LOW"));
	} else if (!strcmp(argv[1], "set"))
	{
		ioctl(fd, GPIO_SET, gpio_pin);
	} else if (!strcmp(argv[1], "clear"))
	{
		ioctl(fd, GPIO_CLEAR, gpio_pin);
	} else print_usage();

	return result;
}

ghofman
Location: Vancouver, BC, Canada
Posts: 26
Joined: Sun May 20, 2007 5:11 am

Re: Generic gpio driver

Wed Feb 04, 2009 1:02 am

Hi,

This looks interesting. Can you tell me if this is generic for at91sam9XXX series ?

Thanks

Gertjan
haizaar
Posts: 5
Joined: Thu Aug 07, 2008 8:56 am

Re: Generic gpio driver

Wed Feb 04, 2009 1:08 am

It really should be.
But all I can really promise is that this works on at91sam9260.
potatolicious
Posts: 1
Joined: Tue Mar 17, 2009 2:48 am

Re: Generic gpio driver

Tue Mar 17, 2009 2:50 am

Hi,

I manually applied this patch to kernel 2.6.28, but do not see a /dev/gpio device. Is this built as a kernel module? "modprobe gpio" or "modprobe gpiodev" didn't locate anything...

[edit] I'm really not sure how this thing is supposed to be built at all. It doesn't seem to be part of any module, so I compiled the kernel image and uploaded it to my board (done this before many times). The kernel still boots, but no such device exists.
haizaar
Posts: 5
Joined: Thu Aug 07, 2008 8:56 am

Re: Generic gpio driver

Wed Mar 18, 2009 1:20 pm

Yes, the driver is compiled into kernel. Run cat /proc/misc|grep gpio - it will tell you the minor number of the misc device. Then mknod /dev/gpio c 10 <number_you_got_from_grep>. Then try gpioctl.
ckamas
Posts: 3
Joined: Thu Mar 05, 2009 3:20 am

Re: Generic gpio driver

Thu Apr 02, 2009 7:52 pm

I found a tool to fix the BBCODE patch problem: unwrapdiff

For ubuntu:
sudo apt-get install patchutils

then
unwrapdiff gpio.patch > gpio.patch
haizaar
Posts: 5
Joined: Thu Aug 07, 2008 8:56 am

Re: Generic gpio driver

Thu Apr 02, 2009 8:01 pm

Good to know! Thanks!
ottinger
Posts: 1
Joined: Wed Mar 04, 2009 11:36 am

Re: Generic gpio driver

Wed May 06, 2009 2:27 pm

Just successfully compiled on 2.6.27 on the AT91SAM9RL64 Platform - thanks a lot
pushkar.kulkarni
Posts: 1
Joined: Mon Mar 09, 2009 2:36 pm

Re: Generic gpio driver

Sat Jun 13, 2009 8:20 am

Manually patched this driver to Kernel 2.6.27 and it's working on AT91SAM9263EK.
Good work, Thank you!! :D
tganeshg8
Posts: 9
Joined: Fri May 27, 2016 2:43 pm

Re: Generic gpio driver

Sat Apr 22, 2017 3:47 pm

Dear Friend,

I hope you are working in Openwrt on AT91Sam9xxx..

Please help me to compile the openwrt to AT91sam9g25..

I'm Struggling last few months...

Return to “SAM9 ARM9 MPU”

Who is online

Users browsing this forum: No registered users and 6 guests