diff options
-rw-r--r-- | drivers/gpio/gpiolib-acpi.c | 43 | ||||
-rw-r--r-- | include/acpi/acpi_bus.h | 3 | ||||
-rw-r--r-- | include/linux/acpi.h | 30 |
3 files changed, 74 insertions, 2 deletions
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 8aa6ca473748..5a4d061e787e 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c | |||
@@ -287,6 +287,41 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) | |||
287 | } | 287 | } |
288 | } | 288 | } |
289 | 289 | ||
290 | int acpi_dev_add_driver_gpios(struct acpi_device *adev, | ||
291 | const struct acpi_gpio_mapping *gpios) | ||
292 | { | ||
293 | if (adev && gpios) { | ||
294 | adev->driver_gpios = gpios; | ||
295 | return 0; | ||
296 | } | ||
297 | return -EINVAL; | ||
298 | } | ||
299 | EXPORT_SYMBOL_GPL(acpi_dev_add_driver_gpios); | ||
300 | |||
301 | static bool acpi_get_driver_gpio_data(struct acpi_device *adev, | ||
302 | const char *name, int index, | ||
303 | struct acpi_reference_args *args) | ||
304 | { | ||
305 | const struct acpi_gpio_mapping *gm; | ||
306 | |||
307 | if (!adev->driver_gpios) | ||
308 | return false; | ||
309 | |||
310 | for (gm = adev->driver_gpios; gm->name; gm++) | ||
311 | if (!strcmp(name, gm->name) && gm->data && index < gm->size) { | ||
312 | const struct acpi_gpio_params *par = gm->data + index; | ||
313 | |||
314 | args->adev = adev; | ||
315 | args->args[0] = par->crs_entry_index; | ||
316 | args->args[1] = par->line_index; | ||
317 | args->args[2] = par->active_low; | ||
318 | args->nargs = 3; | ||
319 | return true; | ||
320 | } | ||
321 | |||
322 | return false; | ||
323 | } | ||
324 | |||
290 | struct acpi_gpio_lookup { | 325 | struct acpi_gpio_lookup { |
291 | struct acpi_gpio_info info; | 326 | struct acpi_gpio_info info; |
292 | int index; | 327 | int index; |
@@ -372,8 +407,12 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, | |||
372 | memset(&args, 0, sizeof(args)); | 407 | memset(&args, 0, sizeof(args)); |
373 | ret = acpi_dev_get_property_reference(adev, propname, NULL, | 408 | ret = acpi_dev_get_property_reference(adev, propname, NULL, |
374 | index, &args); | 409 | index, &args); |
375 | if (ret) | 410 | if (ret) { |
376 | return ERR_PTR(ret); | 411 | bool found = acpi_get_driver_gpio_data(adev, propname, |
412 | index, &args); | ||
413 | if (!found) | ||
414 | return ERR_PTR(ret); | ||
415 | } | ||
377 | 416 | ||
378 | /* | 417 | /* |
379 | * The property was found and resolved so need to | 418 | * The property was found and resolved so need to |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index a361f43b1974..7d1ce40e201e 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
@@ -345,6 +345,8 @@ struct acpi_device_data { | |||
345 | const union acpi_object *of_compatible; | 345 | const union acpi_object *of_compatible; |
346 | }; | 346 | }; |
347 | 347 | ||
348 | struct acpi_gpio_mapping; | ||
349 | |||
348 | /* Device */ | 350 | /* Device */ |
349 | struct acpi_device { | 351 | struct acpi_device { |
350 | int device_type; | 352 | int device_type; |
@@ -366,6 +368,7 @@ struct acpi_device { | |||
366 | struct acpi_scan_handler *handler; | 368 | struct acpi_scan_handler *handler; |
367 | struct acpi_hotplug_context *hp; | 369 | struct acpi_hotplug_context *hp; |
368 | struct acpi_driver *driver; | 370 | struct acpi_driver *driver; |
371 | const struct acpi_gpio_mapping *driver_gpios; | ||
369 | void *driver_data; | 372 | void *driver_data; |
370 | struct device dev; | 373 | struct device dev; |
371 | unsigned int physical_node_count; | 374 | unsigned int physical_node_count; |
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 5b8802216a93..0902426c4521 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h | |||
@@ -673,6 +673,36 @@ do { \ | |||
673 | #endif | 673 | #endif |
674 | #endif | 674 | #endif |
675 | 675 | ||
676 | struct acpi_gpio_params { | ||
677 | unsigned int crs_entry_index; | ||
678 | unsigned int line_index; | ||
679 | bool active_low; | ||
680 | }; | ||
681 | |||
682 | struct acpi_gpio_mapping { | ||
683 | const char *name; | ||
684 | const struct acpi_gpio_params *data; | ||
685 | unsigned int size; | ||
686 | }; | ||
687 | |||
688 | #if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB) | ||
689 | int acpi_dev_add_driver_gpios(struct acpi_device *adev, | ||
690 | const struct acpi_gpio_mapping *gpios); | ||
691 | |||
692 | static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) | ||
693 | { | ||
694 | if (adev) | ||
695 | adev->driver_gpios = NULL; | ||
696 | } | ||
697 | #else | ||
698 | static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev, | ||
699 | const struct acpi_gpio_mapping *gpios) | ||
700 | { | ||
701 | return -ENXIO; | ||
702 | } | ||
703 | static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {} | ||
704 | #endif | ||
705 | |||
676 | /* Device properties */ | 706 | /* Device properties */ |
677 | 707 | ||
678 | #define MAX_ACPI_REFERENCE_ARGS 8 | 708 | #define MAX_ACPI_REFERENCE_ARGS 8 |