#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/export.h>
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/gpio/driver.h>
#include <asm/mach-rc32434/rb.h>
#include <asm/mach-rc32434/gpio.h>
#define GPIOFUNC 0x00
#define GPIOCFG 0x04
#define GPIOD 0x08
#define GPIOILEVEL 0x0C
#define GPIOISTAT 0x10
#define GPIONMIEN 0x14
#define IMASK6 0x38
struct rb532_gpio_chip {
struct gpio_chip chip;
void __iomem *regbase;
};
static inline void rb532_set_bit(unsigned bitval,
unsigned offset, void __iomem *ioaddr)
{
unsigned long flags;
u32 val;
local_irq_save(flags);
val = readl(ioaddr);
val &= ~(!bitval << offset);
val |= (!!bitval << offset);
writel(val, ioaddr);
local_irq_restore(flags);
}
static inline int rb532_get_bit(unsigned offset, void __iomem *ioaddr)
{
return readl(ioaddr) & (1 << offset);
}
static int rb532_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct rb532_gpio_chip *gpch;
gpch = gpiochip_get_data(chip);
return !!rb532_get_bit(offset, gpch->regbase + GPIOD);
}
static int rb532_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct rb532_gpio_chip *gpch;
gpch = gpiochip_get_data(chip);
rb532_set_bit(value, offset, gpch->regbase + GPIOD);
return 0;
}
static int rb532_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
struct rb532_gpio_chip *gpch;
gpch = gpiochip_get_data(chip);
rb532_set_bit(0, offset, gpch->regbase + GPIOFUNC);
rb532_set_bit(0, offset, gpch->regbase + GPIOCFG);
return 0;
}
static int rb532_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
struct rb532_gpio_chip *gpch;
gpch = gpiochip_get_data(chip);
rb532_set_bit(0, offset, gpch->regbase + GPIOFUNC);
rb532_set_bit(value, offset, gpch->regbase + GPIOD);
rb532_set_bit(1, offset, gpch->regbase + GPIOCFG);
return 0;
}
static int rb532_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
{
return 8 + 4 * 32 + gpio;
}
static struct rb532_gpio_chip rb532_gpio_chip[] = {
[0] = {
.chip = {
.label = "gpio0",
.direction_input = rb532_gpio_direction_input,
.direction_output = rb532_gpio_direction_output,
.get = rb532_gpio_get,
.set = rb532_gpio_set,
.to_irq = rb532_gpio_to_irq,
.base = 0,
.ngpio = 32,
},
},
};
void rb532_gpio_set_ilevel(int bit, unsigned gpio)
{
rb532_set_bit(bit, gpio, rb532_gpio_chip->regbase + GPIOILEVEL);
}
EXPORT_SYMBOL(rb532_gpio_set_ilevel);
void rb532_gpio_set_istat(int bit, unsigned gpio)
{
rb532_set_bit(bit, gpio, rb532_gpio_chip->regbase + GPIOISTAT);
}
EXPORT_SYMBOL(rb532_gpio_set_istat);
void rb532_gpio_set_func(unsigned gpio)
{
rb532_set_bit(1, gpio, rb532_gpio_chip->regbase + GPIOFUNC);
}
EXPORT_SYMBOL(rb532_gpio_set_func);
static int rb532_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;
rb532_gpio_chip->regbase = devm_ioremap_resource(dev, res);
if (IS_ERR(rb532_gpio_chip->regbase))
return PTR_ERR(rb532_gpio_chip->regbase);
return devm_gpiochip_add_data(dev, &rb532_gpio_chip->chip, rb532_gpio_chip);
}
static struct platform_driver rb532_gpio_driver = {
.driver = {
.name = "rb532-gpio",
},
.probe = rb532_gpio_probe,
};
static int __init rb532_gpio_init(void)
{
return platform_driver_register(&rb532_gpio_driver);
}
arch_initcall(rb532_gpio_init);