/* * linux/arch/h8300/kernel/gpio.c * * Yoshinori Sato <ysato@users.sourceforge.jp> * */ /* * Internal I/O Port Management */ #include <linux/stddef.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/fs.h> #include <linux/init.h> #define _(addr) (volatile unsigned char *)(addr) #if defined(CONFIG_H83007) || defined(CONFIG_H83068) #include <asm/regs306x.h> static volatile unsigned char *ddrs[] = { _(P1DDR),_(P2DDR),_(P3DDR),_(P4DDR),_(P5DDR),_(P6DDR), NULL, _(P8DDR),_(P9DDR),_(PADDR),_(PBDDR), }; #define MAX_PORT 11 #endif #if defined(CONFIG_H83002) || defined(CONFIG_H8048) /* Fix me!! */ #include <asm/regs306x.h> static volatile unsigned char *ddrs[] = { _(P1DDR),_(P2DDR),_(P3DDR),_(P4DDR),_(P5DDR),_(P6DDR), NULL, _(P8DDR),_(P9DDR),_(PADDR),_(PBDDR), }; #define MAX_PORT 11 #endif #if defined(CONFIG_H8S2678) #include <asm/regs267x.h> static volatile unsigned char *ddrs[] = { _(P1DDR),_(P2DDR),_(P3DDR),NULL ,_(P5DDR),_(P6DDR), _(P7DDR),_(P8DDR),NULL, _(PADDR),_(PBDDR),_(PCDDR), _(PDDDR),_(PEDDR),_(PFDDR),_(PGDDR),_(PHDDR), _(PADDR),_(PBDDR),_(PCDDR),_(PDDDR),_(PEDDR),_(PFDDR), _(PGDDR),_(PHDDR) }; #define MAX_PORT 17 #endif #undef _ #if !defined(P1DDR) #error Unsuppoted CPU Selection #endif static struct { unsigned char used; unsigned char ddr; } gpio_regs[MAX_PORT]; extern char *_platform_gpio_table(int length); int h8300_reserved_gpio(int port, unsigned int bits) { unsigned char *used; if (port < 0 || port >= MAX_PORT) return -1; used = &(gpio_regs[port].used); if ((*used & bits) != 0) return 0; *used |= bits; return 1; } int h8300_free_gpio(int port, unsigned int bits) { unsigned char *used; if (port < 0 || port >= MAX_PORT) return -1; used = &(gpio_regs[port].used); if ((*used & bits) != bits) return 0; *used &= (~bits); return 1; } int h8300_set_gpio_dir(int port_bit,int dir) { int port = (port_bit >> 8) & 0xff; int bit = port_bit & 0xff; if (ddrs[port] == NULL) return 0; if (gpio_regs[port].used & bit) { if (dir) gpio_regs[port].ddr |= bit; else gpio_regs[port].ddr &= ~bit; *ddrs[port] = gpio_regs[port].ddr; return 1; } else return 0; } int h8300_get_gpio_dir(int port_bit) { int port = (port_bit >> 8) & 0xff; int bit = port_bit & 0xff; if (ddrs[port] == NULL) return 0; if (gpio_regs[port].used & bit) { return (gpio_regs[port].ddr & bit) != 0; } else return -1; } #if defined(CONFIG_PROC_FS) static char *port_status(int portno) { static char result[10]; static const char io[2]={'I','O'}; char *rp; int c; unsigned char used,ddr; used = gpio_regs[portno].used; ddr = gpio_regs[portno].ddr; result[8]='\0'; rp = result + 7; for (c = 8; c > 0; c--,rp--,used >>= 1, ddr >>= 1) if (used & 0x01) *rp = io[ ddr & 0x01]; else *rp = '-'; return result; } static int gpio_proc_show(struct seq_file *m, void *v) { static const char port_name[]="123456789ABCDEFGH"; int c; for (c = 0; c < MAX_PORT; c++) { if (ddrs[c] == NULL) continue; seq_printf(m, "P%c: %s\n", port_name[c], port_status(c)); } return 0; } static int gpio_proc_open(struct inode *inode, struct file *file) { return single_open(file, gpio_proc_show, PDE_DATA(inode)); } static const struct file_operations gpio_proc_fops = { .open = gpio_proc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static __init int register_proc(void) { return proc_create("gpio", S_IRUGO, NULL, &gpio_proc_fops) != NULL; } __initcall(register_proc); #endif void __init h8300_gpio_init(void) { memcpy(gpio_regs,_platform_gpio_table(sizeof(gpio_regs)),sizeof(gpio_regs)); }