aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2015-12-15 10:23:43 -0800
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2015-12-15 10:23:43 -0800
commit7f0ad5396a22c061c3c724c299848b4bc2440de5 (patch)
tree3685069aaecb43ff57bf7fdc09ed1432c69ed622
parentLinux 4.4-rc5 (diff)
parentgpiolib: tighten up ACPI legacy gpio lookups (diff)
downloadlinux-dev-7f0ad5396a22c061c3c724c299848b4bc2440de5.tar.xz
linux-dev-7f0ad5396a22c061c3c724c299848b4bc2440de5.zip
Merge branch 'for-dmitry' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio into goodix
Bring in changes to ACPI GPIOLIB to better handle legacy ACPI mappings needed for subsequent Goodix driver changes.
-rw-r--r--drivers/gpio/gpiolib-acpi.c43
-rw-r--r--drivers/gpio/gpiolib.c3
-rw-r--r--drivers/gpio/gpiolib.h8
3 files changed, 54 insertions, 0 deletions
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 16a7b6816744..7ab7bc3c9300 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -922,3 +922,46 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
}
return count;
}
+
+struct acpi_crs_lookup {
+ struct list_head node;
+ struct acpi_device *adev;
+ const char *con_id;
+};
+
+static DEFINE_MUTEX(acpi_crs_lookup_lock);
+static LIST_HEAD(acpi_crs_lookup_list);
+
+bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id)
+{
+ struct acpi_crs_lookup *l, *lookup = NULL;
+
+ /* Never allow fallback if the device has properties */
+ if (adev->data.properties || adev->driver_gpios)
+ return false;
+
+ mutex_lock(&acpi_crs_lookup_lock);
+
+ list_for_each_entry(l, &acpi_crs_lookup_list, node) {
+ if (l->adev == adev) {
+ lookup = l;
+ break;
+ }
+ }
+
+ if (!lookup) {
+ lookup = kmalloc(sizeof(*lookup), GFP_KERNEL);
+ if (lookup) {
+ lookup->adev = adev;
+ lookup->con_id = con_id;
+ list_add_tail(&lookup->node, &acpi_crs_lookup_list);
+ }
+ }
+
+ mutex_unlock(&acpi_crs_lookup_lock);
+
+ return lookup &&
+ ((!lookup->con_id && !con_id) ||
+ (lookup->con_id && con_id &&
+ strcmp(lookup->con_id, con_id) == 0));
+}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 2a91f3287e3b..c8a1e884da74 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1868,6 +1868,9 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
/* Then from plain _CRS GPIOs */
if (IS_ERR(desc)) {
+ if (!acpi_can_fallback_to_crs(adev, con_id))
+ return ERR_PTR(-ENOENT);
+
desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
if (IS_ERR(desc))
return desc;
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 98ab08c0aa2d..2b87cbd68478 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -47,6 +47,8 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
struct acpi_gpio_info *info);
int acpi_gpio_count(struct device *dev, const char *con_id);
+
+bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id);
#else
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
@@ -73,6 +75,12 @@ static inline int acpi_gpio_count(struct device *dev, const char *con_id)
{
return -ENODEV;
}
+
+static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
+ const char *con_id)
+{
+ return false;
+}
#endif
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,