aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib-acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio/gpiolib-acpi.c')
-rw-r--r--drivers/gpio/gpiolib-acpi.c84
1 files changed, 84 insertions, 0 deletions
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index c0929d938ced..c4919966453d 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -712,3 +712,87 @@ void acpi_gpiochip_remove(struct gpio_chip *chip)
712 acpi_detach_data(handle, acpi_gpio_chip_dh); 712 acpi_detach_data(handle, acpi_gpio_chip_dh);
713 kfree(acpi_gpio); 713 kfree(acpi_gpio);
714} 714}
715
716static unsigned int acpi_gpio_package_count(const union acpi_object *obj)
717{
718 const union acpi_object *element = obj->package.elements;
719 const union acpi_object *end = element + obj->package.count;
720 unsigned int count = 0;
721
722 while (element < end) {
723 if (element->type == ACPI_TYPE_LOCAL_REFERENCE)
724 count++;
725
726 element++;
727 }
728 return count;
729}
730
731static int acpi_find_gpio_count(struct acpi_resource *ares, void *data)
732{
733 unsigned int *count = data;
734
735 if (ares->type == ACPI_RESOURCE_TYPE_GPIO)
736 *count += ares->data.gpio.pin_table_length;
737
738 return 1;
739}
740
741/**
742 * acpi_gpio_count - return the number of GPIOs associated with a
743 * device / function or -ENOENT if no GPIO has been
744 * assigned to the requested function.
745 * @dev: GPIO consumer, can be NULL for system-global GPIOs
746 * @con_id: function within the GPIO consumer
747 */
748int acpi_gpio_count(struct device *dev, const char *con_id)
749{
750 struct acpi_device *adev = ACPI_COMPANION(dev);
751 const union acpi_object *obj;
752 const struct acpi_gpio_mapping *gm;
753 int count = -ENOENT;
754 int ret;
755 char propname[32];
756 unsigned int i;
757
758 /* Try first from _DSD */
759 for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
760 if (con_id && strcmp(con_id, "gpios"))
761 snprintf(propname, sizeof(propname), "%s-%s",
762 con_id, gpio_suffixes[i]);
763 else
764 snprintf(propname, sizeof(propname), "%s",
765 gpio_suffixes[i]);
766
767 ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
768 &obj);
769 if (ret == 0) {
770 if (obj->type == ACPI_TYPE_LOCAL_REFERENCE)
771 count = 1;
772 else if (obj->type == ACPI_TYPE_PACKAGE)
773 count = acpi_gpio_package_count(obj);
774 } else if (adev->driver_gpios) {
775 for (gm = adev->driver_gpios; gm->name; gm++)
776 if (strcmp(propname, gm->name) == 0) {
777 count = gm->size;
778 break;
779 }
780 }
781 if (count >= 0)
782 break;
783 }
784
785 /* Then from plain _CRS GPIOs */
786 if (count < 0) {
787 struct list_head resource_list;
788 unsigned int crs_count = 0;
789
790 INIT_LIST_HEAD(&resource_list);
791 acpi_dev_get_resources(adev, &resource_list,
792 acpi_find_gpio_count, &crs_count);
793 acpi_dev_free_resource_list(&resource_list);
794 if (crs_count > 0)
795 count = crs_count;
796 }
797 return count;
798}