aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-11-03 17:39:41 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-11-04 15:58:24 -0500
commitf028d5242d7ecb0a1bfc80e7bd292201c8612641 (patch)
tree269609af6e6448736a8e831eb8740c6d60947f29
parentb26d4e2283b6d9b65bfe14b99c9c3a560e390a00 (diff)
ACPI / GPIO: Driver GPIO mappings for ACPI GPIOs
Provide a way for device drivers using GPIOs described by ACPI GpioIo resources in _CRS to tell the GPIO subsystem what names (connection IDs) to associate with specific GPIO pins defined in there. To do that, a driver needs to define a mapping table as a NULL-terminated array of struct acpi_gpio_mapping objects that each contain a name, a pointer to an array of line data (struct acpi_gpio_params) objects and the size of that array. Each struct acpi_gpio_params object consists of three fields, crs_entry_index, line_index, active_low, representing the index of the target GpioIo()/GpioInt() resource in _CRS starting from zero, the index of the target line in that resource starting from zero, and the active-low flag for that line, respectively. Next, the mapping table needs to be passed as the second argument to acpi_dev_add_driver_gpios() that will register it with the ACPI device object pointed to by its first argument. That should be done in the driver's .probe() routine. On removal, the driver should unregister its GPIO mapping table by calling acpi_dev_remove_driver_gpios() on the ACPI device object where that table was previously registered. Included are fixes from Mika Westerberg. Acked-by: Alexandre Courbot <acourbot@nvidia.com> Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/gpio/gpiolib-acpi.c43
-rw-r--r--include/acpi/acpi_bus.h3
-rw-r--r--include/linux/acpi.h30
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
290int 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}
299EXPORT_SYMBOL_GPL(acpi_dev_add_driver_gpios);
300
301static 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
290struct acpi_gpio_lookup { 325struct 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
348struct acpi_gpio_mapping;
349
348/* Device */ 350/* Device */
349struct acpi_device { 351struct 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
676struct acpi_gpio_params {
677 unsigned int crs_entry_index;
678 unsigned int line_index;
679 bool active_low;
680};
681
682struct 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)
689int acpi_dev_add_driver_gpios(struct acpi_device *adev,
690 const struct acpi_gpio_mapping *gpios);
691
692static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
693{
694 if (adev)
695 adev->driver_gpios = NULL;
696}
697#else
698static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
699 const struct acpi_gpio_mapping *gpios)
700{
701 return -ENXIO;
702}
703static 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