diff options
author | Mika Westerberg <mika.westerberg@linux.intel.com> | 2014-10-29 10:41:01 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-11-04 15:58:22 -0500 |
commit | 0d9a693cc8619b28f0eeb689a554647d42848fde (patch) | |
tree | a5df01e1767f6a537531ad5bfc69cb9b2097bdf6 /drivers/gpio/gpiolib-acpi.c | |
parent | f60e7074902a66d9a132a971ecda63ee5b8bc154 (diff) |
gpio / ACPI: Add support for _DSD device properties
With release of ACPI 5.1 and _DSD method we can finally name GPIOs (and
other things as well) returned by _CRS. Previously we were only able to
use integer index to find the corresponding GPIO, which is pretty error
prone if the order changes.
With _DSD we can now query GPIOs using name instead of an integer index,
like the below example shows:
// Bluetooth device with reset and shutdown GPIOs
Device (BTH)
{
Name (_HID, ...)
Name (_CRS, ResourceTemplate ()
{
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
"\\_SB.GPO0", 0, ResourceConsumer) {15}
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
"\\_SB.GPO0", 0, ResourceConsumer) {27, 31}
})
Name (_DSD, Package ()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package ()
{
Package () {"reset-gpio", Package() {^BTH, 1, 1, 0 }},
Package () {"shutdown-gpio", Package() {^BTH, 0, 0, 0 }},
}
})
}
The format of the supported GPIO property is:
Package () { "name", Package () { ref, index, pin, active_low }}
ref - The device that has _CRS containing GpioIo()/GpioInt() resources,
typically this is the device itself (BTH in our case).
index - Index of the GpioIo()/GpioInt() resource in _CRS starting from zero.
pin - Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
active_low - If 1 the GPIO is marked as active_low.
Since ACPI GpioIo() resource does not have field saying whether it is
active low or high, the "active_low" argument can be used here. Setting
it to 1 marks the GPIO as active low.
In our Bluetooth example the "reset-gpio" refers to the second GpioIo()
resource, second pin in that resource with the GPIO number of 31.
This patch implements necessary support to gpiolib for extracting GPIOs
using _DSD device properties.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Grant Likely <grant.likely@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/gpio/gpiolib-acpi.c')
-rw-r--r-- | drivers/gpio/gpiolib-acpi.c | 78 |
1 files changed, 64 insertions, 14 deletions
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 05c6275da224..8aa6ca473748 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c | |||
@@ -290,6 +290,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) | |||
290 | struct acpi_gpio_lookup { | 290 | struct acpi_gpio_lookup { |
291 | struct acpi_gpio_info info; | 291 | struct acpi_gpio_info info; |
292 | int index; | 292 | int index; |
293 | int pin_index; | ||
293 | struct gpio_desc *desc; | 294 | struct gpio_desc *desc; |
294 | int n; | 295 | int n; |
295 | }; | 296 | }; |
@@ -303,13 +304,24 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data) | |||
303 | 304 | ||
304 | if (lookup->n++ == lookup->index && !lookup->desc) { | 305 | if (lookup->n++ == lookup->index && !lookup->desc) { |
305 | const struct acpi_resource_gpio *agpio = &ares->data.gpio; | 306 | const struct acpi_resource_gpio *agpio = &ares->data.gpio; |
307 | int pin_index = lookup->pin_index; | ||
308 | |||
309 | if (pin_index >= agpio->pin_table_length) | ||
310 | return 1; | ||
306 | 311 | ||
307 | lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr, | 312 | lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr, |
308 | agpio->pin_table[0]); | 313 | agpio->pin_table[pin_index]); |
309 | lookup->info.gpioint = | 314 | lookup->info.gpioint = |
310 | agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; | 315 | agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; |
311 | lookup->info.active_low = | 316 | |
312 | agpio->polarity == ACPI_ACTIVE_LOW; | 317 | /* |
318 | * ActiveLow is only specified for GpioInt resource. If | ||
319 | * GpioIo is used then the only way to set the flag is | ||
320 | * to use _DSD "gpios" property. | ||
321 | */ | ||
322 | if (lookup->info.gpioint) | ||
323 | lookup->info.active_low = | ||
324 | agpio->polarity == ACPI_ACTIVE_LOW; | ||
313 | } | 325 | } |
314 | 326 | ||
315 | return 1; | 327 | return 1; |
@@ -317,40 +329,75 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data) | |||
317 | 329 | ||
318 | /** | 330 | /** |
319 | * acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources | 331 | * acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources |
320 | * @dev: pointer to a device to get GPIO from | 332 | * @adev: pointer to a ACPI device to get GPIO from |
333 | * @propname: Property name of the GPIO (optional) | ||
321 | * @index: index of GpioIo/GpioInt resource (starting from %0) | 334 | * @index: index of GpioIo/GpioInt resource (starting from %0) |
322 | * @info: info pointer to fill in (optional) | 335 | * @info: info pointer to fill in (optional) |
323 | * | 336 | * |
324 | * Function goes through ACPI resources for @dev and based on @index looks | 337 | * Function goes through ACPI resources for @adev and based on @index looks |
325 | * up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor, | 338 | * up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor, |
326 | * and returns it. @index matches GpioIo/GpioInt resources only so if there | 339 | * and returns it. @index matches GpioIo/GpioInt resources only so if there |
327 | * are total %3 GPIO resources, the index goes from %0 to %2. | 340 | * are total %3 GPIO resources, the index goes from %0 to %2. |
328 | * | 341 | * |
342 | * If @propname is specified the GPIO is looked using device property. In | ||
343 | * that case @index is used to select the GPIO entry in the property value | ||
344 | * (in case of multiple). | ||
345 | * | ||
329 | * If the GPIO cannot be translated or there is an error an ERR_PTR is | 346 | * If the GPIO cannot be translated or there is an error an ERR_PTR is |
330 | * returned. | 347 | * returned. |
331 | * | 348 | * |
332 | * Note: if the GPIO resource has multiple entries in the pin list, this | 349 | * Note: if the GPIO resource has multiple entries in the pin list, this |
333 | * function only returns the first. | 350 | * function only returns the first. |
334 | */ | 351 | */ |
335 | struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, | 352 | struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, |
353 | const char *propname, int index, | ||
336 | struct acpi_gpio_info *info) | 354 | struct acpi_gpio_info *info) |
337 | { | 355 | { |
338 | struct acpi_gpio_lookup lookup; | 356 | struct acpi_gpio_lookup lookup; |
339 | struct list_head resource_list; | 357 | struct list_head resource_list; |
340 | struct acpi_device *adev; | 358 | bool active_low = false; |
341 | acpi_handle handle; | ||
342 | int ret; | 359 | int ret; |
343 | 360 | ||
344 | if (!dev) | 361 | if (!adev) |
345 | return ERR_PTR(-EINVAL); | ||
346 | |||
347 | handle = ACPI_HANDLE(dev); | ||
348 | if (!handle || acpi_bus_get_device(handle, &adev)) | ||
349 | return ERR_PTR(-ENODEV); | 362 | return ERR_PTR(-ENODEV); |
350 | 363 | ||
351 | memset(&lookup, 0, sizeof(lookup)); | 364 | memset(&lookup, 0, sizeof(lookup)); |
352 | lookup.index = index; | 365 | lookup.index = index; |
353 | 366 | ||
367 | if (propname) { | ||
368 | struct acpi_reference_args args; | ||
369 | |||
370 | dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname); | ||
371 | |||
372 | memset(&args, 0, sizeof(args)); | ||
373 | ret = acpi_dev_get_property_reference(adev, propname, NULL, | ||
374 | index, &args); | ||
375 | if (ret) | ||
376 | return ERR_PTR(ret); | ||
377 | |||
378 | /* | ||
379 | * The property was found and resolved so need to | ||
380 | * lookup the GPIO based on returned args instead. | ||
381 | */ | ||
382 | adev = args.adev; | ||
383 | if (args.nargs >= 2) { | ||
384 | lookup.index = args.args[0]; | ||
385 | lookup.pin_index = args.args[1]; | ||
386 | /* | ||
387 | * 3rd argument, if present is used to | ||
388 | * specify active_low. | ||
389 | */ | ||
390 | if (args.nargs >= 3) | ||
391 | active_low = !!args.args[2]; | ||
392 | } | ||
393 | |||
394 | dev_dbg(&adev->dev, "GPIO: _DSD returned %s %zd %llu %llu %llu\n", | ||
395 | dev_name(&adev->dev), args.nargs, | ||
396 | args.args[0], args.args[1], args.args[2]); | ||
397 | } else { | ||
398 | dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index); | ||
399 | } | ||
400 | |||
354 | INIT_LIST_HEAD(&resource_list); | 401 | INIT_LIST_HEAD(&resource_list); |
355 | ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio, | 402 | ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio, |
356 | &lookup); | 403 | &lookup); |
@@ -359,8 +406,11 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, | |||
359 | 406 | ||
360 | acpi_dev_free_resource_list(&resource_list); | 407 | acpi_dev_free_resource_list(&resource_list); |
361 | 408 | ||
362 | if (lookup.desc && info) | 409 | if (lookup.desc && info) { |
363 | *info = lookup.info; | 410 | *info = lookup.info; |
411 | if (active_low) | ||
412 | info->active_low = active_low; | ||
413 | } | ||
364 | 414 | ||
365 | return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT); | 415 | return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT); |
366 | } | 416 | } |