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.3-rc5 475 lines 11 kB view raw
1#include <linux/kernel.h> 2#include <linux/init.h> 3#include <linux/gpio.h> 4#include <linux/gpio/driver.h> 5#include <linux/of_gpio.h> 6#include <linux/io.h> 7#include <linux/interrupt.h> 8#include <linux/platform_device.h> 9#include <linux/basic_mmio_gpio.h> 10 11#define ETRAX_FS_rw_pa_dout 0 12#define ETRAX_FS_r_pa_din 4 13#define ETRAX_FS_rw_pa_oe 8 14#define ETRAX_FS_rw_intr_cfg 12 15#define ETRAX_FS_rw_intr_mask 16 16#define ETRAX_FS_rw_ack_intr 20 17#define ETRAX_FS_r_intr 24 18#define ETRAX_FS_r_masked_intr 28 19#define ETRAX_FS_rw_pb_dout 32 20#define ETRAX_FS_r_pb_din 36 21#define ETRAX_FS_rw_pb_oe 40 22#define ETRAX_FS_rw_pc_dout 48 23#define ETRAX_FS_r_pc_din 52 24#define ETRAX_FS_rw_pc_oe 56 25#define ETRAX_FS_rw_pd_dout 64 26#define ETRAX_FS_r_pd_din 68 27#define ETRAX_FS_rw_pd_oe 72 28#define ETRAX_FS_rw_pe_dout 80 29#define ETRAX_FS_r_pe_din 84 30#define ETRAX_FS_rw_pe_oe 88 31 32#define ARTPEC3_r_pa_din 0 33#define ARTPEC3_rw_pa_dout 4 34#define ARTPEC3_rw_pa_oe 8 35#define ARTPEC3_r_pb_din 44 36#define ARTPEC3_rw_pb_dout 48 37#define ARTPEC3_rw_pb_oe 52 38#define ARTPEC3_r_pc_din 88 39#define ARTPEC3_rw_pc_dout 92 40#define ARTPEC3_rw_pc_oe 96 41#define ARTPEC3_r_pd_din 116 42#define ARTPEC3_rw_intr_cfg 120 43#define ARTPEC3_rw_intr_pins 124 44#define ARTPEC3_rw_intr_mask 128 45#define ARTPEC3_rw_ack_intr 132 46#define ARTPEC3_r_masked_intr 140 47 48#define GIO_CFG_OFF 0 49#define GIO_CFG_HI 1 50#define GIO_CFG_LO 2 51#define GIO_CFG_SET 3 52#define GIO_CFG_POSEDGE 5 53#define GIO_CFG_NEGEDGE 6 54#define GIO_CFG_ANYEDGE 7 55 56struct etraxfs_gpio_info; 57 58struct etraxfs_gpio_block { 59 spinlock_t lock; 60 u32 mask; 61 u32 cfg; 62 u32 pins; 63 unsigned int group[8]; 64 65 void __iomem *regs; 66 const struct etraxfs_gpio_info *info; 67}; 68 69struct etraxfs_gpio_chip { 70 struct bgpio_chip bgc; 71 struct etraxfs_gpio_block *block; 72}; 73 74struct etraxfs_gpio_port { 75 const char *label; 76 unsigned int oe; 77 unsigned int dout; 78 unsigned int din; 79 unsigned int ngpio; 80}; 81 82struct etraxfs_gpio_info { 83 unsigned int num_ports; 84 const struct etraxfs_gpio_port *ports; 85 86 unsigned int rw_ack_intr; 87 unsigned int rw_intr_mask; 88 unsigned int rw_intr_cfg; 89 unsigned int rw_intr_pins; 90 unsigned int r_masked_intr; 91}; 92 93static const struct etraxfs_gpio_port etraxfs_gpio_etraxfs_ports[] = { 94 { 95 .label = "A", 96 .ngpio = 8, 97 .oe = ETRAX_FS_rw_pa_oe, 98 .dout = ETRAX_FS_rw_pa_dout, 99 .din = ETRAX_FS_r_pa_din, 100 }, 101 { 102 .label = "B", 103 .ngpio = 18, 104 .oe = ETRAX_FS_rw_pb_oe, 105 .dout = ETRAX_FS_rw_pb_dout, 106 .din = ETRAX_FS_r_pb_din, 107 }, 108 { 109 .label = "C", 110 .ngpio = 18, 111 .oe = ETRAX_FS_rw_pc_oe, 112 .dout = ETRAX_FS_rw_pc_dout, 113 .din = ETRAX_FS_r_pc_din, 114 }, 115 { 116 .label = "D", 117 .ngpio = 18, 118 .oe = ETRAX_FS_rw_pd_oe, 119 .dout = ETRAX_FS_rw_pd_dout, 120 .din = ETRAX_FS_r_pd_din, 121 }, 122 { 123 .label = "E", 124 .ngpio = 18, 125 .oe = ETRAX_FS_rw_pe_oe, 126 .dout = ETRAX_FS_rw_pe_dout, 127 .din = ETRAX_FS_r_pe_din, 128 }, 129}; 130 131static const struct etraxfs_gpio_info etraxfs_gpio_etraxfs = { 132 .num_ports = ARRAY_SIZE(etraxfs_gpio_etraxfs_ports), 133 .ports = etraxfs_gpio_etraxfs_ports, 134 .rw_ack_intr = ETRAX_FS_rw_ack_intr, 135 .rw_intr_mask = ETRAX_FS_rw_intr_mask, 136 .rw_intr_cfg = ETRAX_FS_rw_intr_cfg, 137 .r_masked_intr = ETRAX_FS_r_masked_intr, 138}; 139 140static const struct etraxfs_gpio_port etraxfs_gpio_artpec3_ports[] = { 141 { 142 .label = "A", 143 .ngpio = 32, 144 .oe = ARTPEC3_rw_pa_oe, 145 .dout = ARTPEC3_rw_pa_dout, 146 .din = ARTPEC3_r_pa_din, 147 }, 148 { 149 .label = "B", 150 .ngpio = 32, 151 .oe = ARTPEC3_rw_pb_oe, 152 .dout = ARTPEC3_rw_pb_dout, 153 .din = ARTPEC3_r_pb_din, 154 }, 155 { 156 .label = "C", 157 .ngpio = 16, 158 .oe = ARTPEC3_rw_pc_oe, 159 .dout = ARTPEC3_rw_pc_dout, 160 .din = ARTPEC3_r_pc_din, 161 }, 162 { 163 .label = "D", 164 .ngpio = 32, 165 .din = ARTPEC3_r_pd_din, 166 }, 167}; 168 169static const struct etraxfs_gpio_info etraxfs_gpio_artpec3 = { 170 .num_ports = ARRAY_SIZE(etraxfs_gpio_artpec3_ports), 171 .ports = etraxfs_gpio_artpec3_ports, 172 .rw_ack_intr = ARTPEC3_rw_ack_intr, 173 .rw_intr_mask = ARTPEC3_rw_intr_mask, 174 .rw_intr_cfg = ARTPEC3_rw_intr_cfg, 175 .r_masked_intr = ARTPEC3_r_masked_intr, 176 .rw_intr_pins = ARTPEC3_rw_intr_pins, 177}; 178 179static unsigned int etraxfs_gpio_chip_to_port(struct gpio_chip *gc) 180{ 181 return gc->label[0] - 'A'; 182} 183 184static int etraxfs_gpio_of_xlate(struct gpio_chip *gc, 185 const struct of_phandle_args *gpiospec, 186 u32 *flags) 187{ 188 /* 189 * Port numbers are A to E, and the properties are integers, so we 190 * specify them as 0xA - 0xE. 191 */ 192 if (etraxfs_gpio_chip_to_port(gc) + 0xA != gpiospec->args[2]) 193 return -EINVAL; 194 195 return of_gpio_simple_xlate(gc, gpiospec, flags); 196} 197 198static const struct of_device_id etraxfs_gpio_of_table[] = { 199 { 200 .compatible = "axis,etraxfs-gio", 201 .data = &etraxfs_gpio_etraxfs, 202 }, 203 { 204 .compatible = "axis,artpec3-gio", 205 .data = &etraxfs_gpio_artpec3, 206 }, 207 {}, 208}; 209 210static unsigned int etraxfs_gpio_to_group_irq(unsigned int gpio) 211{ 212 return gpio % 8; 213} 214 215static unsigned int etraxfs_gpio_to_group_pin(struct etraxfs_gpio_chip *chip, 216 unsigned int gpio) 217{ 218 return 4 * etraxfs_gpio_chip_to_port(&chip->bgc.gc) + gpio / 8; 219} 220 221static void etraxfs_gpio_irq_ack(struct irq_data *d) 222{ 223 struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d); 224 struct etraxfs_gpio_block *block = chip->block; 225 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); 226 227 writel(BIT(grpirq), block->regs + block->info->rw_ack_intr); 228} 229 230static void etraxfs_gpio_irq_mask(struct irq_data *d) 231{ 232 struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d); 233 struct etraxfs_gpio_block *block = chip->block; 234 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); 235 236 spin_lock(&block->lock); 237 block->mask &= ~BIT(grpirq); 238 writel(block->mask, block->regs + block->info->rw_intr_mask); 239 spin_unlock(&block->lock); 240} 241 242static void etraxfs_gpio_irq_unmask(struct irq_data *d) 243{ 244 struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d); 245 struct etraxfs_gpio_block *block = chip->block; 246 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); 247 248 spin_lock(&block->lock); 249 block->mask |= BIT(grpirq); 250 writel(block->mask, block->regs + block->info->rw_intr_mask); 251 spin_unlock(&block->lock); 252} 253 254static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type) 255{ 256 struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d); 257 struct etraxfs_gpio_block *block = chip->block; 258 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); 259 u32 cfg; 260 261 switch (type) { 262 case IRQ_TYPE_EDGE_RISING: 263 cfg = GIO_CFG_POSEDGE; 264 break; 265 case IRQ_TYPE_EDGE_FALLING: 266 cfg = GIO_CFG_NEGEDGE; 267 break; 268 case IRQ_TYPE_EDGE_BOTH: 269 cfg = GIO_CFG_ANYEDGE; 270 break; 271 case IRQ_TYPE_LEVEL_LOW: 272 cfg = GIO_CFG_LO; 273 break; 274 case IRQ_TYPE_LEVEL_HIGH: 275 cfg = GIO_CFG_HI; 276 break; 277 default: 278 return -EINVAL; 279 } 280 281 spin_lock(&block->lock); 282 block->cfg &= ~(0x7 << (grpirq * 3)); 283 block->cfg |= (cfg << (grpirq * 3)); 284 writel(block->cfg, block->regs + block->info->rw_intr_cfg); 285 spin_unlock(&block->lock); 286 287 return 0; 288} 289 290static int etraxfs_gpio_irq_request_resources(struct irq_data *d) 291{ 292 struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d); 293 struct etraxfs_gpio_block *block = chip->block; 294 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); 295 int ret = -EBUSY; 296 297 spin_lock(&block->lock); 298 if (block->group[grpirq]) 299 goto out; 300 301 ret = gpiochip_lock_as_irq(&chip->bgc.gc, d->hwirq); 302 if (ret) 303 goto out; 304 305 block->group[grpirq] = d->irq; 306 if (block->info->rw_intr_pins) { 307 unsigned int pin = etraxfs_gpio_to_group_pin(chip, d->hwirq); 308 309 block->pins &= ~(0xf << (grpirq * 4)); 310 block->pins |= (pin << (grpirq * 4)); 311 312 writel(block->pins, block->regs + block->info->rw_intr_pins); 313 } 314 315out: 316 spin_unlock(&block->lock); 317 return ret; 318} 319 320static void etraxfs_gpio_irq_release_resources(struct irq_data *d) 321{ 322 struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d); 323 struct etraxfs_gpio_block *block = chip->block; 324 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); 325 326 spin_lock(&block->lock); 327 block->group[grpirq] = 0; 328 gpiochip_unlock_as_irq(&chip->bgc.gc, d->hwirq); 329 spin_unlock(&block->lock); 330} 331 332static struct irq_chip etraxfs_gpio_irq_chip = { 333 .name = "gpio-etraxfs", 334 .irq_ack = etraxfs_gpio_irq_ack, 335 .irq_mask = etraxfs_gpio_irq_mask, 336 .irq_unmask = etraxfs_gpio_irq_unmask, 337 .irq_set_type = etraxfs_gpio_irq_set_type, 338 .irq_request_resources = etraxfs_gpio_irq_request_resources, 339 .irq_release_resources = etraxfs_gpio_irq_release_resources, 340}; 341 342static irqreturn_t etraxfs_gpio_interrupt(int irq, void *dev_id) 343{ 344 struct etraxfs_gpio_block *block = dev_id; 345 unsigned long intr = readl(block->regs + block->info->r_masked_intr); 346 int bit; 347 348 for_each_set_bit(bit, &intr, 8) 349 generic_handle_irq(block->group[bit]); 350 351 return IRQ_RETVAL(intr & 0xff); 352} 353 354static int etraxfs_gpio_probe(struct platform_device *pdev) 355{ 356 struct device *dev = &pdev->dev; 357 const struct etraxfs_gpio_info *info; 358 const struct of_device_id *match; 359 struct etraxfs_gpio_block *block; 360 struct etraxfs_gpio_chip *chips; 361 struct resource *res, *irq; 362 bool allportsirq = false; 363 void __iomem *regs; 364 int ret; 365 int i; 366 367 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 368 regs = devm_ioremap_resource(dev, res); 369 if (IS_ERR(regs)) 370 return PTR_ERR(regs); 371 372 match = of_match_node(etraxfs_gpio_of_table, dev->of_node); 373 if (!match) 374 return -EINVAL; 375 376 info = match->data; 377 378 chips = devm_kzalloc(dev, sizeof(*chips) * info->num_ports, GFP_KERNEL); 379 if (!chips) 380 return -ENOMEM; 381 382 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 383 if (!irq) 384 return -EINVAL; 385 386 block = devm_kzalloc(dev, sizeof(*block), GFP_KERNEL); 387 if (!block) 388 return -ENOMEM; 389 390 spin_lock_init(&block->lock); 391 392 block->regs = regs; 393 block->info = info; 394 395 writel(0, block->regs + info->rw_intr_mask); 396 writel(0, block->regs + info->rw_intr_cfg); 397 if (info->rw_intr_pins) { 398 allportsirq = true; 399 writel(0, block->regs + info->rw_intr_pins); 400 } 401 402 ret = devm_request_irq(dev, irq->start, etraxfs_gpio_interrupt, 403 IRQF_SHARED, dev_name(dev), block); 404 if (ret) { 405 dev_err(dev, "Unable to request irq %d\n", ret); 406 return ret; 407 } 408 409 for (i = 0; i < info->num_ports; i++) { 410 struct etraxfs_gpio_chip *chip = &chips[i]; 411 struct bgpio_chip *bgc = &chip->bgc; 412 const struct etraxfs_gpio_port *port = &info->ports[i]; 413 unsigned long flags = BGPIOF_READ_OUTPUT_REG_SET; 414 void __iomem *dat = regs + port->din; 415 void __iomem *set = regs + port->dout; 416 void __iomem *dirout = regs + port->oe; 417 418 chip->block = block; 419 420 if (dirout == set) { 421 dirout = set = NULL; 422 flags = BGPIOF_NO_OUTPUT; 423 } 424 425 ret = bgpio_init(bgc, dev, 4, 426 dat, set, NULL, dirout, NULL, 427 flags); 428 if (ret) { 429 dev_err(dev, "Unable to init port %s\n", 430 port->label); 431 continue; 432 } 433 434 bgc->gc.ngpio = port->ngpio; 435 bgc->gc.label = port->label; 436 437 bgc->gc.of_node = dev->of_node; 438 bgc->gc.of_gpio_n_cells = 3; 439 bgc->gc.of_xlate = etraxfs_gpio_of_xlate; 440 441 ret = gpiochip_add(&bgc->gc); 442 if (ret) { 443 dev_err(dev, "Unable to register port %s\n", 444 bgc->gc.label); 445 continue; 446 } 447 448 if (i > 0 && !allportsirq) 449 continue; 450 451 ret = gpiochip_irqchip_add(&bgc->gc, &etraxfs_gpio_irq_chip, 0, 452 handle_level_irq, IRQ_TYPE_NONE); 453 if (ret) { 454 dev_err(dev, "Unable to add irqchip to port %s\n", 455 bgc->gc.label); 456 } 457 } 458 459 return 0; 460} 461 462static struct platform_driver etraxfs_gpio_driver = { 463 .driver = { 464 .name = "etraxfs-gpio", 465 .of_match_table = of_match_ptr(etraxfs_gpio_of_table), 466 }, 467 .probe = etraxfs_gpio_probe, 468}; 469 470static int __init etraxfs_gpio_init(void) 471{ 472 return platform_driver_register(&etraxfs_gpio_driver); 473} 474 475device_initcall(etraxfs_gpio_init);