| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2008, 2009 Provigent Ltd. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Author: Baruch Siach <baruch@tkos.co.il> |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 8 | | - * published by the Free Software Foundation. |
|---|
| 9 | 6 | * |
|---|
| 10 | 7 | * Driver for the ARM PrimeCell(tm) General Purpose Input/Output (PL061) |
|---|
| 11 | 8 | * |
|---|
| .. | .. |
|---|
| 19 | 16 | #include <linux/interrupt.h> |
|---|
| 20 | 17 | #include <linux/irq.h> |
|---|
| 21 | 18 | #include <linux/irqchip/chained_irq.h> |
|---|
| 19 | +#include <linux/module.h> |
|---|
| 22 | 20 | #include <linux/bitops.h> |
|---|
| 23 | 21 | #include <linux/gpio/driver.h> |
|---|
| 24 | 22 | #include <linux/device.h> |
|---|
| .. | .. |
|---|
| 66 | 64 | { |
|---|
| 67 | 65 | struct pl061 *pl061 = gpiochip_get_data(gc); |
|---|
| 68 | 66 | |
|---|
| 69 | | - return !(readb(pl061->base + GPIODIR) & BIT(offset)); |
|---|
| 67 | + if (readb(pl061->base + GPIODIR) & BIT(offset)) |
|---|
| 68 | + return GPIO_LINE_DIRECTION_OUT; |
|---|
| 69 | + |
|---|
| 70 | + return GPIO_LINE_DIRECTION_IN; |
|---|
| 70 | 71 | } |
|---|
| 71 | 72 | |
|---|
| 72 | 73 | static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) |
|---|
| .. | .. |
|---|
| 286 | 287 | { |
|---|
| 287 | 288 | struct device *dev = &adev->dev; |
|---|
| 288 | 289 | struct pl061 *pl061; |
|---|
| 290 | + struct gpio_irq_chip *girq; |
|---|
| 289 | 291 | int ret, irq; |
|---|
| 290 | 292 | |
|---|
| 291 | 293 | pl061 = devm_kzalloc(dev, sizeof(*pl061), GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 297 | 299 | return PTR_ERR(pl061->base); |
|---|
| 298 | 300 | |
|---|
| 299 | 301 | raw_spin_lock_init(&pl061->lock); |
|---|
| 300 | | - if (of_property_read_bool(dev->of_node, "gpio-ranges")) { |
|---|
| 301 | | - pl061->gc.request = gpiochip_generic_request; |
|---|
| 302 | | - pl061->gc.free = gpiochip_generic_free; |
|---|
| 303 | | - } |
|---|
| 304 | | - |
|---|
| 302 | + pl061->gc.request = gpiochip_generic_request; |
|---|
| 303 | + pl061->gc.free = gpiochip_generic_free; |
|---|
| 305 | 304 | pl061->gc.base = -1; |
|---|
| 306 | 305 | pl061->gc.get_direction = pl061_get_direction; |
|---|
| 307 | 306 | pl061->gc.direction_input = pl061_direction_input; |
|---|
| .. | .. |
|---|
| 312 | 311 | pl061->gc.label = dev_name(dev); |
|---|
| 313 | 312 | pl061->gc.parent = dev; |
|---|
| 314 | 313 | pl061->gc.owner = THIS_MODULE; |
|---|
| 315 | | - |
|---|
| 316 | | - ret = gpiochip_add_data(&pl061->gc, pl061); |
|---|
| 317 | | - if (ret) |
|---|
| 318 | | - return ret; |
|---|
| 319 | 314 | |
|---|
| 320 | 315 | /* |
|---|
| 321 | 316 | * irq_chip support |
|---|
| .. | .. |
|---|
| 329 | 324 | |
|---|
| 330 | 325 | writeb(0, pl061->base + GPIOIE); /* disable irqs */ |
|---|
| 331 | 326 | irq = adev->irq[0]; |
|---|
| 332 | | - if (irq < 0) { |
|---|
| 333 | | - dev_err(&adev->dev, "invalid IRQ\n"); |
|---|
| 334 | | - return -ENODEV; |
|---|
| 335 | | - } |
|---|
| 327 | + if (!irq) |
|---|
| 328 | + dev_warn(&adev->dev, "IRQ support disabled\n"); |
|---|
| 336 | 329 | pl061->parent_irq = irq; |
|---|
| 337 | 330 | |
|---|
| 338 | | - ret = gpiochip_irqchip_add(&pl061->gc, &pl061->irq_chip, |
|---|
| 339 | | - 0, handle_bad_irq, |
|---|
| 340 | | - IRQ_TYPE_NONE); |
|---|
| 341 | | - if (ret) { |
|---|
| 342 | | - dev_info(&adev->dev, "could not add irqchip\n"); |
|---|
| 331 | + girq = &pl061->gc.irq; |
|---|
| 332 | + girq->chip = &pl061->irq_chip; |
|---|
| 333 | + girq->parent_handler = pl061_irq_handler; |
|---|
| 334 | + girq->num_parents = 1; |
|---|
| 335 | + girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents), |
|---|
| 336 | + GFP_KERNEL); |
|---|
| 337 | + if (!girq->parents) |
|---|
| 338 | + return -ENOMEM; |
|---|
| 339 | + girq->parents[0] = irq; |
|---|
| 340 | + girq->default_type = IRQ_TYPE_NONE; |
|---|
| 341 | + girq->handler = handle_bad_irq; |
|---|
| 342 | + |
|---|
| 343 | + ret = devm_gpiochip_add_data(dev, &pl061->gc, pl061); |
|---|
| 344 | + if (ret) |
|---|
| 343 | 345 | return ret; |
|---|
| 344 | | - } |
|---|
| 345 | | - gpiochip_set_chained_irqchip(&pl061->gc, &pl061->irq_chip, |
|---|
| 346 | | - irq, pl061_irq_handler); |
|---|
| 347 | 346 | |
|---|
| 348 | 347 | amba_set_drvdata(adev, pl061); |
|---|
| 349 | | - dev_info(&adev->dev, "PL061 GPIO chip @%pa registered\n", |
|---|
| 350 | | - &adev->res.start); |
|---|
| 348 | + dev_info(dev, "PL061 GPIO chip registered\n"); |
|---|
| 351 | 349 | |
|---|
| 352 | 350 | return 0; |
|---|
| 353 | 351 | } |
|---|
| .. | .. |
|---|
| 411 | 409 | }, |
|---|
| 412 | 410 | { 0, 0 }, |
|---|
| 413 | 411 | }; |
|---|
| 412 | +MODULE_DEVICE_TABLE(amba, pl061_ids); |
|---|
| 414 | 413 | |
|---|
| 415 | 414 | static struct amba_driver pl061_gpio_driver = { |
|---|
| 416 | 415 | .drv = { |
|---|
| .. | .. |
|---|
| 422 | 421 | .id_table = pl061_ids, |
|---|
| 423 | 422 | .probe = pl061_probe, |
|---|
| 424 | 423 | }; |
|---|
| 424 | +module_amba_driver(pl061_gpio_driver); |
|---|
| 425 | 425 | |
|---|
| 426 | | -static int __init pl061_gpio_init(void) |
|---|
| 427 | | -{ |
|---|
| 428 | | - return amba_driver_register(&pl061_gpio_driver); |
|---|
| 429 | | -} |
|---|
| 430 | | -device_initcall(pl061_gpio_init); |
|---|
| 426 | +MODULE_LICENSE("GPL v2"); |
|---|