summaryrefslogtreecommitdiff
path: root/drivers/gpio/gpiolib-acpi.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-12-11 10:43:14 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-11 10:43:14 -0800
commitc1b30e4d9466000c0e287e9245d4397da4d7d2f9 (patch)
tree18ac4c6bb435202cee8e7281f58b0c72f7fa0144 /drivers/gpio/gpiolib-acpi.c
parent92a578b064d0227a3a7fbbdb9e29dbab7f8d400e (diff)
parent853b6bf044dcced57c523dbddabf8942e907be6e (diff)
Merge tag 'pinctrl-v3.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl
Pull pin control changes from Linus Walleij: "Here is a stash of pin control changes I have collected for the v3.19 series. Mainly new hardware support, with Intels new embedded SoC as the especially interesting thing standing out, fully using the subsystem. - Force conversion of the ux500 pin control device trees and parsers to use the generic pin control bindings. - New driver and device tree bindings for the Qualcomm PMIC MPP pin controller and GPIO. - Some ACPI infrastructure for pin controllers. - New driver for the Intel CherryView/Braswell pin controller, the first Intel pin controller to fully take advantage of the pin control subsystem. - Support the Freescale i.MX VF610 variant. - Support the sunxi A80 variant. - Support the Samsung Exynos 4415 and Exynos 7 variants. - Split out Intel pin controllers to their own subdirectory. - A large slew of rockchip pin control updates, including suspend/resume support. - A large slew of Samsung Exynos pin controller updates. - Various minor updates and fixes" * tag 'pinctrl-v3.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (49 commits) pinctrl: at91: enhance (debugfs) at91_gpio_dbg_show pinctrl: meson: add device tree bindings documentation gpio: tz1090: Fix error handling of irq_of_parse_and_map pinctrl: tz1090-pinctrl.txt: Fix typo in binding pinctrl: pinconf-generic: Declare dt_params/conf_items const pinctrl: exynos: Add support for Exynos4415 pinctrl: exynos: Add initial driver data for Exynos7 pinctrl: exynos: Add irq_chip instance for Exynos7 wakeup interrupts pinctrl: exynos: Consolidate irq domain callbacks pinctrl: exynos: Generalize the eint16_31 demux code pinctrl: samsung: Separate per-bank init and runtime data pinctrl: samsung: Constify samsung_pin_ctrl struct pinctrl: samsung: Constify samsung_pin_bank_type struct pinctrl: samsung: Drop unused label field in samsung_pin_ctrl struct pinctrl: samsung: Make samsung_pinctrl_get_soc_data use ERR_PTR() pinctrl: Add Intel Cherryview/Braswell pin controller support gpio / ACPI: Add knowledge about pin controllers to acpi_get_gpiod() pinctrl: Fix path error in documentation pinctrl: rockchip: save and restore gpio6_c6 pinmux in suspend/resume pinctrl: rockchip: add suspend/resume functions ...
Diffstat (limited to 'drivers/gpio/gpiolib-acpi.c')
-rw-r--r--drivers/gpio/gpiolib-acpi.c62
1 files changed, 59 insertions, 3 deletions
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index ba98bb59a58f..c3bdaff71c25 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -11,12 +11,14 @@
*/
#include <linux/errno.h>
+#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/export.h>
#include <linux/acpi.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
+#include <linux/pinctrl/pinctrl.h>
#include "gpiolib.h"
@@ -55,6 +57,58 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
return ACPI_HANDLE(gc->dev) == data;
}
+#ifdef CONFIG_PINCTRL
+/**
+ * acpi_gpiochip_pin_to_gpio_offset() - translates ACPI GPIO to Linux GPIO
+ * @chip: GPIO chip
+ * @pin: ACPI GPIO pin number from GpioIo/GpioInt resource
+ *
+ * Function takes ACPI GpioIo/GpioInt pin number as a parameter and
+ * translates it to a corresponding offset suitable to be passed to a
+ * GPIO controller driver.
+ *
+ * Typically the returned offset is same as @pin, but if the GPIO
+ * controller uses pin controller and the mapping is not contigous the
+ * offset might be different.
+ */
+static int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip, int pin)
+{
+ struct gpio_pin_range *pin_range;
+
+ /* If there are no ranges in this chip, use 1:1 mapping */
+ if (list_empty(&chip->pin_ranges))
+ return pin;
+
+ list_for_each_entry(pin_range, &chip->pin_ranges, node) {
+ const struct pinctrl_gpio_range *range = &pin_range->range;
+ int i;
+
+ if (range->pins) {
+ for (i = 0; i < range->npins; i++) {
+ if (range->pins[i] == pin)
+ return range->base + i - chip->base;
+ }
+ } else {
+ if (pin >= range->pin_base &&
+ pin < range->pin_base + range->npins) {
+ unsigned gpio_base;
+
+ gpio_base = range->base - chip->base;
+ return gpio_base + pin - range->pin_base;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+#else
+static inline int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip,
+ int pin)
+{
+ return pin;
+}
+#endif
+
/**
* acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with GPIO API
* @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
@@ -69,6 +123,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
struct gpio_chip *chip;
acpi_handle handle;
acpi_status status;
+ int offset;
status = acpi_get_handle(NULL, path, &handle);
if (ACPI_FAILURE(status))
@@ -78,10 +133,11 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
if (!chip)
return ERR_PTR(-ENODEV);
- if (pin < 0 || pin > chip->ngpio)
- return ERR_PTR(-EINVAL);
+ offset = acpi_gpiochip_pin_to_gpio_offset(chip, pin);
+ if (offset < 0)
+ return ERR_PTR(offset);
- return gpiochip_get_desc(chip, pin);
+ return gpiochip_get_desc(chip, offset);
}
static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)