1/* 2 * Atheros AR71XX/AR724X/AR913X GPIO API support 3 * 4 * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> 5 * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> 6 * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> 7 * 8 * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP 9 * 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 28static void __iomem *ath79_gpio_base; 29static unsigned long ath79_gpio_count; 30static DEFINE_SPINLOCK(ath79_gpio_lock); 31 32static 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 42static int __ath79_gpio_get_value(unsigned gpio) 43{ 44 return (__raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_IN) >> gpio) & 1; 45} 46 47static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned offset) 48{ 49 return __ath79_gpio_get_value(offset); 50} 51 52static void ath79_gpio_set_value(struct gpio_chip *chip, 53 unsigned offset, int value) 54{ 55 __ath79_gpio_set_value(offset, value); 56} 57 58static 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 74static 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 95static 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 110static 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 131static 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 140static void __iomem *ath79_gpio_get_function_reg(void) 141{ 142 u32 reg = 0; 143 144 if (soc_is_ar71xx() || 145 soc_is_ar724x() || 146 soc_is_ar913x() || 147 soc_is_ar933x()) 148 reg = AR71XX_GPIO_REG_FUNC; 149 else if (soc_is_ar934x()) 150 reg = AR934X_GPIO_REG_FUNC; 151 else 152 BUG(); 153 154 return ath79_gpio_base + reg; 155} 156 157void ath79_gpio_function_setup(u32 set, u32 clear) 158{ 159 void __iomem *reg = ath79_gpio_get_function_reg(); 160 unsigned long flags; 161 162 spin_lock_irqsave(&ath79_gpio_lock, flags); 163 164 __raw_writel((__raw_readl(reg) & ~clear) | set, reg); 165 /* flush write */ 166 __raw_readl(reg); 167 168 spin_unlock_irqrestore(&ath79_gpio_lock, flags); 169} 170 171void ath79_gpio_function_enable(u32 mask) 172{ 173 ath79_gpio_function_setup(mask, 0); 174} 175 176void ath79_gpio_function_disable(u32 mask) 177{ 178 ath79_gpio_function_setup(0, mask); 179} 180 181void __init ath79_gpio_init(void) 182{ 183 int err; 184 185 if (soc_is_ar71xx()) 186 ath79_gpio_count = AR71XX_GPIO_COUNT; 187 else if (soc_is_ar7240()) 188 ath79_gpio_count = AR7240_GPIO_COUNT; 189 else if (soc_is_ar7241() || soc_is_ar7242()) 190 ath79_gpio_count = AR7241_GPIO_COUNT; 191 else if (soc_is_ar913x()) 192 ath79_gpio_count = AR913X_GPIO_COUNT; 193 else if (soc_is_ar933x()) 194 ath79_gpio_count = AR933X_GPIO_COUNT; 195 else if (soc_is_ar934x()) 196 ath79_gpio_count = AR934X_GPIO_COUNT; 197 else if (soc_is_qca955x()) 198 ath79_gpio_count = QCA955X_GPIO_COUNT; 199 else 200 BUG(); 201 202 ath79_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE); 203 ath79_gpio_chip.ngpio = ath79_gpio_count; 204 if (soc_is_ar934x() || soc_is_qca955x()) { 205 ath79_gpio_chip.direction_input = ar934x_gpio_direction_input; 206 ath79_gpio_chip.direction_output = ar934x_gpio_direction_output; 207 } 208 209 err = gpiochip_add(&ath79_gpio_chip); 210 if (err) 211 panic("cannot add AR71xx GPIO chip, error=%d", err); 212} 213 214int gpio_get_value(unsigned gpio) 215{ 216 if (gpio < ath79_gpio_count) 217 return __ath79_gpio_get_value(gpio); 218 219 return __gpio_get_value(gpio); 220} 221EXPORT_SYMBOL(gpio_get_value); 222 223void gpio_set_value(unsigned gpio, int value) 224{ 225 if (gpio < ath79_gpio_count) 226 __ath79_gpio_set_value(gpio, value); 227 else 228 __gpio_set_value(gpio, value); 229} 230EXPORT_SYMBOL(gpio_set_value); 231 232int gpio_to_irq(unsigned gpio) 233{ 234 /* FIXME */ 235 return -EINVAL; 236} 237EXPORT_SYMBOL(gpio_to_irq); 238 239int irq_to_gpio(unsigned irq) 240{ 241 /* FIXME */ 242 return -EINVAL; 243} 244EXPORT_SYMBOL(irq_to_gpio); 245