| Gabor Juhos | 6eae43c | 2011-01-04 21:28:15 +0100 | [diff] [blame] | 1 | /* | 
 | 2 |  *  Atheros AR71XX/AR724X/AR913X GPIO API support | 
 | 3 |  * | 
| Gabor Juhos | 5b5b544 | 2012-03-14 10:45:23 +0100 | [diff] [blame] | 4 |  *  Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> | 
 | 5 |  *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> | 
| Gabor Juhos | 6eae43c | 2011-01-04 21:28:15 +0100 | [diff] [blame] | 6 |  *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | 
 | 7 |  * | 
| Gabor Juhos | 5b5b544 | 2012-03-14 10:45:23 +0100 | [diff] [blame] | 8 |  *  Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP | 
 | 9 |  * | 
| Gabor Juhos | 6eae43c | 2011-01-04 21:28:15 +0100 | [diff] [blame] | 10 |  *  This program is free software; you can redistribute it and/or modify it | 
 | 11 |  *  under the terms of the GNU General Public License version 2 as published | 
 | 12 |  *  by the Free Software Foundation. | 
 | 13 |  */ | 
 | 14 |  | 
 | 15 | #include <linux/kernel.h> | 
 | 16 | #include <linux/init.h> | 
 | 17 | #include <linux/module.h> | 
 | 18 | #include <linux/types.h> | 
 | 19 | #include <linux/spinlock.h> | 
 | 20 | #include <linux/io.h> | 
 | 21 | #include <linux/ioport.h> | 
 | 22 | #include <linux/gpio.h> | 
 | 23 |  | 
 | 24 | #include <asm/mach-ath79/ar71xx_regs.h> | 
 | 25 | #include <asm/mach-ath79/ath79.h> | 
 | 26 | #include "common.h" | 
 | 27 |  | 
 | 28 | static void __iomem *ath79_gpio_base; | 
 | 29 | static unsigned long ath79_gpio_count; | 
 | 30 | static DEFINE_SPINLOCK(ath79_gpio_lock); | 
 | 31 |  | 
 | 32 | static void __ath79_gpio_set_value(unsigned gpio, int value) | 
 | 33 | { | 
 | 34 | 	void __iomem *base = ath79_gpio_base; | 
 | 35 |  | 
 | 36 | 	if (value) | 
 | 37 | 		__raw_writel(1 << gpio, base + AR71XX_GPIO_REG_SET); | 
 | 38 | 	else | 
 | 39 | 		__raw_writel(1 << gpio, base + AR71XX_GPIO_REG_CLEAR); | 
 | 40 | } | 
 | 41 |  | 
 | 42 | static int __ath79_gpio_get_value(unsigned gpio) | 
 | 43 | { | 
 | 44 | 	return (__raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_IN) >> gpio) & 1; | 
 | 45 | } | 
 | 46 |  | 
 | 47 | static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned offset) | 
 | 48 | { | 
 | 49 | 	return __ath79_gpio_get_value(offset); | 
 | 50 | } | 
 | 51 |  | 
 | 52 | static void ath79_gpio_set_value(struct gpio_chip *chip, | 
 | 53 | 				  unsigned offset, int value) | 
 | 54 | { | 
 | 55 | 	__ath79_gpio_set_value(offset, value); | 
 | 56 | } | 
 | 57 |  | 
 | 58 | static int ath79_gpio_direction_input(struct gpio_chip *chip, | 
 | 59 | 				       unsigned offset) | 
 | 60 | { | 
 | 61 | 	void __iomem *base = ath79_gpio_base; | 
 | 62 | 	unsigned long flags; | 
 | 63 |  | 
 | 64 | 	spin_lock_irqsave(&ath79_gpio_lock, flags); | 
 | 65 |  | 
 | 66 | 	__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset), | 
 | 67 | 		     base + AR71XX_GPIO_REG_OE); | 
 | 68 |  | 
 | 69 | 	spin_unlock_irqrestore(&ath79_gpio_lock, flags); | 
 | 70 |  | 
 | 71 | 	return 0; | 
 | 72 | } | 
 | 73 |  | 
 | 74 | static int ath79_gpio_direction_output(struct gpio_chip *chip, | 
 | 75 | 					unsigned offset, int value) | 
 | 76 | { | 
 | 77 | 	void __iomem *base = ath79_gpio_base; | 
 | 78 | 	unsigned long flags; | 
 | 79 |  | 
 | 80 | 	spin_lock_irqsave(&ath79_gpio_lock, flags); | 
 | 81 |  | 
 | 82 | 	if (value) | 
 | 83 | 		__raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET); | 
 | 84 | 	else | 
 | 85 | 		__raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR); | 
 | 86 |  | 
 | 87 | 	__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset), | 
 | 88 | 		     base + AR71XX_GPIO_REG_OE); | 
 | 89 |  | 
 | 90 | 	spin_unlock_irqrestore(&ath79_gpio_lock, flags); | 
 | 91 |  | 
 | 92 | 	return 0; | 
 | 93 | } | 
 | 94 |  | 
| Gabor Juhos | 5b5b544 | 2012-03-14 10:45:23 +0100 | [diff] [blame] | 95 | static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | 
 | 96 | { | 
 | 97 | 	void __iomem *base = ath79_gpio_base; | 
 | 98 | 	unsigned long flags; | 
 | 99 |  | 
 | 100 | 	spin_lock_irqsave(&ath79_gpio_lock, flags); | 
 | 101 |  | 
 | 102 | 	__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset), | 
 | 103 | 		     base + AR71XX_GPIO_REG_OE); | 
 | 104 |  | 
 | 105 | 	spin_unlock_irqrestore(&ath79_gpio_lock, flags); | 
 | 106 |  | 
 | 107 | 	return 0; | 
 | 108 | } | 
 | 109 |  | 
 | 110 | static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset, | 
 | 111 | 					int value) | 
 | 112 | { | 
 | 113 | 	void __iomem *base = ath79_gpio_base; | 
 | 114 | 	unsigned long flags; | 
 | 115 |  | 
 | 116 | 	spin_lock_irqsave(&ath79_gpio_lock, flags); | 
 | 117 |  | 
 | 118 | 	if (value) | 
 | 119 | 		__raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET); | 
 | 120 | 	else | 
 | 121 | 		__raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR); | 
 | 122 |  | 
 | 123 | 	__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset), | 
 | 124 | 		     base + AR71XX_GPIO_REG_OE); | 
 | 125 |  | 
 | 126 | 	spin_unlock_irqrestore(&ath79_gpio_lock, flags); | 
 | 127 |  | 
 | 128 | 	return 0; | 
 | 129 | } | 
 | 130 |  | 
| Gabor Juhos | 6eae43c | 2011-01-04 21:28:15 +0100 | [diff] [blame] | 131 | static struct gpio_chip ath79_gpio_chip = { | 
 | 132 | 	.label			= "ath79", | 
 | 133 | 	.get			= ath79_gpio_get_value, | 
 | 134 | 	.set			= ath79_gpio_set_value, | 
 | 135 | 	.direction_input	= ath79_gpio_direction_input, | 
 | 136 | 	.direction_output	= ath79_gpio_direction_output, | 
 | 137 | 	.base			= 0, | 
 | 138 | }; | 
 | 139 |  | 
 | 140 | void ath79_gpio_function_enable(u32 mask) | 
 | 141 | { | 
 | 142 | 	void __iomem *base = ath79_gpio_base; | 
 | 143 | 	unsigned long flags; | 
 | 144 |  | 
 | 145 | 	spin_lock_irqsave(&ath79_gpio_lock, flags); | 
 | 146 |  | 
 | 147 | 	__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) | mask, | 
 | 148 | 		     base + AR71XX_GPIO_REG_FUNC); | 
 | 149 | 	/* flush write */ | 
 | 150 | 	__raw_readl(base + AR71XX_GPIO_REG_FUNC); | 
 | 151 |  | 
 | 152 | 	spin_unlock_irqrestore(&ath79_gpio_lock, flags); | 
 | 153 | } | 
 | 154 |  | 
 | 155 | void ath79_gpio_function_disable(u32 mask) | 
 | 156 | { | 
 | 157 | 	void __iomem *base = ath79_gpio_base; | 
 | 158 | 	unsigned long flags; | 
 | 159 |  | 
 | 160 | 	spin_lock_irqsave(&ath79_gpio_lock, flags); | 
 | 161 |  | 
 | 162 | 	__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~mask, | 
 | 163 | 		     base + AR71XX_GPIO_REG_FUNC); | 
 | 164 | 	/* flush write */ | 
 | 165 | 	__raw_readl(base + AR71XX_GPIO_REG_FUNC); | 
 | 166 |  | 
 | 167 | 	spin_unlock_irqrestore(&ath79_gpio_lock, flags); | 
 | 168 | } | 
 | 169 |  | 
 | 170 | void ath79_gpio_function_setup(u32 set, u32 clear) | 
 | 171 | { | 
 | 172 | 	void __iomem *base = ath79_gpio_base; | 
 | 173 | 	unsigned long flags; | 
 | 174 |  | 
 | 175 | 	spin_lock_irqsave(&ath79_gpio_lock, flags); | 
 | 176 |  | 
 | 177 | 	__raw_writel((__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~clear) | set, | 
 | 178 | 		     base + AR71XX_GPIO_REG_FUNC); | 
 | 179 | 	/* flush write */ | 
 | 180 | 	__raw_readl(base + AR71XX_GPIO_REG_FUNC); | 
 | 181 |  | 
 | 182 | 	spin_unlock_irqrestore(&ath79_gpio_lock, flags); | 
 | 183 | } | 
 | 184 |  | 
 | 185 | void __init ath79_gpio_init(void) | 
 | 186 | { | 
 | 187 | 	int err; | 
 | 188 |  | 
 | 189 | 	if (soc_is_ar71xx()) | 
 | 190 | 		ath79_gpio_count = AR71XX_GPIO_COUNT; | 
| Gabor Juhos | b4da14a | 2012-08-04 18:01:24 +0200 | [diff] [blame] | 191 | 	else if (soc_is_ar7240()) | 
 | 192 | 		ath79_gpio_count = AR7240_GPIO_COUNT; | 
 | 193 | 	else if (soc_is_ar7241() || soc_is_ar7242()) | 
 | 194 | 		ath79_gpio_count = AR7241_GPIO_COUNT; | 
| Gabor Juhos | 6eae43c | 2011-01-04 21:28:15 +0100 | [diff] [blame] | 195 | 	else if (soc_is_ar913x()) | 
 | 196 | 		ath79_gpio_count = AR913X_GPIO_COUNT; | 
| Gabor Juhos | fdfbcf4 | 2011-06-20 21:26:07 +0200 | [diff] [blame] | 197 | 	else if (soc_is_ar933x()) | 
 | 198 | 		ath79_gpio_count = AR933X_GPIO_COUNT; | 
| Gabor Juhos | 5b5b544 | 2012-03-14 10:45:23 +0100 | [diff] [blame] | 199 | 	else if (soc_is_ar934x()) | 
 | 200 | 		ath79_gpio_count = AR934X_GPIO_COUNT; | 
| Gabor Juhos | 6eae43c | 2011-01-04 21:28:15 +0100 | [diff] [blame] | 201 | 	else | 
 | 202 | 		BUG(); | 
 | 203 |  | 
 | 204 | 	ath79_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE); | 
 | 205 | 	ath79_gpio_chip.ngpio = ath79_gpio_count; | 
| Gabor Juhos | 5b5b544 | 2012-03-14 10:45:23 +0100 | [diff] [blame] | 206 | 	if (soc_is_ar934x()) { | 
 | 207 | 		ath79_gpio_chip.direction_input = ar934x_gpio_direction_input; | 
 | 208 | 		ath79_gpio_chip.direction_output = ar934x_gpio_direction_output; | 
 | 209 | 	} | 
| Gabor Juhos | 6eae43c | 2011-01-04 21:28:15 +0100 | [diff] [blame] | 210 |  | 
 | 211 | 	err = gpiochip_add(&ath79_gpio_chip); | 
 | 212 | 	if (err) | 
 | 213 | 		panic("cannot add AR71xx GPIO chip, error=%d", err); | 
 | 214 | } | 
 | 215 |  | 
 | 216 | int gpio_get_value(unsigned gpio) | 
 | 217 | { | 
 | 218 | 	if (gpio < ath79_gpio_count) | 
 | 219 | 		return __ath79_gpio_get_value(gpio); | 
 | 220 |  | 
 | 221 | 	return __gpio_get_value(gpio); | 
 | 222 | } | 
 | 223 | EXPORT_SYMBOL(gpio_get_value); | 
 | 224 |  | 
 | 225 | void gpio_set_value(unsigned gpio, int value) | 
 | 226 | { | 
 | 227 | 	if (gpio < ath79_gpio_count) | 
 | 228 | 		__ath79_gpio_set_value(gpio, value); | 
 | 229 | 	else | 
 | 230 | 		__gpio_set_value(gpio, value); | 
 | 231 | } | 
 | 232 | EXPORT_SYMBOL(gpio_set_value); | 
 | 233 |  | 
 | 234 | int gpio_to_irq(unsigned gpio) | 
 | 235 | { | 
 | 236 | 	/* FIXME */ | 
 | 237 | 	return -EINVAL; | 
 | 238 | } | 
 | 239 | EXPORT_SYMBOL(gpio_to_irq); | 
 | 240 |  | 
 | 241 | int irq_to_gpio(unsigned irq) | 
 | 242 | { | 
 | 243 | 	/* FIXME */ | 
 | 244 | 	return -EINVAL; | 
 | 245 | } | 
 | 246 | EXPORT_SYMBOL(irq_to_gpio); |