Skip to content

Commit

Permalink
gpio / ACPI: Allocate ACPI specific data directly in acpi_gpiochip_add()
Browse files Browse the repository at this point in the history
We are going to add more ACPI specific data to accompany GPIO chip so
instead of allocating it per each use-case we allocate it once when
acpi_gpiochip_add() is called and release it when acpi_gpiochip_remove() is
called.

Doing this allows us to add more ACPI specific data by merely adding new
fields to struct acpi_gpio_chip.

In addition we embed evt_pins member directly to the structure instead of
having it as a pointer. This simplifies the code a bit since we don't need
to check against NULL.

Signed-off-by: Mika Westerberg <[email protected]>
Signed-off-by: Linus Walleij <[email protected]>
  • Loading branch information
westeri authored and linusw committed Mar 13, 2014
1 parent 77c2d79 commit aa92b6f
Showing 1 changed file with 64 additions and 42 deletions.
106 changes: 64 additions & 42 deletions drivers/gpio/gpiolib-acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ struct acpi_gpio_evt_pin {
unsigned int irq;
};

struct acpi_gpio_chip {
struct gpio_chip *chip;
struct list_head evt_pins;
};

static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
{
if (!gc->dev)
Expand Down Expand Up @@ -81,27 +86,27 @@ static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data)
return IRQ_HANDLED;
}

static void acpi_gpio_evt_dh(acpi_handle handle, void *data)
static void acpi_gpio_chip_dh(acpi_handle handle, void *data)
{
/* The address of this function is used as a key. */
}

/**
* acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
* @chip: gpio chip
* @acpi_gpio: ACPI GPIO chip
*
* ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
* handled by ACPI event methods which need to be called from the GPIO
* chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which
* gpio pins have acpi event methods and assigns interrupt handlers that calls
* the acpi event methods for those pins.
*/
static void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio)
{
struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
struct gpio_chip *chip = acpi_gpio->chip;
struct acpi_resource *res;
acpi_handle handle, evt_handle;
struct list_head *evt_pins = NULL;
acpi_status status;
unsigned int pin;
int irq, ret;
Expand All @@ -114,23 +119,7 @@ static void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
if (!handle)
return;

status = acpi_get_event_resources(handle, &buf);
if (ACPI_FAILURE(status))
return;

status = acpi_get_handle(handle, "_EVT", &evt_handle);
if (ACPI_SUCCESS(status)) {
evt_pins = kzalloc(sizeof(*evt_pins), GFP_KERNEL);
if (evt_pins) {
INIT_LIST_HEAD(evt_pins);
status = acpi_attach_data(handle, acpi_gpio_evt_dh,
evt_pins);
if (ACPI_FAILURE(status)) {
kfree(evt_pins);
evt_pins = NULL;
}
}
}
INIT_LIST_HEAD(&acpi_gpio->evt_pins);

/*
* If a GPIO interrupt has an ACPI event handler method, or _EVT is
Expand Down Expand Up @@ -167,14 +156,18 @@ static void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
data = ev_handle;
}
}
if (!handler && evt_pins) {
if (!handler) {
struct acpi_gpio_evt_pin *evt_pin;

status = acpi_get_handle(handle, "_EVT", &evt_handle);
if (ACPI_FAILURE(status))
continue

evt_pin = kzalloc(sizeof(*evt_pin), GFP_KERNEL);
if (!evt_pin)
continue;

list_add_tail(&evt_pin->node, evt_pins);
list_add_tail(&evt_pin->node, &acpi_gpio->evt_pins);
evt_pin->evt_handle = evt_handle;
evt_pin->pin = pin;
evt_pin->irq = irq;
Expand All @@ -197,39 +190,27 @@ static void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)

/**
* acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts.
* @chip: gpio chip
* @acpi_gpio: ACPI GPIO chip
*
* Free interrupts associated with the _EVT method for the given GPIO chip.
*
* The remaining ACPI event interrupts associated with the chip are freed
* automatically.
*/
static void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio)
{
acpi_handle handle;
acpi_status status;
struct list_head *evt_pins;
struct acpi_gpio_evt_pin *evt_pin, *ep;
struct gpio_chip *chip = acpi_gpio->chip;

if (!chip->dev || !chip->to_irq)
return;

handle = ACPI_HANDLE(chip->dev);
if (!handle)
return;

status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins);
if (ACPI_FAILURE(status))
return;

list_for_each_entry_safe_reverse(evt_pin, ep, evt_pins, node) {
list_for_each_entry_safe_reverse(evt_pin, ep, &acpi_gpio->evt_pins,
node) {
devm_free_irq(chip->dev, evt_pin->irq, evt_pin);
list_del(&evt_pin->node);
kfree(evt_pin);
}

acpi_detach_data(handle, acpi_gpio_evt_dh);
kfree(evt_pins);
}

struct acpi_gpio_lookup {
Expand Down Expand Up @@ -312,10 +293,51 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,

void acpi_gpiochip_add(struct gpio_chip *chip)
{
acpi_gpiochip_request_interrupts(chip);
struct acpi_gpio_chip *acpi_gpio;
acpi_handle handle;
acpi_status status;

handle = ACPI_HANDLE(chip->dev);
if (!handle)
return;

acpi_gpio = kzalloc(sizeof(*acpi_gpio), GFP_KERNEL);
if (!acpi_gpio) {
dev_err(chip->dev,
"Failed to allocate memory for ACPI GPIO chip\n");
return;
}

acpi_gpio->chip = chip;

status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio);
if (ACPI_FAILURE(status)) {
dev_err(chip->dev, "Failed to attach ACPI GPIO chip\n");
kfree(acpi_gpio);
return;
}

acpi_gpiochip_request_interrupts(acpi_gpio);
}

void acpi_gpiochip_remove(struct gpio_chip *chip)
{
acpi_gpiochip_free_interrupts(chip);
struct acpi_gpio_chip *acpi_gpio;
acpi_handle handle;
acpi_status status;

handle = ACPI_HANDLE(chip->dev);
if (!handle)
return;

status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
if (ACPI_FAILURE(status)) {
dev_warn(chip->dev, "Failed to retrieve ACPI GPIO chip\n");
return;
}

acpi_gpiochip_free_interrupts(acpi_gpio);

acpi_detach_data(handle, acpi_gpio_chip_dh);
kfree(acpi_gpio);
}

0 comments on commit aa92b6f

Please sign in to comment.