mirror of
https://github.com/torvalds/linux.git
synced 2024-12-29 14:21:47 +00:00
a81ecc1631
Cc: stable@vger.kernel.org Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
179 lines
3.6 KiB
C
179 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/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));
|
|
}
|