gpiolib-acpi: Preserve non direction flags when updating gpiod_flags

Message ID 20181230172944.17758-1-hdegoede@redhat.com
State New
Headers show
Series
  • gpiolib-acpi: Preserve non direction flags when updating gpiod_flags
Related show

Commit Message

Hans de Goede Dec. 30, 2018, 5:29 p.m.
__acpi_gpio_update_gpiod_flags purpose is to make the gpiod_flags used
when requesting a GPIO match the restrictions from the ACPI resource,
as stored in acpi_gpio_info.flags.

But acpi_gpio_info.flags only contains direction info, and the
requester may have passed in special non-direction flags like
GPIOD_FLAGS_BIT_NONEXCLUSIVE, which we currently clobber.

This commit modifies __acpi_gpio_update_gpiod_flags to preserve these
special flags, so that a requested of an ACPI GPIO can e.g. pass
GPIOD_FLAGS_BIT_NONEXCLUSIV and have it work as intended.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/gpio/gpiolib-acpi.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

Comments

Mika Westerberg Dec. 31, 2018, 9:34 a.m. | #1
On Sun, Dec 30, 2018 at 06:29:44PM +0100, Hans de Goede wrote:
> __acpi_gpio_update_gpiod_flags purpose is to make the gpiod_flags used
> when requesting a GPIO match the restrictions from the ACPI resource,
> as stored in acpi_gpio_info.flags.
> 
> But acpi_gpio_info.flags only contains direction info, and the
> requester may have passed in special non-direction flags like
> GPIOD_FLAGS_BIT_NONEXCLUSIVE, which we currently clobber.
> 
> This commit modifies __acpi_gpio_update_gpiod_flags to preserve these
> special flags, so that a requested of an ACPI GPIO can e.g. pass
> GPIOD_FLAGS_BIT_NONEXCLUSIV and have it work as intended.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>

Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Andy Shevchenko Dec. 31, 2018, 10:50 a.m. | #2
On Sun, Dec 30, 2018 at 06:29:44PM +0100, Hans de Goede wrote:
> __acpi_gpio_update_gpiod_flags purpose is to make the gpiod_flags used
> when requesting a GPIO match the restrictions from the ACPI resource,
> as stored in acpi_gpio_info.flags.
> 
> But acpi_gpio_info.flags only contains direction info, and the
> requester may have passed in special non-direction flags like
> GPIOD_FLAGS_BIT_NONEXCLUSIVE, which we currently clobber.
> 
> This commit modifies __acpi_gpio_update_gpiod_flags to preserve these
> special flags, so that a requested of an ACPI GPIO can e.g. pass
> GPIOD_FLAGS_BIT_NONEXCLUSIV and have it work as intended.

> +		*flags &= ~mask;
> +		*flags |= update & mask;

Minor: I would rather write it in one line

		*flags = (*flags & ~mask) | (update & mask);

Nonetheless,
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Hans de Goede Dec. 31, 2018, 8:43 p.m. | #3
Hi,

On 12/31/18 11:50 AM, Andy Shevchenko wrote:
> On Sun, Dec 30, 2018 at 06:29:44PM +0100, Hans de Goede wrote:
>> __acpi_gpio_update_gpiod_flags purpose is to make the gpiod_flags used
>> when requesting a GPIO match the restrictions from the ACPI resource,
>> as stored in acpi_gpio_info.flags.
>>
>> But acpi_gpio_info.flags only contains direction info, and the
>> requester may have passed in special non-direction flags like
>> GPIOD_FLAGS_BIT_NONEXCLUSIVE, which we currently clobber.
>>
>> This commit modifies __acpi_gpio_update_gpiod_flags to preserve these
>> special flags, so that a requested of an ACPI GPIO can e.g. pass
>> GPIOD_FLAGS_BIT_NONEXCLUSIV and have it work as intended.
> 
>> +		*flags &= ~mask;
>> +		*flags |= update & mask;
> 
> Minor: I would rather write it in one line
> 
> 		*flags = (*flags & ~mask) | (update & mask);

Good idea, the 2 step approach is from before I introduced the
mask helper variable.

I'll send a v2 with this changed.

> Nonetheless,
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

Thanks.

Regards,

Hans

Patch

diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 091a3784720d..a281f9409c06 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -469,6 +469,9 @@  acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio)
 static int
 __acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update)
 {
+	const enum gpiod_flags mask =
+		GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT |
+		GPIOD_FLAGS_BIT_DIR_VAL;
 	int ret = 0;
 
 	/*
@@ -489,7 +492,8 @@  __acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update)
 		if (((*flags & GPIOD_FLAGS_BIT_DIR_SET) && (diff & GPIOD_FLAGS_BIT_DIR_OUT)) ||
 		    ((*flags & GPIOD_FLAGS_BIT_DIR_OUT) && (diff & GPIOD_FLAGS_BIT_DIR_VAL)))
 			ret = -EINVAL;
-		*flags = update;
+		*flags &= ~mask;
+		*flags |= update & mask;
 	}
 	return ret;
 }