gpio.c (7570B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org> 4 * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org> 5 * Copyright (C) 2009-2010 Florian Fainelli <florian@openwrt.org> 6 */ 7 8#include <linux/init.h> 9#include <linux/export.h> 10#include <linux/gpio.h> 11 12#include <asm/mach-ar7/ar7.h> 13 14#define AR7_GPIO_MAX 32 15#define TITAN_GPIO_MAX 51 16 17struct ar7_gpio_chip { 18 void __iomem *regs; 19 struct gpio_chip chip; 20}; 21 22static int ar7_gpio_get_value(struct gpio_chip *chip, unsigned gpio) 23{ 24 struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); 25 void __iomem *gpio_in = gpch->regs + AR7_GPIO_INPUT; 26 27 return !!(readl(gpio_in) & (1 << gpio)); 28} 29 30static int titan_gpio_get_value(struct gpio_chip *chip, unsigned gpio) 31{ 32 struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); 33 void __iomem *gpio_in0 = gpch->regs + TITAN_GPIO_INPUT_0; 34 void __iomem *gpio_in1 = gpch->regs + TITAN_GPIO_INPUT_1; 35 36 return readl(gpio >> 5 ? gpio_in1 : gpio_in0) & (1 << (gpio & 0x1f)); 37} 38 39static void ar7_gpio_set_value(struct gpio_chip *chip, 40 unsigned gpio, int value) 41{ 42 struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); 43 void __iomem *gpio_out = gpch->regs + AR7_GPIO_OUTPUT; 44 unsigned tmp; 45 46 tmp = readl(gpio_out) & ~(1 << gpio); 47 if (value) 48 tmp |= 1 << gpio; 49 writel(tmp, gpio_out); 50} 51 52static void titan_gpio_set_value(struct gpio_chip *chip, 53 unsigned gpio, int value) 54{ 55 struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); 56 void __iomem *gpio_out0 = gpch->regs + TITAN_GPIO_OUTPUT_0; 57 void __iomem *gpio_out1 = gpch->regs + TITAN_GPIO_OUTPUT_1; 58 unsigned tmp; 59 60 tmp = readl(gpio >> 5 ? gpio_out1 : gpio_out0) & ~(1 << (gpio & 0x1f)); 61 if (value) 62 tmp |= 1 << (gpio & 0x1f); 63 writel(tmp, gpio >> 5 ? gpio_out1 : gpio_out0); 64} 65 66static int ar7_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) 67{ 68 struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); 69 void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR; 70 71 writel(readl(gpio_dir) | (1 << gpio), gpio_dir); 72 73 return 0; 74} 75 76static int titan_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) 77{ 78 struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); 79 void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0; 80 void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1; 81 82 if (gpio >= TITAN_GPIO_MAX) 83 return -EINVAL; 84 85 writel(readl(gpio >> 5 ? gpio_dir1 : gpio_dir0) | (1 << (gpio & 0x1f)), 86 gpio >> 5 ? gpio_dir1 : gpio_dir0); 87 return 0; 88} 89 90static int ar7_gpio_direction_output(struct gpio_chip *chip, 91 unsigned gpio, int value) 92{ 93 struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); 94 void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR; 95 96 ar7_gpio_set_value(chip, gpio, value); 97 writel(readl(gpio_dir) & ~(1 << gpio), gpio_dir); 98 99 return 0; 100} 101 102static int titan_gpio_direction_output(struct gpio_chip *chip, 103 unsigned gpio, int value) 104{ 105 struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); 106 void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0; 107 void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1; 108 109 if (gpio >= TITAN_GPIO_MAX) 110 return -EINVAL; 111 112 titan_gpio_set_value(chip, gpio, value); 113 writel(readl(gpio >> 5 ? gpio_dir1 : gpio_dir0) & ~(1 << 114 (gpio & 0x1f)), gpio >> 5 ? gpio_dir1 : gpio_dir0); 115 116 return 0; 117} 118 119static struct ar7_gpio_chip ar7_gpio_chip = { 120 .chip = { 121 .label = "ar7-gpio", 122 .direction_input = ar7_gpio_direction_input, 123 .direction_output = ar7_gpio_direction_output, 124 .set = ar7_gpio_set_value, 125 .get = ar7_gpio_get_value, 126 .base = 0, 127 .ngpio = AR7_GPIO_MAX, 128 } 129}; 130 131static struct ar7_gpio_chip titan_gpio_chip = { 132 .chip = { 133 .label = "titan-gpio", 134 .direction_input = titan_gpio_direction_input, 135 .direction_output = titan_gpio_direction_output, 136 .set = titan_gpio_set_value, 137 .get = titan_gpio_get_value, 138 .base = 0, 139 .ngpio = TITAN_GPIO_MAX, 140 } 141}; 142 143static inline int ar7_gpio_enable_ar7(unsigned gpio) 144{ 145 void __iomem *gpio_en = ar7_gpio_chip.regs + AR7_GPIO_ENABLE; 146 147 writel(readl(gpio_en) | (1 << gpio), gpio_en); 148 149 return 0; 150} 151 152static inline int ar7_gpio_enable_titan(unsigned gpio) 153{ 154 void __iomem *gpio_en0 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_0; 155 void __iomem *gpio_en1 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_1; 156 157 writel(readl(gpio >> 5 ? gpio_en1 : gpio_en0) | (1 << (gpio & 0x1f)), 158 gpio >> 5 ? gpio_en1 : gpio_en0); 159 160 return 0; 161} 162 163int ar7_gpio_enable(unsigned gpio) 164{ 165 return ar7_is_titan() ? ar7_gpio_enable_titan(gpio) : 166 ar7_gpio_enable_ar7(gpio); 167} 168EXPORT_SYMBOL(ar7_gpio_enable); 169 170static inline int ar7_gpio_disable_ar7(unsigned gpio) 171{ 172 void __iomem *gpio_en = ar7_gpio_chip.regs + AR7_GPIO_ENABLE; 173 174 writel(readl(gpio_en) & ~(1 << gpio), gpio_en); 175 176 return 0; 177} 178 179static inline int ar7_gpio_disable_titan(unsigned gpio) 180{ 181 void __iomem *gpio_en0 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_0; 182 void __iomem *gpio_en1 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_1; 183 184 writel(readl(gpio >> 5 ? gpio_en1 : gpio_en0) & ~(1 << (gpio & 0x1f)), 185 gpio >> 5 ? gpio_en1 : gpio_en0); 186 187 return 0; 188} 189 190int ar7_gpio_disable(unsigned gpio) 191{ 192 return ar7_is_titan() ? ar7_gpio_disable_titan(gpio) : 193 ar7_gpio_disable_ar7(gpio); 194} 195EXPORT_SYMBOL(ar7_gpio_disable); 196 197struct titan_gpio_cfg { 198 u32 reg; 199 u32 shift; 200 u32 func; 201}; 202 203static const struct titan_gpio_cfg titan_gpio_table[] = { 204 /* reg, start bit, mux value */ 205 {4, 24, 1}, 206 {4, 26, 1}, 207 {4, 28, 1}, 208 {4, 30, 1}, 209 {5, 6, 1}, 210 {5, 8, 1}, 211 {5, 10, 1}, 212 {5, 12, 1}, 213 {7, 14, 3}, 214 {7, 16, 3}, 215 {7, 18, 3}, 216 {7, 20, 3}, 217 {7, 22, 3}, 218 {7, 26, 3}, 219 {7, 28, 3}, 220 {7, 30, 3}, 221 {8, 0, 3}, 222 {8, 2, 3}, 223 {8, 4, 3}, 224 {8, 10, 3}, 225 {8, 14, 3}, 226 {8, 16, 3}, 227 {8, 18, 3}, 228 {8, 20, 3}, 229 {9, 8, 3}, 230 {9, 10, 3}, 231 {9, 12, 3}, 232 {9, 14, 3}, 233 {9, 18, 3}, 234 {9, 20, 3}, 235 {9, 24, 3}, 236 {9, 26, 3}, 237 {9, 28, 3}, 238 {9, 30, 3}, 239 {10, 0, 3}, 240 {10, 2, 3}, 241 {10, 8, 3}, 242 {10, 10, 3}, 243 {10, 12, 3}, 244 {10, 14, 3}, 245 {13, 12, 3}, 246 {13, 14, 3}, 247 {13, 16, 3}, 248 {13, 18, 3}, 249 {13, 24, 3}, 250 {13, 26, 3}, 251 {13, 28, 3}, 252 {13, 30, 3}, 253 {14, 2, 3}, 254 {14, 6, 3}, 255 {14, 8, 3}, 256 {14, 12, 3} 257}; 258 259static int titan_gpio_pinsel(unsigned gpio) 260{ 261 struct titan_gpio_cfg gpio_cfg; 262 u32 mux_status, pin_sel_reg, tmp; 263 void __iomem *pin_sel = (void __iomem *)KSEG1ADDR(AR7_REGS_PINSEL); 264 265 if (gpio >= ARRAY_SIZE(titan_gpio_table)) 266 return -EINVAL; 267 268 gpio_cfg = titan_gpio_table[gpio]; 269 pin_sel_reg = gpio_cfg.reg - 1; 270 271 mux_status = (readl(pin_sel + pin_sel_reg) >> gpio_cfg.shift) & 0x3; 272 273 /* Check the mux status */ 274 if (!((mux_status == 0) || (mux_status == gpio_cfg.func))) 275 return 0; 276 277 /* Set the pin sel value */ 278 tmp = readl(pin_sel + pin_sel_reg); 279 tmp |= ((gpio_cfg.func & 0x3) << gpio_cfg.shift); 280 writel(tmp, pin_sel + pin_sel_reg); 281 282 return 0; 283} 284 285/* Perform minimal Titan GPIO configuration */ 286static void titan_gpio_init(void) 287{ 288 unsigned i; 289 290 for (i = 44; i < 48; i++) { 291 titan_gpio_pinsel(i); 292 ar7_gpio_enable_titan(i); 293 titan_gpio_direction_input(&titan_gpio_chip.chip, i); 294 } 295} 296 297int __init ar7_gpio_init(void) 298{ 299 int ret; 300 struct ar7_gpio_chip *gpch; 301 unsigned size; 302 303 if (!ar7_is_titan()) { 304 gpch = &ar7_gpio_chip; 305 size = 0x10; 306 } else { 307 gpch = &titan_gpio_chip; 308 size = 0x1f; 309 } 310 311 gpch->regs = ioremap(AR7_REGS_GPIO, size); 312 if (!gpch->regs) { 313 printk(KERN_ERR "%s: failed to ioremap regs\n", 314 gpch->chip.label); 315 return -ENOMEM; 316 } 317 318 ret = gpiochip_add_data(&gpch->chip, gpch); 319 if (ret) { 320 printk(KERN_ERR "%s: failed to add gpiochip\n", 321 gpch->chip.label); 322 iounmap(gpch->regs); 323 return ret; 324 } 325 printk(KERN_INFO "%s: registered %d GPIOs\n", 326 gpch->chip.label, gpch->chip.ngpio); 327 328 if (ar7_is_titan()) 329 titan_gpio_init(); 330 331 return ret; 332}