linux/drivers/gpio/gpiolib-acpi.c
<<
>>
Prefs
   1/*
   2 * ACPI helpers for GPIO API
   3 *
   4 * Copyright (C) 2012, Intel Corporation
   5 * Authors: Mathias Nyman <mathias.nyman@linux.intel.com>
   6 *          Mika Westerberg <mika.westerberg@linux.intel.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12
  13#include <linux/errno.h>
  14#include <linux/gpio.h>
  15#include <linux/export.h>
  16#include <linux/acpi_gpio.h>
  17#include <linux/acpi.h>
  18#include <linux/interrupt.h>
  19
  20static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
  21{
  22        if (!gc->dev)
  23                return false;
  24
  25        return ACPI_HANDLE(gc->dev) == data;
  26}
  27
  28/**
  29 * acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API
  30 * @path:       ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
  31 * @pin:        ACPI GPIO pin number (0-based, controller-relative)
  32 *
  33 * Returns GPIO number to use with Linux generic GPIO API, or errno error value
  34 */
  35
  36int acpi_get_gpio(char *path, int pin)
  37{
  38        struct gpio_chip *chip;
  39        acpi_handle handle;
  40        acpi_status status;
  41
  42        status = acpi_get_handle(NULL, path, &handle);
  43        if (ACPI_FAILURE(status))
  44                return -ENODEV;
  45
  46        chip = gpiochip_find(handle, acpi_gpiochip_find);
  47        if (!chip)
  48                return -ENODEV;
  49
  50        if (!gpio_is_valid(chip->base + pin))
  51                return -EINVAL;
  52
  53        return chip->base + pin;
  54}
  55EXPORT_SYMBOL_GPL(acpi_get_gpio);
  56
  57
  58static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
  59{
  60        acpi_handle handle = data;
  61
  62        acpi_evaluate_object(handle, NULL, NULL, NULL);
  63
  64        return IRQ_HANDLED;
  65}
  66
  67/**
  68 * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
  69 * @chip:      gpio chip
  70 *
  71 * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
  72 * handled by ACPI event methods which need to be called from the GPIO
  73 * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which
  74 * gpio pins have acpi event methods and assigns interrupt handlers that calls
  75 * the acpi event methods for those pins.
  76 *
  77 * Interrupts are automatically freed on driver detach
  78 */
  79
  80void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
  81{
  82        struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
  83        struct acpi_resource *res;
  84        acpi_handle handle, ev_handle;
  85        acpi_status status;
  86        unsigned int pin;
  87        int irq, ret;
  88        char ev_name[5];
  89
  90        if (!chip->dev || !chip->to_irq)
  91                return;
  92
  93        handle = ACPI_HANDLE(chip->dev);
  94        if (!handle)
  95                return;
  96
  97        status = acpi_get_event_resources(handle, &buf);
  98        if (ACPI_FAILURE(status))
  99                return;
 100
 101        /* If a gpio interrupt has an acpi event handler method, then
 102         * set up an interrupt handler that calls the acpi event handler
 103         */
 104
 105        for (res = buf.pointer;
 106             res && (res->type != ACPI_RESOURCE_TYPE_END_TAG);
 107             res = ACPI_NEXT_RESOURCE(res)) {
 108
 109                if (res->type != ACPI_RESOURCE_TYPE_GPIO ||
 110                    res->data.gpio.connection_type !=
 111                    ACPI_RESOURCE_GPIO_TYPE_INT)
 112                        continue;
 113
 114                pin = res->data.gpio.pin_table[0];
 115                if (pin > chip->ngpio)
 116                        continue;
 117
 118                sprintf(ev_name, "_%c%02X",
 119                res->data.gpio.triggering ? 'E' : 'L', pin);
 120
 121                status = acpi_get_handle(handle, ev_name, &ev_handle);
 122                if (ACPI_FAILURE(status))
 123                        continue;
 124
 125                irq = chip->to_irq(chip, pin);
 126                if (irq < 0)
 127                        continue;
 128
 129                /* Assume BIOS sets the triggering, so no flags */
 130                ret = devm_request_threaded_irq(chip->dev, irq, NULL,
 131                                          acpi_gpio_irq_handler,
 132                                          0,
 133                                          "GPIO-signaled-ACPI-event",
 134                                          ev_handle);
 135                if (ret)
 136                        dev_err(chip->dev,
 137                                "Failed to request IRQ %d ACPI event handler\n",
 138                                irq);
 139        }
 140}
 141EXPORT_SYMBOL(acpi_gpiochip_request_interrupts);
 142
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.