--- a/arch/arm/mach-cns3xxx/cns3420vb.c +++ b/arch/arm/mach-cns3xxx/cns3420vb.c @@ -216,7 +216,7 @@ static struct map_desc cns3420_io_desc[] static void __init cns3420_map_io(void) { - cns3xxx_map_io(); + cns3xxx_common_init(); iotable_init(cns3420_io_desc, ARRAY_SIZE(cns3420_io_desc)); cns3420_early_serial_setup(); --- a/arch/arm/mach-cns3xxx/core.c +++ b/arch/arm/mach-cns3xxx/core.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "core.h" @@ -72,12 +73,73 @@ static struct map_desc cns3xxx_io_desc[] }, }; -void __init cns3xxx_map_io(void) +static inline void gpio_line_config(u8 line, u32 direction) +{ + u32 reg; + if (direction) { + if (line < 32) { + reg = __raw_readl(CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_DIR); + reg |= (1 << line); + __raw_writel(reg, CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_DIR); + } else { + reg = __raw_readl(CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_DIR); + reg |= (1 << (line - 32)); + __raw_writel(reg, CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_DIR); + } + } else { + if (line < 32) { + reg = __raw_readl(CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_DIR); + reg &= ~(1 << line); + __raw_writel(reg, CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_DIR); + } else { + reg = __raw_readl(CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_DIR); + reg &= ~(1 << (line - 32)); + __raw_writel(reg, CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_DIR); + } + } +} + +static int cns3xxx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + gpio_line_config(gpio, CNS3XXX_GPIO_IN); + return 0; +} + +static int cns3xxx_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int level) +{ + gpio_line_set(gpio, level); + gpio_line_config(gpio, CNS3XXX_GPIO_OUT); + return 0; +} + +static int cns3xxx_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +{ + return gpio_get_value(gpio); +} + +static void cns3xxx_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value) +{ + gpio_set_value(gpio, value); +} + +static struct gpio_chip cns3xxx_gpio_chip = { + .label = "CNS3XXX_GPIO_CHIP", + .direction_input = cns3xxx_gpio_direction_input, + .direction_output = cns3xxx_gpio_direction_output, + .get = cns3xxx_gpio_get_value, + .set = cns3xxx_gpio_set_value, + .base = 0, + .ngpio = 64, +}; + +void __init cns3xxx_common_init(void) { #ifdef CONFIG_LOCAL_TIMERS twd_base = (void __iomem *) CNS3XXX_TC11MP_TWD_BASE_VIRT; #endif iotable_init(cns3xxx_io_desc, ARRAY_SIZE(cns3xxx_io_desc)); + + gpiochip_add(&cns3xxx_gpio_chip); } /* used by entry-macro.S */ --- a/arch/arm/mach-cns3xxx/core.h +++ b/arch/arm/mach-cns3xxx/core.h @@ -21,7 +21,7 @@ void __init cns3xxx_l2x0_init(void); static inline void cns3xxx_l2x0_init(void) {} #endif /* CONFIG_CACHE_L2X0 */ -void __init cns3xxx_map_io(void); +void __init cns3xxx_common_init(void); void __init cns3xxx_init_irq(void); void cns3xxx_power_off(void); void cns3xxx_restart(char, const char *); --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -366,6 +366,7 @@ config ARCH_CLPS711X config ARCH_CNS3XXX bool "Cavium Networks CNS3XXX family" select CPU_V6K + select ARCH_WANT_OPTIONAL_GPIOLIB select GENERIC_CLOCKEVENTS select ARM_GIC select CLKDEV_LOOKUP --- /dev/null +++ b/arch/arm/mach-cns3xxx/include/mach/gpio.h @@ -0,0 +1,98 @@ +/* + * arch/arm/mach-cns3xxx/include/mach/gpio.h + * + * CNS3xxx GPIO wrappers for arch-neutral GPIO calls + * + * Copyright 2011 Gateworks Corporation + * Chris Lang + * + * Based on IXP implementation by Milan Svoboda + * Based on PXA implementation by Philipp Zabel + * + * 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, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ASM_ARCH_CNS3XXX_GPIO_H +#define __ASM_ARCH_CNS3XXX_GPIO_H + +#include +#include +#include +#include /* cansleep wrappers */ + +#define NR_BUILTIN_GPIO 64 + +#define CNS3XXX_GPIO_IN 0x0 +#define CNS3XXX_GPIO_OUT 0x1 + +#define CNS3XXX_GPIO_LO 0 +#define CNS3XXX_GPIO_HI 1 + +#define CNS3XXX_GPIO_OUTPUT 0x00 +#define CNS3XXX_GPIO_INPUT 0x04 +#define CNS3XXX_GPIO_DIR 0x08 +#define CNS3XXX_GPIO_SET 0x10 +#define CNS3XXX_GPIO_CLEAR 0x14 + +static inline void gpio_line_get(u8 line, int *value) +{ + if (line < 32) + *value = ((__raw_readl(CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_INPUT) >> line) & 0x1); + else + *value = ((__raw_readl(CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_INPUT) >> (line - 32)) & 0x1); +} + +static inline void gpio_line_set(u8 line, int value) +{ + if (line < 32) { + if (value) + __raw_writel((1 << line), CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_SET); + else + __raw_writel((1 << line), CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_CLEAR); + } else { + if (value) + __raw_writel((1 << line), CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_SET); + else + __raw_writel((1 << line), CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_CLEAR); + } +} + +static inline int gpio_get_value(unsigned gpio) +{ + if (gpio < NR_BUILTIN_GPIO) + { + int value; + gpio_line_get(gpio, &value); + return value; + } + else + return __gpio_get_value(gpio); +} + +static inline void gpio_set_value(unsigned gpio, int value) +{ + if (gpio < NR_BUILTIN_GPIO) + gpio_line_set(gpio, value); + else + __gpio_set_value(gpio, value); +} + +#define gpio_cansleep __gpio_cansleep + +extern int gpio_to_irq(int gpio); +extern int irq_to_gpio(int gpio); + +#endif