aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm-2.4/files/arch/mips/bcm947xx/gpio.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm-2.4/files/arch/mips/bcm947xx/gpio.c')
-rw-r--r--target/linux/brcm-2.4/files/arch/mips/bcm947xx/gpio.c159
1 files changed, 159 insertions, 0 deletions
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
index 0000000000..c31f58bac6
--- /dev/null
+++ b/target/linux/brcm-2.4/files/arch/mips/bcm947xx/gpio.c
@@ -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);