Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: ath79: add GPIOLIB support

This patch implements generic GPIO routines for the built-in
GPIO controllers of the Atheros AR71XX/AR724X/AR913X SoCs.

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: linux-mips@linux-mips.org
Cc: Luis R. Rodriguez <lrodriguez@atheros.com>
Cc: Cliff Holden <Cliff.Holden@Atheros.com>
Cc: Kathy Giori <Kathy.Giori@Atheros.com>
Patchwork: https://patchwork.linux-mips.org/patch/1948/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Gabor Juhos and committed by
Ralf Baechle
6eae43c5 d4a67d9d

+252 -2
+1
arch/mips/Kconfig
··· 68 68 69 69 config ATH79 70 70 bool "Atheros AR71XX/AR724X/AR913X based boards" 71 + select ARCH_REQUIRE_GPIOLIB 71 72 select BOOT_RAW 72 73 select CEVT_R4K 73 74 select CSRC_R4K
+1 -1
arch/mips/ath79/Makefile
··· 8 8 # under the terms of the GNU General Public License version 2 as published 9 9 # by the Free Software Foundation. 10 10 11 - obj-y := prom.o setup.o irq.o common.o clock.o 11 + obj-y := prom.o setup.o irq.o common.o clock.o gpio.o 12 12 13 13 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o 14 14
+5
arch/mips/ath79/common.h
··· 23 23 void ath79_clocks_init(void); 24 24 void ath79_ddr_wb_flush(unsigned int reg); 25 25 26 + void ath79_gpio_function_enable(u32 mask); 27 + void ath79_gpio_function_disable(u32 mask); 28 + void ath79_gpio_function_setup(u32 set, u32 clear); 29 + void ath79_gpio_init(void); 30 + 26 31 #endif /* __ATH79_COMMON_H */
+197
arch/mips/ath79/gpio.c
··· 1 + /* 2 + * Atheros AR71XX/AR724X/AR913X GPIO API support 3 + * 4 + * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> 5 + * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms of the GNU General Public License version 2 as published 9 + * by the Free Software Foundation. 10 + */ 11 + 12 + #include <linux/kernel.h> 13 + #include <linux/init.h> 14 + #include <linux/module.h> 15 + #include <linux/types.h> 16 + #include <linux/spinlock.h> 17 + #include <linux/io.h> 18 + #include <linux/ioport.h> 19 + #include <linux/gpio.h> 20 + 21 + #include <asm/mach-ath79/ar71xx_regs.h> 22 + #include <asm/mach-ath79/ath79.h> 23 + #include "common.h" 24 + 25 + static void __iomem *ath79_gpio_base; 26 + static unsigned long ath79_gpio_count; 27 + static DEFINE_SPINLOCK(ath79_gpio_lock); 28 + 29 + static void __ath79_gpio_set_value(unsigned gpio, int value) 30 + { 31 + void __iomem *base = ath79_gpio_base; 32 + 33 + if (value) 34 + __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_SET); 35 + else 36 + __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_CLEAR); 37 + } 38 + 39 + static int __ath79_gpio_get_value(unsigned gpio) 40 + { 41 + return (__raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_IN) >> gpio) & 1; 42 + } 43 + 44 + static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned offset) 45 + { 46 + return __ath79_gpio_get_value(offset); 47 + } 48 + 49 + static void ath79_gpio_set_value(struct gpio_chip *chip, 50 + unsigned offset, int value) 51 + { 52 + __ath79_gpio_set_value(offset, value); 53 + } 54 + 55 + static int ath79_gpio_direction_input(struct gpio_chip *chip, 56 + unsigned offset) 57 + { 58 + void __iomem *base = ath79_gpio_base; 59 + unsigned long flags; 60 + 61 + spin_lock_irqsave(&ath79_gpio_lock, flags); 62 + 63 + __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset), 64 + base + AR71XX_GPIO_REG_OE); 65 + 66 + spin_unlock_irqrestore(&ath79_gpio_lock, flags); 67 + 68 + return 0; 69 + } 70 + 71 + static int ath79_gpio_direction_output(struct gpio_chip *chip, 72 + unsigned offset, int value) 73 + { 74 + void __iomem *base = ath79_gpio_base; 75 + unsigned long flags; 76 + 77 + spin_lock_irqsave(&ath79_gpio_lock, flags); 78 + 79 + if (value) 80 + __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET); 81 + else 82 + __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR); 83 + 84 + __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset), 85 + base + AR71XX_GPIO_REG_OE); 86 + 87 + spin_unlock_irqrestore(&ath79_gpio_lock, flags); 88 + 89 + return 0; 90 + } 91 + 92 + static struct gpio_chip ath79_gpio_chip = { 93 + .label = "ath79", 94 + .get = ath79_gpio_get_value, 95 + .set = ath79_gpio_set_value, 96 + .direction_input = ath79_gpio_direction_input, 97 + .direction_output = ath79_gpio_direction_output, 98 + .base = 0, 99 + }; 100 + 101 + void ath79_gpio_function_enable(u32 mask) 102 + { 103 + void __iomem *base = ath79_gpio_base; 104 + unsigned long flags; 105 + 106 + spin_lock_irqsave(&ath79_gpio_lock, flags); 107 + 108 + __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) | mask, 109 + base + AR71XX_GPIO_REG_FUNC); 110 + /* flush write */ 111 + __raw_readl(base + AR71XX_GPIO_REG_FUNC); 112 + 113 + spin_unlock_irqrestore(&ath79_gpio_lock, flags); 114 + } 115 + 116 + void ath79_gpio_function_disable(u32 mask) 117 + { 118 + void __iomem *base = ath79_gpio_base; 119 + unsigned long flags; 120 + 121 + spin_lock_irqsave(&ath79_gpio_lock, flags); 122 + 123 + __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~mask, 124 + base + AR71XX_GPIO_REG_FUNC); 125 + /* flush write */ 126 + __raw_readl(base + AR71XX_GPIO_REG_FUNC); 127 + 128 + spin_unlock_irqrestore(&ath79_gpio_lock, flags); 129 + } 130 + 131 + void ath79_gpio_function_setup(u32 set, u32 clear) 132 + { 133 + void __iomem *base = ath79_gpio_base; 134 + unsigned long flags; 135 + 136 + spin_lock_irqsave(&ath79_gpio_lock, flags); 137 + 138 + __raw_writel((__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~clear) | set, 139 + base + AR71XX_GPIO_REG_FUNC); 140 + /* flush write */ 141 + __raw_readl(base + AR71XX_GPIO_REG_FUNC); 142 + 143 + spin_unlock_irqrestore(&ath79_gpio_lock, flags); 144 + } 145 + 146 + void __init ath79_gpio_init(void) 147 + { 148 + int err; 149 + 150 + if (soc_is_ar71xx()) 151 + ath79_gpio_count = AR71XX_GPIO_COUNT; 152 + else if (soc_is_ar724x()) 153 + ath79_gpio_count = AR724X_GPIO_COUNT; 154 + else if (soc_is_ar913x()) 155 + ath79_gpio_count = AR913X_GPIO_COUNT; 156 + else 157 + BUG(); 158 + 159 + ath79_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE); 160 + ath79_gpio_chip.ngpio = ath79_gpio_count; 161 + 162 + err = gpiochip_add(&ath79_gpio_chip); 163 + if (err) 164 + panic("cannot add AR71xx GPIO chip, error=%d", err); 165 + } 166 + 167 + int gpio_get_value(unsigned gpio) 168 + { 169 + if (gpio < ath79_gpio_count) 170 + return __ath79_gpio_get_value(gpio); 171 + 172 + return __gpio_get_value(gpio); 173 + } 174 + EXPORT_SYMBOL(gpio_get_value); 175 + 176 + void gpio_set_value(unsigned gpio, int value) 177 + { 178 + if (gpio < ath79_gpio_count) 179 + __ath79_gpio_set_value(gpio, value); 180 + else 181 + __gpio_set_value(gpio, value); 182 + } 183 + EXPORT_SYMBOL(gpio_set_value); 184 + 185 + int gpio_to_irq(unsigned gpio) 186 + { 187 + /* FIXME */ 188 + return -EINVAL; 189 + } 190 + EXPORT_SYMBOL(gpio_to_irq); 191 + 192 + int irq_to_gpio(unsigned irq) 193 + { 194 + /* FIXME */ 195 + return -EINVAL; 196 + } 197 + EXPORT_SYMBOL(irq_to_gpio);
+1 -1
arch/mips/ath79/setup.c
··· 157 157 AR71XX_RESET_SIZE); 158 158 ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE, 159 159 AR71XX_PLL_SIZE); 160 - 161 160 ath79_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE, 162 161 AR71XX_DDR_CTRL_SIZE); 163 162 ··· 182 183 183 184 static int __init ath79_setup(void) 184 185 { 186 + ath79_gpio_init(); 185 187 ath79_register_uart(); 186 188 return 0; 187 189 }
+21
arch/mips/include/asm/mach-ath79/ar71xx_regs.h
··· 25 25 #define AR71XX_DDR_CTRL_SIZE 0x100 26 26 #define AR71XX_UART_BASE (AR71XX_APB_BASE + 0x00020000) 27 27 #define AR71XX_UART_SIZE 0x100 28 + #define AR71XX_GPIO_BASE (AR71XX_APB_BASE + 0x00040000) 29 + #define AR71XX_GPIO_SIZE 0x100 28 30 #define AR71XX_PLL_BASE (AR71XX_APB_BASE + 0x00050000) 29 31 #define AR71XX_PLL_SIZE 0x100 30 32 #define AR71XX_RESET_BASE (AR71XX_APB_BASE + 0x00060000) ··· 205 203 #define AR71XX_SPI_IOC_CS2 AR71XX_SPI_IOC_CS(2) 206 204 #define AR71XX_SPI_IOC_CS_ALL (AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1 | \ 207 205 AR71XX_SPI_IOC_CS2) 206 + 207 + /* 208 + * GPIO block 209 + */ 210 + #define AR71XX_GPIO_REG_OE 0x00 211 + #define AR71XX_GPIO_REG_IN 0x04 212 + #define AR71XX_GPIO_REG_OUT 0x08 213 + #define AR71XX_GPIO_REG_SET 0x0c 214 + #define AR71XX_GPIO_REG_CLEAR 0x10 215 + #define AR71XX_GPIO_REG_INT_MODE 0x14 216 + #define AR71XX_GPIO_REG_INT_TYPE 0x18 217 + #define AR71XX_GPIO_REG_INT_POLARITY 0x1c 218 + #define AR71XX_GPIO_REG_INT_PENDING 0x20 219 + #define AR71XX_GPIO_REG_INT_ENABLE 0x24 220 + #define AR71XX_GPIO_REG_FUNC 0x28 221 + 222 + #define AR71XX_GPIO_COUNT 16 223 + #define AR724X_GPIO_COUNT 18 224 + #define AR913X_GPIO_COUNT 22 208 225 209 226 #endif /* __ASM_MACH_AR71XX_REGS_H */
+26
arch/mips/include/asm/mach-ath79/gpio.h
··· 1 + /* 2 + * Atheros AR71XX/AR724X/AR913X GPIO API definitions 3 + * 4 + * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> 5 + * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms of the GNU General Public License version 2 as published 9 + * by the Free Software Foundation. 10 + * 11 + */ 12 + 13 + #ifndef __ASM_MACH_ATH79_GPIO_H 14 + #define __ASM_MACH_ATH79_GPIO_H 15 + 16 + #define ARCH_NR_GPIOS 64 17 + #include <asm-generic/gpio.h> 18 + 19 + int gpio_to_irq(unsigned gpio); 20 + int irq_to_gpio(unsigned irq); 21 + int gpio_get_value(unsigned gpio); 22 + void gpio_set_value(unsigned gpio, int value); 23 + 24 + #define gpio_cansleep __gpio_cansleep 25 + 26 + #endif /* __ASM_MACH_ATH79_GPIO_H */