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

Configure Feed

Select the types of activity you want to include in your feed.

at v4.13 394 lines 10 kB view raw
1/* 2 * Ingenic JZ47xx GPIO driver 3 * 4 * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net> 5 * 6 * License terms: GNU General Public License (GPL) version 2 7 */ 8 9#include <linux/gpio/driver.h> 10#include <linux/interrupt.h> 11#include <linux/io.h> 12#include <linux/module.h> 13#include <linux/of_address.h> 14#include <linux/of_device.h> 15#include <linux/of_irq.h> 16#include <linux/pinctrl/consumer.h> 17#include <linux/regmap.h> 18 19#define GPIO_PIN 0x00 20#define GPIO_MSK 0x20 21 22#define JZ4740_GPIO_DATA 0x10 23#define JZ4740_GPIO_SELECT 0x50 24#define JZ4740_GPIO_DIR 0x60 25#define JZ4740_GPIO_TRIG 0x70 26#define JZ4740_GPIO_FLAG 0x80 27 28#define JZ4770_GPIO_INT 0x10 29#define JZ4770_GPIO_PAT1 0x30 30#define JZ4770_GPIO_PAT0 0x40 31#define JZ4770_GPIO_FLAG 0x50 32 33#define REG_SET(x) ((x) + 0x4) 34#define REG_CLEAR(x) ((x) + 0x8) 35 36enum jz_version { 37 ID_JZ4740, 38 ID_JZ4770, 39 ID_JZ4780, 40}; 41 42struct ingenic_gpio_chip { 43 struct regmap *map; 44 struct gpio_chip gc; 45 struct irq_chip irq_chip; 46 unsigned int irq, reg_base; 47 enum jz_version version; 48}; 49 50static u32 gpio_ingenic_read_reg(struct ingenic_gpio_chip *jzgc, u8 reg) 51{ 52 unsigned int val; 53 54 regmap_read(jzgc->map, jzgc->reg_base + reg, &val); 55 56 return (u32) val; 57} 58 59static void gpio_ingenic_set_bit(struct ingenic_gpio_chip *jzgc, 60 u8 reg, u8 offset, bool set) 61{ 62 if (set) 63 reg = REG_SET(reg); 64 else 65 reg = REG_CLEAR(reg); 66 67 regmap_write(jzgc->map, jzgc->reg_base + reg, BIT(offset)); 68} 69 70static inline bool gpio_get_value(struct ingenic_gpio_chip *jzgc, u8 offset) 71{ 72 unsigned int val = gpio_ingenic_read_reg(jzgc, GPIO_PIN); 73 74 return !!(val & BIT(offset)); 75} 76 77static void gpio_set_value(struct ingenic_gpio_chip *jzgc, u8 offset, int value) 78{ 79 if (jzgc->version >= ID_JZ4770) 80 gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_PAT0, offset, !!value); 81 else 82 gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_DATA, offset, !!value); 83} 84 85static void irq_set_type(struct ingenic_gpio_chip *jzgc, 86 u8 offset, unsigned int type) 87{ 88 u8 reg1, reg2; 89 90 if (jzgc->version >= ID_JZ4770) { 91 reg1 = JZ4770_GPIO_PAT1; 92 reg2 = JZ4770_GPIO_PAT0; 93 } else { 94 reg1 = JZ4740_GPIO_TRIG; 95 reg2 = JZ4740_GPIO_DIR; 96 } 97 98 switch (type) { 99 case IRQ_TYPE_EDGE_RISING: 100 gpio_ingenic_set_bit(jzgc, reg2, offset, true); 101 gpio_ingenic_set_bit(jzgc, reg1, offset, true); 102 break; 103 case IRQ_TYPE_EDGE_FALLING: 104 gpio_ingenic_set_bit(jzgc, reg2, offset, false); 105 gpio_ingenic_set_bit(jzgc, reg1, offset, true); 106 break; 107 case IRQ_TYPE_LEVEL_HIGH: 108 gpio_ingenic_set_bit(jzgc, reg2, offset, true); 109 gpio_ingenic_set_bit(jzgc, reg1, offset, false); 110 break; 111 case IRQ_TYPE_LEVEL_LOW: 112 default: 113 gpio_ingenic_set_bit(jzgc, reg2, offset, false); 114 gpio_ingenic_set_bit(jzgc, reg1, offset, false); 115 break; 116 } 117} 118 119static void ingenic_gpio_irq_mask(struct irq_data *irqd) 120{ 121 struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); 122 struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); 123 124 gpio_ingenic_set_bit(jzgc, GPIO_MSK, irqd->hwirq, true); 125} 126 127static void ingenic_gpio_irq_unmask(struct irq_data *irqd) 128{ 129 struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); 130 struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); 131 132 gpio_ingenic_set_bit(jzgc, GPIO_MSK, irqd->hwirq, false); 133} 134 135static void ingenic_gpio_irq_enable(struct irq_data *irqd) 136{ 137 struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); 138 struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); 139 int irq = irqd->hwirq; 140 141 if (jzgc->version >= ID_JZ4770) 142 gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_INT, irq, true); 143 else 144 gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, true); 145 146 ingenic_gpio_irq_unmask(irqd); 147} 148 149static void ingenic_gpio_irq_disable(struct irq_data *irqd) 150{ 151 struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); 152 struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); 153 int irq = irqd->hwirq; 154 155 ingenic_gpio_irq_mask(irqd); 156 157 if (jzgc->version >= ID_JZ4770) 158 gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_INT, irq, false); 159 else 160 gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, false); 161} 162 163static void ingenic_gpio_irq_ack(struct irq_data *irqd) 164{ 165 struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); 166 struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); 167 int irq = irqd->hwirq; 168 bool high; 169 170 if (irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) { 171 /* 172 * Switch to an interrupt for the opposite edge to the one that 173 * triggered the interrupt being ACKed. 174 */ 175 high = gpio_get_value(jzgc, irq); 176 if (high) 177 irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_FALLING); 178 else 179 irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_RISING); 180 } 181 182 if (jzgc->version >= ID_JZ4770) 183 gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_FLAG, irq, false); 184 else 185 gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_DATA, irq, true); 186} 187 188static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) 189{ 190 struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); 191 struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); 192 193 switch (type) { 194 case IRQ_TYPE_EDGE_BOTH: 195 case IRQ_TYPE_EDGE_RISING: 196 case IRQ_TYPE_EDGE_FALLING: 197 irq_set_handler_locked(irqd, handle_edge_irq); 198 break; 199 case IRQ_TYPE_LEVEL_HIGH: 200 case IRQ_TYPE_LEVEL_LOW: 201 irq_set_handler_locked(irqd, handle_level_irq); 202 break; 203 default: 204 irq_set_handler_locked(irqd, handle_bad_irq); 205 } 206 207 if (type == IRQ_TYPE_EDGE_BOTH) { 208 /* 209 * The hardware does not support interrupts on both edges. The 210 * best we can do is to set up a single-edge interrupt and then 211 * switch to the opposing edge when ACKing the interrupt. 212 */ 213 bool high = gpio_get_value(jzgc, irqd->hwirq); 214 215 type = high ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING; 216 } 217 218 irq_set_type(jzgc, irqd->hwirq, type); 219 return 0; 220} 221 222static int ingenic_gpio_irq_set_wake(struct irq_data *irqd, unsigned int on) 223{ 224 struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); 225 struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); 226 227 return irq_set_irq_wake(jzgc->irq, on); 228} 229 230static void ingenic_gpio_irq_handler(struct irq_desc *desc) 231{ 232 struct gpio_chip *gc = irq_desc_get_handler_data(desc); 233 struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); 234 struct irq_chip *irq_chip = irq_data_get_irq_chip(&desc->irq_data); 235 unsigned long flag, i; 236 237 chained_irq_enter(irq_chip, desc); 238 239 if (jzgc->version >= ID_JZ4770) 240 flag = gpio_ingenic_read_reg(jzgc, JZ4770_GPIO_FLAG); 241 else 242 flag = gpio_ingenic_read_reg(jzgc, JZ4740_GPIO_FLAG); 243 244 for_each_set_bit(i, &flag, 32) 245 generic_handle_irq(irq_linear_revmap(gc->irqdomain, i)); 246 chained_irq_exit(irq_chip, desc); 247} 248 249static void ingenic_gpio_set(struct gpio_chip *gc, 250 unsigned int offset, int value) 251{ 252 struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); 253 254 gpio_set_value(jzgc, offset, value); 255} 256 257static int ingenic_gpio_get(struct gpio_chip *gc, unsigned int offset) 258{ 259 struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); 260 261 return (int) gpio_get_value(jzgc, offset); 262} 263 264static int ingenic_gpio_direction_input(struct gpio_chip *gc, 265 unsigned int offset) 266{ 267 return pinctrl_gpio_direction_input(gc->base + offset); 268} 269 270static int ingenic_gpio_direction_output(struct gpio_chip *gc, 271 unsigned int offset, int value) 272{ 273 ingenic_gpio_set(gc, offset, value); 274 return pinctrl_gpio_direction_output(gc->base + offset); 275} 276 277static const struct of_device_id ingenic_gpio_of_match[] = { 278 { .compatible = "ingenic,jz4740-gpio", .data = (void *)ID_JZ4740 }, 279 { .compatible = "ingenic,jz4770-gpio", .data = (void *)ID_JZ4770 }, 280 { .compatible = "ingenic,jz4780-gpio", .data = (void *)ID_JZ4780 }, 281 {}, 282}; 283MODULE_DEVICE_TABLE(of, ingenic_gpio_of_match); 284 285static int ingenic_gpio_probe(struct platform_device *pdev) 286{ 287 struct device *dev = &pdev->dev; 288 const struct of_device_id *of_id = of_match_device( 289 ingenic_gpio_of_match, dev); 290 struct ingenic_gpio_chip *jzgc; 291 u32 bank; 292 int err; 293 294 jzgc = devm_kzalloc(dev, sizeof(*jzgc), GFP_KERNEL); 295 if (!jzgc) 296 return -ENOMEM; 297 298 jzgc->map = dev_get_drvdata(dev->parent); 299 if (!jzgc->map) { 300 dev_err(dev, "Cannot get parent regmap\n"); 301 return -ENXIO; 302 } 303 304 err = of_property_read_u32(dev->of_node, "reg", &bank); 305 if (err) { 306 dev_err(dev, "Cannot read \"reg\" property: %i\n", err); 307 return err; 308 } 309 310 jzgc->reg_base = bank * 0x100; 311 312 jzgc->gc.label = devm_kasprintf(dev, GFP_KERNEL, "GPIO%c", 'A' + bank); 313 if (!jzgc->gc.label) 314 return -ENOMEM; 315 316 /* DO NOT EXPAND THIS: FOR BACKWARD GPIO NUMBERSPACE COMPATIBIBILITY 317 * ONLY: WORK TO TRANSITION CONSUMERS TO USE THE GPIO DESCRIPTOR API IN 318 * <linux/gpio/consumer.h> INSTEAD. 319 */ 320 jzgc->gc.base = bank * 32; 321 322 jzgc->gc.ngpio = 32; 323 jzgc->gc.parent = dev; 324 jzgc->gc.of_node = dev->of_node; 325 jzgc->gc.owner = THIS_MODULE; 326 jzgc->version = (enum jz_version)of_id->data; 327 328 jzgc->gc.set = ingenic_gpio_set; 329 jzgc->gc.get = ingenic_gpio_get; 330 jzgc->gc.direction_input = ingenic_gpio_direction_input; 331 jzgc->gc.direction_output = ingenic_gpio_direction_output; 332 333 if (of_property_read_bool(dev->of_node, "gpio-ranges")) { 334 jzgc->gc.request = gpiochip_generic_request; 335 jzgc->gc.free = gpiochip_generic_free; 336 } 337 338 err = devm_gpiochip_add_data(dev, &jzgc->gc, jzgc); 339 if (err) 340 return err; 341 342 jzgc->irq = irq_of_parse_and_map(dev->of_node, 0); 343 if (!jzgc->irq) 344 return -EINVAL; 345 346 jzgc->irq_chip.name = jzgc->gc.label; 347 jzgc->irq_chip.irq_enable = ingenic_gpio_irq_enable; 348 jzgc->irq_chip.irq_disable = ingenic_gpio_irq_disable; 349 jzgc->irq_chip.irq_unmask = ingenic_gpio_irq_unmask; 350 jzgc->irq_chip.irq_mask = ingenic_gpio_irq_mask; 351 jzgc->irq_chip.irq_ack = ingenic_gpio_irq_ack; 352 jzgc->irq_chip.irq_set_type = ingenic_gpio_irq_set_type; 353 jzgc->irq_chip.irq_set_wake = ingenic_gpio_irq_set_wake; 354 jzgc->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND; 355 356 err = gpiochip_irqchip_add(&jzgc->gc, &jzgc->irq_chip, 0, 357 handle_level_irq, IRQ_TYPE_NONE); 358 if (err) 359 return err; 360 361 gpiochip_set_chained_irqchip(&jzgc->gc, &jzgc->irq_chip, 362 jzgc->irq, ingenic_gpio_irq_handler); 363 return 0; 364} 365 366static int ingenic_gpio_remove(struct platform_device *pdev) 367{ 368 return 0; 369} 370 371static struct platform_driver ingenic_gpio_driver = { 372 .driver = { 373 .name = "gpio-ingenic", 374 .of_match_table = of_match_ptr(ingenic_gpio_of_match), 375 }, 376 .probe = ingenic_gpio_probe, 377 .remove = ingenic_gpio_remove, 378}; 379 380static int __init ingenic_gpio_drv_register(void) 381{ 382 return platform_driver_register(&ingenic_gpio_driver); 383} 384subsys_initcall(ingenic_gpio_drv_register); 385 386static void __exit ingenic_gpio_drv_unregister(void) 387{ 388 platform_driver_unregister(&ingenic_gpio_driver); 389} 390module_exit(ingenic_gpio_drv_unregister); 391 392MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>"); 393MODULE_DESCRIPTION("Ingenic JZ47xx GPIO driver"); 394MODULE_LICENSE("GPL");