| /* linux/arch/arm/plat-s3c24xx/gpiolib.c |
| * |
| * Copyright (c) 2008 Simtec Electronics |
| * http://armlinux.simtec.co.uk/ |
| * Ben Dooks <ben@simtec.co.uk> |
| * |
| * S3C24XX GPIOlib support |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License. |
| */ |
| |
| #include <linux/kernel.h> |
| #include <linux/init.h> |
| #include <linux/module.h> |
| #include <linux/interrupt.h> |
| #include <linux/ioport.h> |
| #include <linux/io.h> |
| #include <linux/gpio.h> |
| |
| #include <mach/hardware.h> |
| #include <asm/irq.h> |
| |
| #include <mach/regs-gpio.h> |
| |
| struct s3c24xx_gpio_chip { |
| struct gpio_chip chip; |
| void __iomem *base; |
| }; |
| |
| static inline struct s3c24xx_gpio_chip *to_s3c_chip(struct gpio_chip *gpc) |
| { |
| return container_of(gpc, struct s3c24xx_gpio_chip, chip); |
| } |
| |
| /* these routines are exported for use by other parts of the platform |
| * and system support, but are not intended to be used directly by the |
| * drivers themsevles. |
| */ |
| |
| static int s3c24xx_gpiolib_input(struct gpio_chip *chip, unsigned offset) |
| { |
| struct s3c24xx_gpio_chip *ourchip = to_s3c_chip(chip); |
| void __iomem *base = ourchip->base; |
| unsigned long flags; |
| unsigned long con; |
| |
| local_irq_save(flags); |
| |
| con = __raw_readl(base + 0x00); |
| con &= ~(3 << (offset * 2)); |
| con |= (S3C2410_GPIO_OUTPUT & 0xf) << (offset * 2); |
| |
| __raw_writel(con, base + 0x00); |
| |
| local_irq_restore(flags); |
| return 0; |
| } |
| |
| static int s3c24xx_gpiolib_output(struct gpio_chip *chip, |
| unsigned offset, int value) |
| { |
| struct s3c24xx_gpio_chip *ourchip = to_s3c_chip(chip); |
| void __iomem *base = ourchip->base; |
| unsigned long flags; |
| unsigned long dat; |
| unsigned long con; |
| |
| local_irq_save(flags); |
| |
| dat = __raw_readl(base + 0x04); |
| dat &= ~(1 << offset); |
| if (value) |
| dat |= 1 << offset; |
| __raw_writel(dat, base + 0x04); |
| |
| con = __raw_readl(base + 0x00); |
| con &= ~(3 << (offset * 2)); |
| con |= (S3C2410_GPIO_OUTPUT & 0xf) << (offset * 2); |
| |
| __raw_writel(con, base + 0x00); |
| __raw_writel(dat, base + 0x04); |
| |
| local_irq_restore(flags); |
| return 0; |
| } |
| |
| static void s3c24xx_gpiolib_set(struct gpio_chip *chip, |
| unsigned offset, int value) |
| { |
| struct s3c24xx_gpio_chip *ourchip = to_s3c_chip(chip); |
| void __iomem *base = ourchip->base; |
| unsigned long flags; |
| unsigned long dat; |
| |
| local_irq_save(flags); |
| |
| dat = __raw_readl(base + 0x04); |
| dat &= ~(1 << offset); |
| if (value) |
| dat |= 1 << offset; |
| __raw_writel(dat, base + 0x04); |
| |
| local_irq_restore(flags); |
| } |
| |
| static int s3c24xx_gpiolib_get(struct gpio_chip *chip, unsigned offset) |
| { |
| struct s3c24xx_gpio_chip *ourchip = to_s3c_chip(chip); |
| unsigned long val; |
| |
| val = __raw_readl(ourchip->base + 0x04); |
| val >>= offset; |
| val &= 1; |
| |
| return val; |
| } |
| |
| static int s3c24xx_gpiolib_banka_input(struct gpio_chip *chip, unsigned offset) |
| { |
| return -EINVAL; |
| } |
| |
| static int s3c24xx_gpiolib_banka_output(struct gpio_chip *chip, |
| unsigned offset, int value) |
| { |
| struct s3c24xx_gpio_chip *ourchip = to_s3c_chip(chip); |
| void __iomem *base = ourchip->base; |
| unsigned long flags; |
| unsigned long dat; |
| unsigned long con; |
| |
| local_irq_save(flags); |
| |
| con = __raw_readl(base + 0x00); |
| dat = __raw_readl(base + 0x04); |
| |
| dat &= ~(1 << offset); |
| if (value) |
| dat |= 1 << offset; |
| |
| __raw_writel(dat, base + 0x04); |
| |
| con &= ~(1 << offset); |
| |
| __raw_writel(con, base + 0x00); |
| __raw_writel(dat, base + 0x04); |
| |
| local_irq_restore(flags); |
| return 0; |
| } |
| |
| static struct s3c24xx_gpio_chip gpios[] = { |
| [0] = { |
| .base = S3C24XX_GPIO_BASE(S3C2410_GPA0), |
| .chip = { |
| .base = S3C2410_GPA0, |
| .owner = THIS_MODULE, |
| .label = "GPIOA", |
| .ngpio = 24, |
| .direction_input = s3c24xx_gpiolib_banka_input, |
| .direction_output = s3c24xx_gpiolib_banka_output, |
| .set = s3c24xx_gpiolib_set, |
| .get = s3c24xx_gpiolib_get, |
| }, |
| }, |
| [1] = { |
| .base = S3C24XX_GPIO_BASE(S3C2410_GPB0), |
| .chip = { |
| .base = S3C2410_GPB0, |
| .owner = THIS_MODULE, |
| .label = "GPIOB", |
| .ngpio = 16, |
| .direction_input = s3c24xx_gpiolib_input, |
| .direction_output = s3c24xx_gpiolib_output, |
| .set = s3c24xx_gpiolib_set, |
| .get = s3c24xx_gpiolib_get, |
| }, |
| }, |
| [2] = { |
| .base = S3C24XX_GPIO_BASE(S3C2410_GPC0), |
| .chip = { |
| .base = S3C2410_GPC0, |
| .owner = THIS_MODULE, |
| .label = "GPIOC", |
| .ngpio = 16, |
| .direction_input = s3c24xx_gpiolib_input, |
| .direction_output = s3c24xx_gpiolib_output, |
| .set = s3c24xx_gpiolib_set, |
| .get = s3c24xx_gpiolib_get, |
| }, |
| }, |
| [3] = { |
| .base = S3C24XX_GPIO_BASE(S3C2410_GPD0), |
| .chip = { |
| .base = S3C2410_GPD0, |
| .owner = THIS_MODULE, |
| .label = "GPIOD", |
| .ngpio = 16, |
| .direction_input = s3c24xx_gpiolib_input, |
| .direction_output = s3c24xx_gpiolib_output, |
| .set = s3c24xx_gpiolib_set, |
| .get = s3c24xx_gpiolib_get, |
| }, |
| }, |
| [4] = { |
| .base = S3C24XX_GPIO_BASE(S3C2410_GPE0), |
| .chip = { |
| .base = S3C2410_GPE0, |
| .label = "GPIOE", |
| .owner = THIS_MODULE, |
| .ngpio = 16, |
| .direction_input = s3c24xx_gpiolib_input, |
| .direction_output = s3c24xx_gpiolib_output, |
| .set = s3c24xx_gpiolib_set, |
| .get = s3c24xx_gpiolib_get, |
| }, |
| }, |
| [5] = { |
| .base = S3C24XX_GPIO_BASE(S3C2410_GPF0), |
| .chip = { |
| .base = S3C2410_GPF0, |
| .owner = THIS_MODULE, |
| .label = "GPIOF", |
| .ngpio = 8, |
| .direction_input = s3c24xx_gpiolib_input, |
| .direction_output = s3c24xx_gpiolib_output, |
| .set = s3c24xx_gpiolib_set, |
| .get = s3c24xx_gpiolib_get, |
| }, |
| }, |
| [6] = { |
| .base = S3C24XX_GPIO_BASE(S3C2410_GPG0), |
| .chip = { |
| .base = S3C2410_GPG0, |
| .owner = THIS_MODULE, |
| .label = "GPIOG", |
| .ngpio = 10, |
| .direction_input = s3c24xx_gpiolib_input, |
| .direction_output = s3c24xx_gpiolib_output, |
| .set = s3c24xx_gpiolib_set, |
| .get = s3c24xx_gpiolib_get, |
| }, |
| }, |
| }; |
| |
| static __init int s3c24xx_gpiolib_init(void) |
| { |
| struct s3c24xx_gpio_chip *chip = gpios; |
| int gpn; |
| |
| for (gpn = 0; gpn < ARRAY_SIZE(gpios); gpn++, chip++) |
| gpiochip_add(&chip->chip); |
| |
| return 0; |
| } |
| |
| arch_initcall(s3c24xx_gpiolib_init); |