174 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *  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/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_read(char *buf, char **start, off_t offset, 
 | |
|                           int len, int *unused_i, void *unused_v)
 | |
| {
 | |
| 	int c,outlen;
 | |
| 	static const char port_name[]="123456789ABCDEFGH";
 | |
| 	outlen = 0;
 | |
| 	for (c = 0; c < MAX_PORT; c++) {
 | |
| 		if (ddrs[c] == NULL)
 | |
| 			continue ;
 | |
| 		len = sprintf(buf,"P%c: %s\n",port_name[c],port_status(c));
 | |
| 		buf += len;
 | |
| 		outlen += len;
 | |
| 	}
 | |
| 	return outlen;
 | |
| }
 | |
| 
 | |
| static __init int register_proc(void)
 | |
| {
 | |
| 	struct proc_dir_entry *proc_gpio;
 | |
| 
 | |
| 	proc_gpio = create_proc_entry("gpio", S_IRUGO, NULL);
 | |
| 	if (proc_gpio) 
 | |
| 		proc_gpio->read_proc = gpio_proc_read;
 | |
| 	return proc_gpio != NULL;
 | |
| }
 | |
| 
 | |
| __initcall(register_proc);
 | |
| #endif
 | |
| 
 | |
| void __init h8300_gpio_init(void)
 | |
| {
 | |
| 	memcpy(gpio_regs,_platform_gpio_table(sizeof(gpio_regs)),sizeof(gpio_regs));
 | |
| }
 |