aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib-acpi.c
diff options
context:
space:
mode:
authorRojhalat Ibrahim <imr@rtschenk.de>2015-02-11 11:27:58 -0500
committerLinus Walleij <linus.walleij@linaro.org>2015-03-05 03:52:28 -0500
commit668585273246f67b0cdafa30dd2da2047a2e1290 (patch)
treec6e3186d6aab7d08e0f50b5030be4bef4a8b17df /drivers/gpio/gpiolib-acpi.c
parent7f2e553a7173b485db41a52060f91fb8e5ab1c69 (diff)
gpiolib: add gpiod_get_array and gpiod_put_array functions
Introduce new functions for conveniently obtaining and disposing of an entire array of GPIOs with one function call. ACPI parts tested by Mika Westerberg, DT parts tested by Rojhalat Ibrahim. Change log: v5: move the ACPI functions to gpiolib-acpi.c v4: - use shorter names for members of struct gpio_descs - rename lut_gpio_count to platform_gpio_count for clarity - add check for successful memory allocation - use ERR_CAST() v3: - rebase on current linux-gpio devel branch - fix ACPI GPIO counting - allow for zero-sized arrays - make the flags argument mandatory for the new functions - clarify documentation v2: change interface Suggested-by: Alexandre Courbot <acourbot@nvidia.com> Signed-off-by: Rojhalat Ibrahim <imr@rtschenk.de> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> Tested-by: Rojhalat Ibrahim <imr@rtschenk.de> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
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}