convert brcm-2.4 to the new target structure
[openwrt/staging/florian.git] / target / linux / brcm-2.4 / files / arch / mips / bcm947xx / gpio.c
diff --git a/target/linux/brcm-2.4/files/arch/mips/bcm947xx/gpio.c b/target/linux/brcm-2.4/files/arch/mips/bcm947xx/gpio.c
new file mode 100644 (file)
index 0000000..c31f58b
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * GPIO char driver
+ *
+ * Copyright 2005, Broadcom Corporation
+ * All Rights Reserved.
+ * 
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ * $Id$
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+
+#include <typedefs.h>
+#include <osl.h>
+#include <bcmutils.h>
+#include <sbutils.h>
+#include <bcmdevs.h>
+
+static sb_t *gpio_sbh;
+static int gpio_major;
+static devfs_handle_t gpio_dir;
+static struct {
+       char *name;
+       devfs_handle_t handle;
+} gpio_file[] = {
+       { "in", NULL },
+       { "out", NULL },
+       { "outen", NULL },
+       { "control", NULL }
+};
+
+static int
+gpio_open(struct inode *inode, struct file * file)
+{
+       if (MINOR(inode->i_rdev) > ARRAYSIZE(gpio_file))
+               return -ENODEV;
+
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+static int
+gpio_release(struct inode *inode, struct file * file)
+{
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+static ssize_t
+gpio_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+       u32 val;
+
+       switch (MINOR(file->f_dentry->d_inode->i_rdev)) {
+       case 0:
+               val = sb_gpioin(gpio_sbh);
+               break;
+       case 1:
+               val = sb_gpioout(gpio_sbh, 0, 0, GPIO_DRV_PRIORITY);
+               break;
+       case 2:
+               val = sb_gpioouten(gpio_sbh, 0, 0, GPIO_DRV_PRIORITY);
+               break;
+       case 3:
+               val = sb_gpiocontrol(gpio_sbh, 0, 0, GPIO_DRV_PRIORITY);
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       if (put_user(val, (u32 *) buf))
+               return -EFAULT;
+
+       return sizeof(val);
+}
+
+static ssize_t
+gpio_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+       u32 val;
+
+       if (get_user(val, (u32 *) buf))
+               return -EFAULT;
+
+       switch (MINOR(file->f_dentry->d_inode->i_rdev)) {
+       case 0:
+               return -EACCES;
+       case 1:
+               sb_gpioout(gpio_sbh, ~0, val, GPIO_DRV_PRIORITY);
+               break;
+       case 2:
+               sb_gpioouten(gpio_sbh, ~0, val, GPIO_DRV_PRIORITY);
+               break;
+       case 3:
+               sb_gpiocontrol(gpio_sbh, ~0, val, GPIO_DRV_PRIORITY);
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       return sizeof(val);
+}
+
+static struct file_operations gpio_fops = {
+       owner:          THIS_MODULE,
+       open:           gpio_open,
+       release:        gpio_release,
+       read:           gpio_read,
+       write:          gpio_write,
+};
+
+static int __init
+gpio_init(void)
+{
+       int i;
+
+       if (!(gpio_sbh = sb_kattach()))
+               return -ENODEV;
+
+       sb_gpiosetcore(gpio_sbh);
+
+       if ((gpio_major = devfs_register_chrdev(0, "gpio", &gpio_fops)) < 0)
+               return gpio_major;
+
+       gpio_dir = devfs_mk_dir(NULL, "gpio", NULL);
+
+       for (i = 0; i < ARRAYSIZE(gpio_file); i++) {
+               gpio_file[i].handle = devfs_register(gpio_dir,
+                                                    gpio_file[i].name,
+                                                    DEVFS_FL_DEFAULT, gpio_major, i,
+                                                    S_IFCHR | S_IRUGO | S_IWUGO,
+                                                    &gpio_fops, NULL);
+       }
+
+       return 0;
+}
+
+static void __exit
+gpio_exit(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAYSIZE(gpio_file); i++)
+               devfs_unregister(gpio_file[i].handle);
+       devfs_unregister(gpio_dir);
+       devfs_unregister_chrdev(gpio_major, "gpio");
+       sb_detach(gpio_sbh);
+}
+
+module_init(gpio_init);
+module_exit(gpio_exit);