| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- --- /dev/null
- +++ b/drivers/char/gemini_gpio_dev.c
- @@ -0,0 +1,356 @@
- +/*
- + * GPIO driver for Gemini board
- + * Provides /dev/gpio
- + */
- +
- +#include <linux/version.h>
- +#include <linux/kernel.h>
- +#include <linux/module.h>
- +#include <linux/init.h>
- +#include <linux/proc_fs.h>
- +#include <linux/fcntl.h>
- +#include <linux/miscdevice.h>
- +#include <asm/uaccess.h> /* copy_to_user, copy_from_user */
- +
- +#include <asm/hardware.h>
- +#include <asm/io.h>
- +#include <asm/arch/sl2312.h>
- +#include <asm/arch/irqs.h>
- +#include <asm/arch/gemini_gpio.h>
- +
- +#define GEMINI_GPIO_BASE1 IO_ADDRESS(SL2312_GPIO_BASE)
- +#define GEMINI_GPIO_BASE2 IO_ADDRESS(SL2312_GPIO_BASE1)
- +
- +#define GPIO_SET 2
- +#define MAX_GPIO_LINE 32*GPIO_SET
- +
- +wait_queue_head_t gemini_gpio_wait[MAX_GPIO_LINE];
- +
- +enum GPIO_REG
- +{
- + GPIO_DATA_OUT = 0x00,
- + GPIO_DATA_IN = 0x04,
- + GPIO_PIN_DIR = 0x08,
- + GPIO_BY_PASS = 0x0C,
- + GPIO_DATA_SET = 0x10,
- + GPIO_DATA_CLEAR = 0x14,
- + GPIO_PULL_ENABLE = 0x18,
- + GPIO_PULL_TYPE = 0x1C,
- + GPIO_INT_ENABLE = 0x20,
- + GPIO_INT_RAW_STATUS = 0x24,
- + GPIO_INT_MASK_STATUS = 0x28,
- + GPIO_INT_MASK = 0x2C,
- + GPIO_INT_CLEAR = 0x30,
- + GPIO_INT_TRIG = 0x34,
- + GPIO_INT_BOTH = 0x38,
- + GPIO_INT_POLAR = 0x3C
- +};
- +
- +unsigned int regist_gpio_int0=0,regist_gpio_int1=0;
- +
- +/* defines a specific GPIO bit number and state */
- +struct gpio_bit {
- + unsigned char bit;
- + unsigned char state;
- +};
- +
- +#define GPIO_MAJOR 10
- +#define GPIO_MINOR 127
- +
- +/*
- + * ioctl calls that are permitted to the /dev/gpio interface
- + */
- +#define GPIO_GET_BIT 0x0000001
- +#define GPIO_SET_BIT 0x0000002
- +#define GPIO_GET_CONFIG 0x0000003
- +#define GPIO_SET_CONFIG 0x0000004
- +
- +//#define GPIO_CONFIG_OUT 1
- +//#define GPIO_CONFIG_IN 2
- +
- +
- +
- +#define DEVICE_NAME "gpio"
- +
- +//#define DEBUG
- +
- +/*
- + * GPIO interface
- + */
- +
- +/* /dev/gpio */
- +static int gpio_ioctl(struct inode *inode, struct file *file,
- + unsigned int cmd, unsigned long arg);
- +
- +/* /proc/driver/gpio */
- +static int gpio_read_proc(char *page, char **start, off_t off,
- + int count, int *eof, void *data);
- +
- +static unsigned char gpio_status; /* bitmapped status byte. */
- +
- +/* functions for set/get gpio lines on storlink cpu */
- +
- +void gpio_line_get(unsigned char pin, u32 * data)
- +{
- + unsigned int set = pin >>5; // each GPIO set has 32 pins
- + unsigned int status,addr;
- +
- + addr = (set ? GEMINI_GPIO_BASE2:GEMINI_GPIO_BASE1) + GPIO_DATA_IN;
- + status = readl(addr);
- +#ifdef DEBUG
- + printk("status = %08X, pin = %d, set = %d\n", status, pin, set);
- +#endif
- + if (set)
- + *data = (status&(1<<(pin-32)))?1:0;
- + else
- + *data = (status&(1<<pin))?1:0;
- +}
- +
- +void gpio_line_set(unsigned char pin, u32 high)
- +{
- + unsigned char set = pin >>5; // each GPIO set has 32 pins
- + unsigned int status=0,addr;
- +
- + addr = (set ? GEMINI_GPIO_BASE2:GEMINI_GPIO_BASE1)+(high?GPIO_DATA_SET:GPIO_DATA_CLEAR);
- +
- + status &= ~(1 << (pin %32));
- + status |= (1 << (pin % 32));
- + writel(status,addr);
- +}
- +
- +/*
- + * pin = [0..63]
- + * mode =
- + * 1 -- OUT
- + * 2 -- IN
- + */
- +void gpio_line_config(unsigned char pin, unsigned char mode)
- +{
- + unsigned char set = pin >>5; // each GPIO set has 32 pins
- + unsigned int status,addr;
- +
- + addr = (set ? GEMINI_GPIO_BASE2:GEMINI_GPIO_BASE1)+GPIO_PIN_DIR;
- + status = readl(addr);
- +
- + status &= ~(1 << (pin %32));
- + if (mode == 1)
- + status |= (1 << (pin % 32)); /* PinDir: 0 - input, 1 - output */
- +
- + writel(status,addr);
- +#if 0
- + /* enable pullup-high if mode is input */
- +
- + addr = (set ? GEMINI_GPIO_BASE2:GEMINI_GPIO_BASE1)+GPIO_PULL_ENABLE;
- + status = readl(addr);
- +
- + status &= ~(1 << (pin %32));
- + if (mode == 2) /* input */
- + status |= (1 << (pin % 32)); /* PullEnable: 0 - disable, 1 - enable */
- +
- + writel(status,addr);
- +
- + addr = (set ? GEMINI_GPIO_BASE2:GEMINI_GPIO_BASE1)+GPIO_PULL_TYPE;
- + status = readl(addr);
- +
- + status &= ~(1 << (pin %32));
- + if (mode == 2) /* input */
- + status |= (1 << (pin % 32)); /* PullType: 0 - low, 1 - high */
- +
- + writel(status,addr);
- +#endif
- +}
- +
- +#define GPIO_IS_OPEN 0x01 /* means /dev/gpio is in use */
- +
- +/*
- + * Now all the various file operations that we export.
- + */
- +static int gpio_ioctl(struct inode *inode, struct file *file,
- + unsigned int cmd, unsigned long arg)
- +{
- + struct gpio_bit bit;
- + u32 val;
- +
- + if (copy_from_user(&bit, (struct gpio_bit *)arg,
- + sizeof(bit)))
- + return -EFAULT;
- +
- + switch (cmd) {
- +
- + case GPIO_GET_BIT:
- + gpio_line_get(bit.bit, &val);
- + bit.state = val;
- + return copy_to_user((void *)arg, &bit, sizeof(bit)) ? -EFAULT : 0;
- + case GPIO_SET_BIT:
- + val = bit.state;
- + gpio_line_set(bit.bit, val);
- + return 0;
- + case GPIO_GET_CONFIG:
- + // gpio_line_config(bit.bit, bit.state);
- + return copy_to_user((void *)arg, &bit, sizeof(bit)) ? -EFAULT : 0;
- + case GPIO_SET_CONFIG:
- + val = bit.state;
- + gpio_line_config(bit.bit, bit.state);
- + return 0;
- + }
- + return -EINVAL;
- +}
- +
- +
- +static int gpio_open(struct inode *inode, struct file *file)
- +{
- + if (gpio_status & GPIO_IS_OPEN)
- + return -EBUSY;
- +
- + gpio_status |= GPIO_IS_OPEN;
- + return 0;
- +}
- +
- +
- +static int gpio_release(struct inode *inode, struct file *file)
- +{
- + /*
- + * Turn off all interrupts once the device is no longer
- + * in use and clear the data.
- + */
- +
- + gpio_status &= ~GPIO_IS_OPEN;
- + return 0;
- +}
- +
- +
- +/*
- + * The various file operations we support.
- + */
- +
- +static struct file_operations gpio_fops = {
- + .owner = THIS_MODULE,
- + .ioctl = gpio_ioctl,
- + .open = gpio_open,
- + .release = gpio_release,
- +};
- +
- +static struct miscdevice gpio_dev =
- +{
- + .minor = GPIO_MINOR,
- + .name = "gpio",
- + .fops = &gpio_fops,
- +};
- +
- +
- +
- +
- +#ifdef CONFIG_PROC_FS
- +static struct proc_dir_entry *dir;
- +
- +/*
- + * Info exported via "/proc/driver/gpio".
- + */
- +static int gpio_get_status(char *buf)
- +{
- + char *p = buf;
- + u32 val = 0;
- + int i;
- + int bit;
- +#ifdef DEBUG
- + u32 addr;
- +
- + for (i = 0; i < 0x20; i+=4 ) {
- + addr = IO_ADDRESS(SL2312_GPIO_BASE) + i;
- + val = readl(addr);
- + p+=sprintf(p, "GPIO0: 0x%02X: %08X\n", i, val );
- + }
- + for (i = 0; i < 0x20; i+=4 ) {
- + addr = IO_ADDRESS(SL2312_GPIO_BASE1) + i;
- + val = readl(addr);
- + p+=sprintf(p, "GPIO1: 0x%02X: %08X\n", i, val );
- + }
- +#endif
- +
- + for (i = 0; i < 32; i++) {
- + gpio_line_get(i, &bit);
- + if (bit)
- + val |= (1 << i);
- + }
- + p += sprintf(p, "gpio0\t: 0x%08x\n", val);
- +
- + val = 0;
- + for (i = 32; i < 64; i++) {
- + gpio_line_get(i, &bit);
- + if (bit)
- + val |= (1 << i);
- + }
- + p += sprintf(p, "gpio1\t: 0x%08x\n", val);
- +
- + return p - buf;
- +}
- +
- +
- +/* /proc/driver/gpio read op
- + */
- +static int gpio_read_proc(char *page, char **start, off_t off,
- + int count, int *eof, void *data)
- +{
- + int len = gpio_get_status (page);
- +
- + if (len <= off+count)
- + *eof = 1;
- + *start = page + off;
- + len -= off;
- + if ( len > count )
- + len = count;
- + if ( len < 0 )
- + len = 0;
- + return len;
- +}
- +#endif /* CONFIG_PROC_FS */
- +
- +
- +static int __init gpio_init_module(void)
- +{
- + int retval;
- +#ifdef CONFIG_PROC_FS
- + struct proc_dir_entry *res;
- +#endif
- +
- + /* register /dev/gpio file ops */
- + //retval = register_chrdev(GPIO_MAJOR, DEVICE_NAME, &gpio_fops);
- + retval = misc_register(&gpio_dev);
- + if(retval < 0)
- + return retval;
- +
- +#ifdef CONFIG_PROC_FS
- + dir = proc_mkdir("driver/gpio", NULL);
- + if (!dir) {
- + misc_deregister(&gpio_dev);
- + return -ENOMEM;
- + }
- + /* register /proc/driver/gpio */
- + res = create_proc_entry("info", 0644, dir);
- + if (res) {
- + res->read_proc= gpio_read_proc;
- + } else {
- + misc_deregister(&gpio_dev);
- + return -ENOMEM;
- + }
- +#endif
- +
- + printk("%s: GPIO driver loaded\n", __FILE__);
- +
- + return 0;
- +}
- +
- +static void __exit gpio_cleanup_module(void)
- +{
- + remove_proc_entry ("info", dir);
- + misc_deregister(&gpio_dev);
- +
- + printk("%s: GPIO driver unloaded\n", __FILE__);
- +}
- +
- +module_init(gpio_init_module);
- +module_exit(gpio_cleanup_module);
- +
- +MODULE_AUTHOR("Jonas Majauskas");
- +MODULE_LICENSE("GPL");
- +
- --- a/drivers/char/Kconfig
- +++ b/drivers/char/Kconfig
- @@ -1064,5 +1064,12 @@
-
- source "drivers/s390/char/Kconfig"
-
- +config GEMINI_GPIO_DEV
- + tristate "GPIO driver for Gemini board (provides /dev/gpio)"
- + depends on ARCH_SL2312
- + default n
- + help
- + GPIO driver for Gemini boards - SL3512, SL3516.
- +
- endmenu
-
- --- a/drivers/char/Makefile
- +++ b/drivers/char/Makefile
- @@ -115,6 +115,7 @@
-
- obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
- obj-$(CONFIG_TCG_TPM) += tpm/
- +obj-$(CONFIG_GEMINI_GPIO_DEV) += gemini_gpio_dev.o
-
- obj-$(CONFIG_PS3_FLASH) += ps3flash.o
-
|