gpio: add ARM Primcell pl061 support
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
This commit is contained in:
parent
695b8b49f5
commit
e554bfa6ce
|
@ -6,6 +6,12 @@ if GPIOLIB
|
||||||
|
|
||||||
menu "GPIO "
|
menu "GPIO "
|
||||||
|
|
||||||
|
config GPIO_PL061
|
||||||
|
bool "PrimeCell PL061 GPIO support"
|
||||||
|
depends on ARM_AMBA
|
||||||
|
help
|
||||||
|
Say yes here to support the PrimeCell PL061 GPIO device
|
||||||
|
|
||||||
config GPIO_STMPE
|
config GPIO_STMPE
|
||||||
depends on I2C_STMPE
|
depends on I2C_STMPE
|
||||||
bool "STMPE GPIO Expander"
|
bool "STMPE GPIO Expander"
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
obj-$(CONFIG_GPIOLIB) += gpio.o
|
obj-$(CONFIG_GPIOLIB) += gpio.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
|
||||||
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
|
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2008, 2009 Provigent Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Driver for the ARM PrimeCell(tm) General Purpose Input/Output (PL061)
|
||||||
|
*
|
||||||
|
* Data sheet: ARM DDI 0190B, September 2000
|
||||||
|
*/
|
||||||
|
#include <common.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <io.h>
|
||||||
|
#include <gpio.h>
|
||||||
|
#include <init.h>
|
||||||
|
|
||||||
|
#include <linux/amba/bus.h>
|
||||||
|
#include <linux/amba/pl061.h>
|
||||||
|
|
||||||
|
#define GPIODIR 0x400
|
||||||
|
#define GPIOIS 0x404
|
||||||
|
#define GPIOIBE 0x408
|
||||||
|
#define GPIOIEV 0x40C
|
||||||
|
#define GPIOIE 0x410
|
||||||
|
#define GPIORIS 0x414
|
||||||
|
#define GPIOMIS 0x418
|
||||||
|
#define GPIOIC 0x41C
|
||||||
|
|
||||||
|
#define PL061_GPIO_NR 8
|
||||||
|
|
||||||
|
struct pl061_gpio {
|
||||||
|
void __iomem *base;
|
||||||
|
struct gpio_chip gc;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
|
||||||
|
{
|
||||||
|
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
|
||||||
|
unsigned char gpiodir;
|
||||||
|
|
||||||
|
if (offset >= gc->ngpio)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
gpiodir = readb(chip->base + GPIODIR);
|
||||||
|
gpiodir &= ~(1 << offset);
|
||||||
|
writeb(gpiodir, chip->base + GPIODIR);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
|
||||||
|
int value)
|
||||||
|
{
|
||||||
|
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
|
||||||
|
unsigned char gpiodir;
|
||||||
|
|
||||||
|
if (offset >= gc->ngpio)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
writeb(!!value << offset, chip->base + (1 << (offset + 2)));
|
||||||
|
gpiodir = readb(chip->base + GPIODIR);
|
||||||
|
gpiodir |= 1 << offset;
|
||||||
|
writeb(gpiodir, chip->base + GPIODIR);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gpio value is set again, because pl061 doesn't allow to set value of
|
||||||
|
* a gpio pin before configuring it in OUT mode.
|
||||||
|
*/
|
||||||
|
writeb(!!value << offset, chip->base + (1 << (offset + 2)));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pl061_get_value(struct gpio_chip *gc, unsigned offset)
|
||||||
|
{
|
||||||
|
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
|
||||||
|
|
||||||
|
return !!readb(chip->base + (1 << (offset + 2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value)
|
||||||
|
{
|
||||||
|
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
|
||||||
|
|
||||||
|
writeb(!!value << offset, chip->base + (1 << (offset + 2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct gpio_ops pl061_gpio_ops = {
|
||||||
|
.direction_input = pl061_direction_input,
|
||||||
|
.direction_output = pl061_direction_output,
|
||||||
|
.get = pl061_get_value,
|
||||||
|
.set = pl061_set_value,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
|
||||||
|
{
|
||||||
|
struct pl061_platform_data *pdata;
|
||||||
|
struct pl061_gpio *chip;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
chip = xzalloc(sizeof(*chip));
|
||||||
|
|
||||||
|
pdata = dev->dev.platform_data;
|
||||||
|
if (pdata) {
|
||||||
|
chip->gc.base = pdata->gpio_base;
|
||||||
|
} else {
|
||||||
|
chip->gc.base = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
chip->base = amba_get_mem_region(dev);
|
||||||
|
|
||||||
|
chip->gc.ops = &pl061_gpio_ops;
|
||||||
|
chip->gc.ngpio = PL061_GPIO_NR;
|
||||||
|
chip->gc.dev = &dev->dev;
|
||||||
|
|
||||||
|
ret = gpiochip_add(&chip->gc);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&dev->dev, "couldn't add gpiochip, ret = %d\n", ret);
|
||||||
|
goto free_mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeb(0, chip->base + GPIOIE); /* disable irqs */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
free_mem:
|
||||||
|
kfree(chip);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct amba_id pl061_ids[] = {
|
||||||
|
{
|
||||||
|
.id = 0x00041061,
|
||||||
|
.mask = 0x000fffff,
|
||||||
|
},
|
||||||
|
{ 0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct amba_driver pl061_gpio_driver = {
|
||||||
|
.drv = {
|
||||||
|
.name = "pl061_gpio",
|
||||||
|
},
|
||||||
|
.id_table = pl061_ids,
|
||||||
|
.probe = pl061_probe,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init pl061_gpio_init(void)
|
||||||
|
{
|
||||||
|
return amba_driver_register(&pl061_gpio_driver);
|
||||||
|
}
|
||||||
|
coredevice_initcall(pl061_gpio_init);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
|
||||||
|
MODULE_DESCRIPTION("PL061 GPIO driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,12 @@
|
||||||
|
#ifndef __AMBA_PL061_H__
|
||||||
|
#define __AMBA_PL061_H__
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
/* platform data for the PL061 GPIO driver */
|
||||||
|
|
||||||
|
struct pl061_platform_data {
|
||||||
|
/* number of the first GPIO */
|
||||||
|
unsigned gpio_base;
|
||||||
|
};
|
||||||
|
#endif /* __AMBA_PL061_H__ */
|
Loading…
Reference in New Issue