Index: linux-2.6.27/drivers/char/Kconfig =================================================================== --- linux-2.6.27.orig/drivers/char/Kconfig +++ linux-2.6.27/drivers/char/Kconfig @@ -1014,6 +1014,24 @@ config GPIO_VR41XX tristate "NEC VR4100 series General-purpose I/O Unit support" depends on CPU_VR41XX +config GPIO_MPC8313 + tristate "mpc8313e gpio" + depends on PPC_MPC831x + select INPUT + default y + help + Give userspace access to the GPIO pins on the MPC8313E devices. + +config EXIO_MPC8313 + tristate "mpc8313e exio" + depends on PPC_MPC831x + select INPUT + select LEDS_CLASS + default y + help + Give userspace access to the Extenrder IO pins on the CPE board. + + config RAW_DRIVER tristate "RAW driver (/dev/raw/rawN)" depends on BLOCK Index: linux-2.6.27/drivers/char/Makefile =================================================================== --- linux-2.6.27.orig/drivers/char/Makefile +++ linux-2.6.27/drivers/char/Makefile @@ -109,6 +109,8 @@ obj-$(CONFIG_TCG_TPM) += tpm/ obj-$(CONFIG_PS3_FLASH) += ps3flash.o obj-$(CONFIG_JS_RTC) += js-rtc.o +obj-$(CONFIG_GPIO_MPC8313) += mpc8313e_gpio.o +obj-$(CONFIG_EXIO_MPC8313) += mpc8313e_exio.o js-rtc-y = rtc.o # Files generated that shall be removed upon make clean Index: linux-2.6.27/drivers/char/mpc8313e_exio.c =================================================================== --- /dev/null +++ linux-2.6.27/drivers/char/mpc8313e_exio.c @@ -0,0 +1,240 @@ +/* +* CPE Extender io driver +* +* Copyright (C) 2007, CenoSYS (www.cenosys.com). +* +* Alexandre Coffignal +* Sylvain Giroudon +* +* This software program is licensed subject to the GNU General Public License +* (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html +* +* Allows a user space process to control the EXIO pins. +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char module_name[] = "exio"; + + +#define NB_EXIO 8 +#define DEFAULT_STATE 0x58 +#define EXIO_BASE 0xfa000000 +#define EXIO_SIZE 0x2 +#define EXIO_LED_MASK 0x01 + +static int major = 0; +static u8 exio_state = DEFAULT_STATE; +static void *exio_io = NULL; +static struct resource *exio_mem = NULL; +static struct class * exio_class = NULL; + + +static void +exio_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + if ( value ) + exio_state &= ~EXIO_LED_MASK; + else + exio_state |= EXIO_LED_MASK; + + iowrite8(exio_state, exio_io); +} + +static struct led_classdev exio_led = { + .name = "boc:blue:status", + .brightness_set = exio_led_set, +}; + +static inline int +exio_led_init(void) +{ + return led_classdev_register(NULL, &exio_led); +} + + +static inline void +exio_led_exit(void) +{ + led_classdev_unregister(&exio_led); +} + + +static inline void +exio_led_suspend(void) +{ + led_classdev_suspend(&exio_led); +} + + +static inline void +exio_led_resume(void) +{ + led_classdev_resume(&exio_led); +} + + +static ssize_t exio_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) +{ + unsigned m = iminor(file->f_path.dentry->d_inode); + size_t i; + char mask; + int err = 0; + + for (i = 0; i < len; ++i) { + char c; + if (get_user(c, data + i)) + return -EFAULT; + + mask=(1<<(7-m)); + switch (c) { + case '0': + /*Clear exio level */ + exio_state&=~mask; + iowrite8(exio_state, exio_io); + break; + case '1': + /*Set exio level */ + exio_state|=mask; + iowrite8(exio_state, exio_io); + break; + default: + printk(KERN_DEBUG "exio%2d bad setting: chr<0x%2x>\n", + m, (int)c); + err++; + } + } + if (err) + return -EINVAL; + + return len; +} + + +static ssize_t exio_read(struct file *file, char __user * buf, + size_t len, loff_t * ppos) +{ + unsigned m = iminor(file->f_path.dentry->d_inode); + int value; + char mask; + char state=ioread8(exio_io); + + mask=(1<<(7-m)); + value=state&mask; + if (put_user(value ? '1' : '0', buf)) + return -EFAULT; + return 1; + +} + +static int exio_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int exio_close(struct inode *inode, struct file *file) +{ + printk(KERN_DEBUG "close()\n"); + return 0; +} + +struct file_operations exio_fops = +{ + .owner = THIS_MODULE, + .read = exio_read, + .write = exio_write, + .open = exio_open, + .release = exio_close /* correspond a close */ +}; + + +static void exio_cleanup(void) +{ + if ( exio_mem ) + release_mem_region(EXIO_BASE, EXIO_SIZE); + exio_mem = NULL; + exio_io = NULL; + + if ( exio_class ) + class_destroy(exio_class); + exio_class = NULL; + + unregister_chrdev(major, module_name); +} + + +static int __init exio_init(void) +{ + int rc, i; + + rc = register_chrdev(major, module_name, &exio_fops); + if ( rc < 0 ) + return rc; + + if ( major == 0 ) { + major = rc; /* accept dynamic major number */ + printk(KERN_INFO "%s: successfully loaded with major %d\n",module_name, major); + } + + exio_class = class_create(THIS_MODULE, "exio"); + if ( exio_class == NULL ) + goto out_cleanup; + + for (i = 0; i < NB_EXIO; i++) { + device_create(exio_class, NULL, MKDEV(major, i) ,NULL, "exio%i", i); + } + + /* System I/O Configuration Register Low */ + exio_mem = request_mem_region(EXIO_BASE, EXIO_SIZE, "exio"); + if ( exio_mem == NULL ) + goto out_cleanup; + + exio_io = ioremap(EXIO_BASE, EXIO_SIZE); + if ( exio_io == NULL ) + goto out_cleanup; + + /* Output default exio state */ + iowrite8(exio_state, exio_io); + + /* Register led class entry for driving the Status led */ + exio_led_init(); + + return 0; + +out_cleanup: + exio_cleanup(); + return -ENOMEM; +} + +static void __exit exio_exit(void) +{ + /* Unregister Status led */ + exio_led_exit(); + + /* Cleanup all other gears */ + exio_cleanup(); +} + + +module_param(major, int, 0644); +MODULE_PARM_DESC(major, "Static major number (none = dynamic)"); +MODULE_AUTHOR("Alexandre Coffignal "); +MODULE_DESCRIPTION("boc01 exio management"); +MODULE_LICENSE("GPL"); + +module_init(exio_init); +module_exit(exio_exit); + + Index: linux-2.6.27/drivers/char/mpc8313e_gpio.c =================================================================== --- /dev/null +++ linux-2.6.27/drivers/char/mpc8313e_gpio.c @@ -0,0 +1,148 @@ +/* +* mpc8313e gpio driver +* +* +* Copyright (C) 2007, CenoSYS (www.cenosys.com). +* Alexandre Coffignal +* alexandre.coffignal@cenosys.com +* +* This software program is licensed subject to the GNU General Public License +* (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html +* +* Allows a user space process to control the GPIO pins. +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char module_name[] = "gpio"; +#define NB_GPIO 8 +static int major = 0; +struct gpio { + __be32 gpdir; + __be32 gpodr; + __be32 gpdat; + __be32 gpier; + __be32 gpimr; + __be32 gpicr; +} __attribute__ ((packed)); +static struct gpio *gpio_regs; + +static ssize_t mpc8313e_gpio_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) +{ + unsigned m = iminor(file->f_path.dentry->d_inode); + size_t i; + int err = 0; + + for (i = 0; i < len; ++i) { + char c; + if (get_user(c, data + i)) + return -EFAULT; + /* set GPIO as output */ + setbits32(&gpio_regs->gpdir, 1 << (31 - m)); + clrbits32(&gpio_regs->gpodr, 1 << (31 - m)); + switch (c) { + case '0': + /*Set GPIO level */ + clrbits32(&gpio_regs->gpdat, 1 << (31 - m)); + break; + case '1': + /*Set GPIO level */ + setbits32(&gpio_regs->gpdat, 1 << (31 - m)); + break; + default: + printk(KERN_DEBUG "io%2d bad setting: chr<0x%2x>\n", + m, (int)c); + err++; + } + } + if (err) + return -EINVAL; + + return len; +} + +static ssize_t mpc8313e_gpio_read(struct file *file, char __user * buf, size_t len, loff_t * ppos) +{ + unsigned m = iminor(file->f_path.dentry->d_inode); + int value; + value=in_be32(&gpio_regs->gpdat)&(1 << (31 - m)); + if (put_user(value ? '1' : '0', buf)) + return -EFAULT; + return 1; + + +} + + + +static int mpc8313e_gpio_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int mpc8313e_gpio_close(struct inode *inode, struct file *file) +{ + return 0; +} + +struct file_operations mpc8313e_gpio_fops = +{ + .owner = THIS_MODULE, + .read = mpc8313e_gpio_read, + .write = mpc8313e_gpio_write, + .open = mpc8313e_gpio_open, + .release = mpc8313e_gpio_close +}; +static struct class * gpio_class; +static int __init mpc8313e_gpio_init(void) +{ + int rc,i; + + rc = register_chrdev(major, module_name, &mpc8313e_gpio_fops); + if (rc < 0) { + return rc; + } + + if (major == 0) { + major = rc; /* accept dynamic major number */ + printk(KERN_INFO "%s: successfully loaded with major %d\n",module_name, major); + + } + gpio_class = class_create(THIS_MODULE, "gpio"); + + for (i = 0; i < NB_GPIO; i++) + { + device_create(gpio_class, NULL, MKDEV(major, i) ,NULL, "gpio%d",i); + + } + + /* System I/O Configuration Register Low */ + gpio_regs = ioremap(get_immrbase() + 0xc00, 0x20); + if (!gpio_regs) + return -ENOMEM; + return 0; +} + +static void __exit mpc8313e_gpio_cleanup(void) +{ + unregister_chrdev(major, module_name); +} +module_param(major, int, 0644); +MODULE_PARM_DESC(major, "Static major number (none = dynamic)"); +MODULE_AUTHOR("Alexandre Coffignal "); +MODULE_DESCRIPTION("mpc8313e GPIO"); +MODULE_LICENSE("GPL"); + +module_init(mpc8313e_gpio_init); +module_exit(mpc8313e_gpio_cleanup); + +