OpenWrt Forum Archive

Topic: Driver for the GPIO's of AR5315 in /proc ...

The content of this topic has been archived between 29 Mar 2018 and 24 Apr 2018. There are no obvious gaps in this topic, but there may still be some posts missing at the end.

@olg:
thank you, it works !

for the interested:
I have made some small modifications in order to compile the module.
You can grab the module and the sources here -> http://daubau.net/proc_gpio/

Here an updated version of proc_gpio, it compiles now out of the box again...


Index: utils/proc_gpio/src/proc_gpio.c
===================================================================
--- utils/proc_gpio/src/proc_gpio.c    (revision 0)
+++ utils/proc_gpio/src/proc_gpio.c    (revision 0)
@@ -0,0 +1,222 @@
+//proc_gpio: AR5315 GPIO pins in /proc/gpio/
+// by olg 
+// GPL'ed
+// some code stolen from Yoshinori Sato <ysato@users.sourceforge.jp>
+
+#include <linux/autoconf.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/proc_fs.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h> /* for copy_from_user */
+#include "ar531x.h"
+
+#define PROCFS_MAX_SIZE 64
+
+struct proc_dir_entry *proc_gpio, *gpio_dir;
+
+//Masks for data exchange through "void *data" pointer
+#define GPIO_IN (1<<5)
+#define GPIO_OUT (1<<6)
+#define GPIO_DIR (1<<7)
+#define PIN_MASK 0x1f
+
+/*
+#define AR5315_GPIO_DI          (AR5315_DSLBASE + 0x0088)
+#define AR5315_GPIO_DO          (AR5315_DSLBASE + 0x0090)
+#define AR5315_GPIO_CR          (AR5315_DSLBASE + 0x0098)
+#define AR5315_GPIO_INT         (AR5315_DSLBASE + 0x00a0)
+*/
+
+#define GPIO_CR_M(x)                (1 << (x))                  //mask for i/o
+#define GPIO_CR_O(x)                (1 << (x))                  //output 
+#define GPIO_CR_I(x)                (0 << (x))                   //input 
+
+
+/*
+#define AR5315_RESET_GPIO       5
+#define AR5315_NUM_GPIO         22
+*/
+        
+static void cleanup_proc(void);
+        
+//The buffer used to store the data returned by the proc file
+static char procfs_buffer[PROCFS_MAX_SIZE];
+static unsigned long procfs_buffer_size = 0;
+
+
+static int gpio_proc_read(char *buf, char **start, off_t offset, 
+                           int len, int *eof, void *data)
+{
+        u32 reg=0;
+        
+        if ( (unsigned int) data & GPIO_IN)
+            reg = sysRegRead(AR5315_GPIO_DI);
+        if ( (unsigned int) data & GPIO_OUT)
+            reg = sysRegRead(AR5315_GPIO_DO);
+        if ( (unsigned int) data & GPIO_DIR)
+            reg = sysRegRead(AR5315_GPIO_CR);
+            
+        //printk (KERN_NOTICE "gpio_proc: read: value of reg ... %#08X   .. value of data %#08X\n",
+        //                                                                    reg,(unsigned int)data);
+            
+        if ( GPIO_CR_M( ((unsigned int)data) & PIN_MASK ) & reg)
+            buf[0]='1';
+        else
+            buf[0]='0';
+        buf[1]=0;
+        
+        *eof = 1;
+        
+        return(2);
+
+ }
+
+static int gpio_proc_info_read(char *buf, char **start, off_t offset, 
+                           int len, int *eof, void *data)
+{
+        *eof = 1;
+        return (
+                sprintf(buf,"GPIO_IN   %#08X \nGPIO_OUT  %#08X \nGPIO_DIR  %#08X \n",                
+                sysRegRead(AR5315_GPIO_DI),
+                sysRegRead(AR5315_GPIO_DO),
+                sysRegRead(AR5315_GPIO_CR)
+                        ));
+ }
+  
+ 
+static int gpio_proc_write(struct file *file, const char *buffer, unsigned long count,
+                    void *data)
+{
+    u32 reg=0;
+    
+    /* get buffer size */
+    procfs_buffer_size = count;
+    if (procfs_buffer_size > PROCFS_MAX_SIZE ) {
+            procfs_buffer_size = PROCFS_MAX_SIZE;
+            }
+    /* write data to the buffer */
+    if ( copy_from_user(procfs_buffer, buffer, procfs_buffer_size) ) {
+            return -EFAULT;
+            }
+        
+    procfs_buffer[procfs_buffer_size]=0;
+    //printk (KERN_NOTICE "you wrote \"%c\" to GPIO %i\n",procfs_buffer[0], ((int)data) & 0xff );
+    
+    //printk (KERN_NOTICE "GPIO PROCID %#08X\n",(int) data );
+    
+    if ( (unsigned int) data & GPIO_IN)
+        reg = sysRegRead(AR5315_GPIO_DI);
+    if ( (unsigned int) data & GPIO_OUT)
+        reg = sysRegRead(AR5315_GPIO_DO);
+    if ( (unsigned int) data & GPIO_DIR)
+        reg = sysRegRead(AR5315_GPIO_CR);
+        
+    //printk (KERN_NOTICE "value before ... %#08X\n",reg);
+    
+    if (procfs_buffer[0]=='0' || procfs_buffer[0]=='i')
+        reg = reg & ~( GPIO_CR_M( ((unsigned int)data) & PIN_MASK ) );
+    if (procfs_buffer[0]=='1' || procfs_buffer[0]=='o')
+        reg = reg  | GPIO_CR_M( ((unsigned int)data) & PIN_MASK ) ;
+
+    //printk (KERN_NOTICE ".. and after write %#08X \n",reg);
+    
+    if ( (unsigned int) data & GPIO_IN)    {
+        sysRegWrite(AR5315_GPIO_DI,reg);
+        (void)sysRegRead(AR5315_GPIO_DI); /* flush write to hardware */
+        }
+    if ( (unsigned int) data & GPIO_OUT) {
+        sysRegWrite(AR5315_GPIO_DO,reg);
+        (void)sysRegRead(AR5315_GPIO_DO); /* flush write to hardware */
+        }
+    if ( (unsigned int) data & GPIO_DIR) {
+        sysRegWrite(AR5315_GPIO_CR,reg);
+        (void)sysRegRead(AR5315_GPIO_CR); /* flush write to hardware */
+        }
+        
+    return procfs_buffer_size;
+}
+ 
+static __init int register_proc(void)
+{
+         unsigned char i,flag=0;
+         char  proc_name[16];
+         
+         /* create directory gpio*/
+        gpio_dir = proc_mkdir("gpio", NULL);
+        if(gpio_dir == NULL) 
+            goto fault;
+        gpio_dir->owner = THIS_MODULE;
+         
+        for (i=0; i < AR5315_NUM_GPIO * 3; i++) //create for every GPIO "x_in"," x_out" and "x_dir"
+        {
+            if ( i / AR5315_NUM_GPIO ==0){
+                flag=GPIO_IN;
+                sprintf(proc_name,"%i_in",i);
+                }
+            if ( i / AR5315_NUM_GPIO ==1){
+                flag=GPIO_OUT;
+                sprintf(proc_name,"%i_out",i % AR5315_NUM_GPIO);
+                }
+            if ( i / AR5315_NUM_GPIO ==2){
+                flag=GPIO_DIR;
+                sprintf(proc_name,"%i_dir",i % AR5315_NUM_GPIO);
+                }
+                
+            proc_gpio = create_proc_entry(proc_name, S_IRUGO, gpio_dir);
+            if (proc_gpio)    {
+                proc_gpio->read_proc = gpio_proc_read;
+                proc_gpio->write_proc = gpio_proc_write;
+                proc_gpio->owner = THIS_MODULE;
+                proc_gpio->data =( (i % AR5315_NUM_GPIO) | flag);
+                } else
+                goto fault;
+                
+        }
+        
+        proc_gpio = create_proc_entry("info", S_IRUGO, gpio_dir);
+            if (proc_gpio)    {
+                proc_gpio->read_proc = gpio_proc_info_read;
+                proc_gpio->owner = THIS_MODULE;
+                } else
+                goto fault;    
+        
+        printk (KERN_NOTICE "gpio_proc: module loaded and /proc/gpio/ created\n");
+            return 0;
+        
+        fault:
+            cleanup_proc();
+            return -EFAULT;    
+}
+
+static void cleanup_proc(void)
+{
+    unsigned char i;
+    char  proc_name[16];
+    
+    for (i=0;i<AR5315_NUM_GPIO;i++)
+    {
+        sprintf(proc_name,"%i_in",i);
+        remove_proc_entry(proc_name,gpio_dir);
+        sprintf(proc_name,"%i_out",i);
+        remove_proc_entry(proc_name,gpio_dir);
+        sprintf(proc_name,"%i_dir",i);
+        remove_proc_entry(proc_name,gpio_dir);
+    }
+    remove_proc_entry("info",gpio_dir);
+    remove_proc_entry("gpio", NULL);
+    printk(KERN_INFO "gpio_proc: unloaded and /proc/gpio/ removed\n");
+    
+}
+
+
+module_init(register_proc);
+module_exit(cleanup_proc);
+
+MODULE_AUTHOR("olg");
+MODULE_DESCRIPTION("AR5315 GPIO pins in /proc/gpio/");
+MODULE_LICENSE("GPL");

Property changes on: utils/proc_gpio/src/proc_gpio.c
___________________________________________________________________
Name: svn:executable
   + *

Index: utils/proc_gpio/src/Makefile
===================================================================
--- utils/proc_gpio/src/Makefile    (revision 0)
+++ utils/proc_gpio/src/Makefile    (revision 0)
@@ -0,0 +1,19 @@
+# $Id$
+#
+# Makefile for switch driver
+#
+# Copyright (C) 2005 Felix Fietkau <nbd@openwrt.org>
+#
+# 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.
+#
+
+obj-m    := proc_gpio.o
+
+ifeq ($(MAKING_MODULES),1)
+#export-objs := switch-core.o
+
+-include $(TOPDIR)/Rules.make
+endif

Property changes on: utils/proc_gpio/src/Makefile
___________________________________________________________________
Name: svn:executable
   + *

Index: utils/proc_gpio/Makefile
===================================================================
--- utils/proc_gpio/Makefile    (revision 0)
+++ utils/proc_gpio/Makefile    (revision 0)
@@ -0,0 +1,51 @@
+# 
+# Copyright (C) 2007 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+# $Id:$
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=kmod-gpio
+PKG_RELEASE:=1
+
+PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/kmod-gpio
+  SECTION:=kernel
+  CATEGORY:=Kernel drivers
+  DEPENDS:=@LINUX_2_6_ATHEROS||LINUX_2_4_AR531X
+  TITLE:=kmod-gpio
+  DESCRIPTION:= proc_gpio: maps the AR5315 GPIO pins in /proc/gpio/
+  VERSION:=$(LINUX_VERSION)-$(BOARD)-$(PKG_RELEASE)
+endef
+
+define Build/Prepare
+    mkdir -p $(PKG_BUILD_DIR)
+    $(CP) ./src/* $(PKG_BUILD_DIR)/
+endef
+
+define Build/Compile
+    $(MAKE) -C "$(LINUX_DIR)" \
+        CROSS_COMPILE="$(TARGET_CROSS)" \
+        ARCH="$(LINUX_KARCH)" \
+        SUBDIRS="$(PKG_BUILD_DIR)" \
+        EXTRA_CFLAGS="-I$(LINUX_DIR)/arch/mips/atheros" \
+        modules
+endef
+    
+define Package/kmod-gpio/install
+    $(INSTALL_DIR) $(1)/lib/modules/$(LINUX_VERSION)
+    $(CP) $(PKG_BUILD_DIR)/*.$(LINUX_KMOD_SUFFIX) \
+        $(1)/lib/modules/$(LINUX_VERSION)
+#    $(INSTALL_DIR) $(1)/lib/network/
+    $(INSTALL_DIR) $(1)/etc/modules.d/
+    printf 'proc_gpio\n' > $(1)/etc/modules.d/80-gpio
+endef
+
+$(eval $(call BuildPackage,kmod-gpio))

Property changes on: utils/proc_gpio/Makefile
___________________________________________________________________
Name: svn:executable
   + *

How is it going with the SDIO guys?

Is it possible to include this module in the atheros build so we can make the wlan light on fonera work ?

GPIO:
Hello, i tried to use what i think is this module ( although its trough a 2 days old DD-Wrt instead of openWrt ), and
the content of /proc/gpio seems really weird, here is a few lines of an ls -l /proc/gpio for illustration...

-r--r--r--    1 root     root            0 Mar  4 19:45 0_dir
-r--r--r--    1 root     root            0 Mar  4 19:45 0_dir
-r--r--r--    1 root     root            0 Mar  4 19:45 0_dir
-r--r--r--    1 root     root            0 Mar  4 19:45 0_in
-r--r--r--    1 root     root            0 Mar  4 19:45 0_out
-r--r--r--    1 root     root            0 Mar  4 19:45 0_out
-r--r--r--    1 root     root            0 Mar  4 19:45 0_out

Pins 0 to 6 have all the same problem, while 7 to 21 have only the '_in' device ...
any hint ?

I2C :
Also : look like some people where interested by trying to use I2C devices trough fonera's gpio port, any progress done here ? I was thinking to use something based on drivers/i2c/busses/i2c-ixp2000.c, is this a good idea ?

Thanks in advance ...

Hm,
I've got no idea what went wrong there.
Does cat /proc/gpio/info work?
What happens on
cat /proc/gpio/0_dir
or
cat /proc/gpio/0_in
?

> Does cat /proc/gpio/info work?
Mmh, here it is :

/proc/gpio # cat info
GPIO_IN   0X7FFF20
GPIO_OUT  0X000024
GPIO_DIR  0X000024

> What happens on
> cat /proc/gpio/0_dir

# cat /proc/gpio0_dir
0

> What happens on
> cat /proc/gpio/0_in

# cat /proc/gpio/0_in
0

Dunno if it can help : I'm using wifi, which makes the WAN led blinking, and i see the bit 2 changing state with the LED if i repeat the cat command ...

# cat /proc/gpio/info
GPIO_IN   0X7FFF20
GPIO_OUT 0X000020
GPIO_DIR  0X000024

Strange  : if i try to display the WAN led status directly ( 2_out ) the value stays to 0 ...

Finally, the following strange behavior :
# cat /proc/gpio/?_in
0000010011

# cat /proc/gpio/?_out
0000000000000000000000

# cat /proc/gpio/?_dir
0000000000000000000000

(Last edited by XavierB on 6 Mar 2007, 23:47)

XavierB wrote:

I'm using wifi, which makes the WAN led blinking, and i see the bit 2 changing state with the LED if i repeat the cat command ...

What do you mean ?
Tried: sysctl -w dev.wifi0.ledpin=1
          sysctl -w dev.wifi0.softled=1
but is not working...

Well, i meant that when the WAN led blinks due to network trafic, i can see the corresponding bit changing state by repeating the "cat info" command:

Seems that
GPIO_OUT  = 0X000024 when the LED is on,
and GPIO_OUT = 0X000020 when the light is off     ( or reverse, cannot tell... )

I juste retried to be sure : look at GPIO_OUT value

/proc/gpio # cat info
GPIO_IN   0X7FFF20
GPIO_OUT  0X000020
GPIO_DIR  0X000024

/proc/gpio # cat info
GPIO_IN   0X7FFF20
GPIO_OUT  0X000024
GPIO_DIR  0X000024

The thing is that
But issuing a "cat 2_out" always shows the value 0.

Ok I understand now, but I'm trying to make the WLAN led work on wlan traffic on fonera...

entering 'dev.wifi0.softled=1' in sysctl.conf bricked my router as it's now constantly rebooting...

any solution ?

(Last edited by intrax on 9 Mar 2007, 13:57)

Hi all.

I have been testing the speed of gpio module on the fonera with this program:

#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>

int main(void)
{
        FILE *fichero;
        int numero;
        struct timeval tv,tv2;
        struct timezone tz;

        if((fichero=fopen("/proc/gpio/2_dir","w"))!=NULL)
        {
                fprintf(fichero,"1");
                fclose(fichero);
                for(numero=0;numero<10;numero++)
                {
                        fichero=NULL;
                        gettimeofday(&tv, &tz);
                        if((fichero=fopen("/proc/gpio/2_out","w"))!=NULL)
                        {
                                fprintf(fichero,(numero % 2)?"1":"0");
                                fclose(fichero);
                        }
                        gettimeofday(&tv2, &tz);
                        printf("%d seconds %d microseconds\n",tv2.tv_sec - tv.tv_sec,tv2.tv_usec - tv.tv_usec);
                }
                puts("I finished");
        }
}

The results have been:

root@OpenWrt:~# ./lanled
0 seconds 558 microseconds
0 seconds 518 microseconds
0 seconds 469 microseconds
0 seconds 471 microseconds
0 seconds 466 microseconds
0 seconds 471 microseconds
0 seconds 471 microseconds
0 seconds 476 microseconds
0 seconds 470 microseconds
0 seconds 492 microseconds
I finished

How can I achieve only a few microseconds (about 4 or less) for use it in i2c protocol or read & write MMC cards?

Thanks in advance. Regards.

I suspect you will have to put it in the kernel.

First of all, put it into the kernel AND do not use print statements. You need to hook it up to a scope to get the hertz. Print statements will take up way too much time.

Thank you for your answers. But before trying it from a kernel space program, could I access to the memory directly from a user space program for improve response times?.

Can I use

extern void ar531x_gpio_ctrl_output(int gpio);
extern void ar531x_gpio_ctrl_input(int gpio);
extern void ar531x_gpio_set(int gpio, int val);
extern int  ar531x_gpio_get(int gpio);

from a normal program.

(Last edited by sistemasorp on 28 Mar 2007, 16:43)

Why isnt GPIO working any more? It worked for the first time after insmod proc_gpio.ko but after restart I only get: "-ash: /tmp: Permission denied" when I want to switch GPIO1 on (wlan led).

there is a bug in the ipk for 2.4 kernel: the module srcipt calls proc-gpio instead of proc_gpio

olg,

Would it be possible to port this to a kernel module and have calls to the driver for speed purposes and porting of various sd-mmc drivers?

... hmm, I dont think this is the way to go, because it would be terrible slow. But im trying to port some very powerful driver class to work with the GPIO pins (the SDIO stack from Atheros), which would also include MMC functionallity, but there are some mean bugs to fix...

Some dmesg appetizer for you:

 
SDIO Memory Function: Probe - enter
SDIO Memory Function: Probe - MMC Card Type Match (MANF:0x6, OEMID:0x0)
SDIO Memory Function: Probe - creating instance
SDIO Memory Function Instance: 0x805E7000
 Card Flags:   0x1
 Card RCA:     0x0
 Oper Clock:   19500000 Hz
 Max Clock:    19500000 Hz
 Oper BlklenLim:  512 bytes
 Max  BlkLen:     512 bytes
 Oper BlksLim:    512 blocks per trans
 Max  Blks:       2048 blocks per trans
SDIO Memory: Write Max Curr: 80 mA, Read Max Curr: 80 mA
SDIO Memory: Allocating Slot current: 80 mA
SDIO Memory Function: Probe - adding instance
SDIO Memory Function: ViewCardCSD
  CSD version: 1.2
  spec version: 3.1-3.31
  File format: Hard disk-like file system with partition table
  Max write block: 512
  partial write not allowed:
  write speed R2W_FACTOR: 256
  Max read block: 512
  partial read allowed:
  C_SIZE/C_SIZE_MULT: 1959/4
  capacity: 62720K
  writable media- perm:0 temp:0
SDIO Memory Function: Probe - creating disk
+SDIO Memory Function: CreateDisk
SDIO Memory Function: block size 512
SDIO Memory Function: setting block size 512
SDIO Memory Function: CreateDisk: size 124928 (Size 62720, FileSysBlockSize 512)
devfs_mk_dir: invalid argument.<4>devfs_mk_dev: could not append to parent for /disc
+SDIO Memory Function: Open
-SDIO Memory Function: Open
 sdmem0:<1>+SDIO Memory Function: DiskRequest
SDIO pRequest->buffer = 80c3d000
SDIO Memory Function: MemoryTransfer reading, Offset:0 Length:4096
SDIO Memory Function: ReadBlocks reading, count/size length 8/512 4096 cmd: 18
-SDIO Memory Function: DiskRequest
 p1
devfs_mk_dev: could not append to parent for /part1
+SDIO Memory Function: Release
-SDIO Memory Function: Release
-SDIO Memory Function: CreateDisk major: 254, minors: 8, first_minor: 0
-SDIO Memory Function: CreateDisk

.. but please do not get impatient smile
olg

Maybe you can share what you've got so far...

More eyes to look at it...

I agree, this is the better way to go.

Not to sound extremely noobish here, but does anyone have an actual listing of where each gpio pin is located on the physical fonera board and whether they are used currently or not? I finally got this kernel module to compile completely and install on the fonera without a hitch and did the wlan led test to be sure it works. I'm aiming to use these gpio pins primarily as basic relay triggers for switching some hefty DC loads so it'd be nice to see what I have available to work with.

Thanks. smile

Is it possible to set more than one gpio pin with one command in a shell script?

Hi,

i managed to get mmc working on the fonera using a homebrew driver, SDIO seemed way to bloated :-)
here is some stuff to drool on ...

root@OpenWrt:/# /etc/init.d/mmc
mmc : MMC Driver for Fonera Version 2.5 (050507) -- '2B|!2B' (john@phrozen.org)
mmc_drv.ko : response : 1
mmc : Card Found
mmc : card in op mode
mmc : SIZE : 220, nMUL : 6, COUNT : 3809, NAME : SEC
mmc : Card Initialised
mmc : The inserted card has a capacity of 499253248 Bytes
mmc : adding disk
mmc: mmc1
mmc : Card was Found
root@OpenWrt:/# mount -t vfat /dev/mmc0 /mnt/ -o noatime,sync
root@OpenWrt:/# df
Filesystem           1k-blocks      Used Available Use% Mounted on
/dev/mtdblock1            7168      3360      3808  47% /
tmpfs                      512         0       512   0% /dev
/dev/mmc0               975040    158208    816832  16% /mnt
root@OpenWrt:/# ls /mnt/
D1.mp3                               kvenyl_mix_dez_05.mp3
The Doors - 01 - The Changeling.mp3  m.mp3
The Doors - 02 - Love Her Madly.mp3  o.mp3
fimageSaneLX416.zip                  q.mp3
fimageSaneMCM.zip
root@OpenWrt:/#

the driver reaches a throughput on writing of about 50k/sec and reading about 160k/sec
the code has been used by me for a long time in other embedded linux projects, so i consider it rather stable.

i am now packaging it into a ipk and will put the link to the source and ipk here in a bit :-)

John

Nice!! Do you have to do any mods to the Pull down resistors or caps on the board?

I just tried this driver and I have problems. Everything with fine with installation but I don't get the following messages:

mmc : MMC Driver for Fonera Version 2.5 (050507) -- '2B|!2B' (john@phrozen.org)
mmc_drv.ko : response : 1
mmc : Card Found
mmc : card in op mode
mmc : SIZE : 220, nMUL : 6, COUNT : 3809, NAME : SEC
mmc : Card Initialised
mmc : The inserted card has a capacity of 499253248 Bytes
mmc : adding disk
mmc: mmc1
mmc : Card was Found

I just get the first line:

mmc : MMC Driver for Fonera Version 2.5 (050507) -- '2B|!2B' (john@phrozen.org)

Also, when I rmmod mmc_drv, I get a seg fault.

The discussion might have continued from here.