Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a31f5c3a authored by Andy Shevchenko's avatar Andy Shevchenko Committed by Linus Walleij
Browse files

gpio: acpi: Override GPIO initialization flags



This allows ACPI GPIO code to modify flags based on
ACPI GpioIo() / GpioInt() resources.

Signed-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Tested-by: default avatarJarkko Nikula <jarkko.nikula@linux.intel.com>
Reviewed-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 2eca25af
Loading
Loading
Loading
Loading
+48 −2
Original line number Diff line number Diff line
@@ -448,6 +448,34 @@ acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio)
	}
}

int
acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update)
{
	int ret = 0;

	/*
	 * Check if the BIOS has IoRestriction with explicitly set direction
	 * and update @flags accordingly. Otherwise use whatever caller asked
	 * for.
	 */
	if (update & GPIOD_FLAGS_BIT_DIR_SET) {
		enum gpiod_flags diff = *flags ^ update;

		/*
		 * Check if caller supplied incompatible GPIO initialization
		 * flags.
		 *
		 * Return %-EINVAL to notify that firmware has different
		 * settings and we are going to use them.
		 */
		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;
	}
	return ret;
}

struct acpi_gpio_lookup {
	struct acpi_gpio_info info;
	int index;
@@ -485,8 +513,11 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
		 * - ACPI_ACTIVE_HIGH == GPIO_ACTIVE_HIGH
		 */
		if (lookup->info.gpioint) {
			lookup->info.flags = GPIOD_IN;
			lookup->info.polarity = agpio->polarity;
			lookup->info.triggering = agpio->triggering;
		} else {
			lookup->info.flags = acpi_gpio_to_gpiod_flags(agpio);
		}

	}
@@ -613,13 +644,14 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
struct gpio_desc *acpi_find_gpio(struct device *dev,
				 const char *con_id,
				 unsigned int idx,
				 enum gpiod_flags flags,
				 enum gpiod_flags *dflags,
				 enum gpio_lookup_flags *lookupflags)
{
	struct acpi_device *adev = ACPI_COMPANION(dev);
	struct acpi_gpio_info info;
	struct gpio_desc *desc;
	char propname[32];
	int err;
	int i;

	/* Try first from _DSD */
@@ -650,7 +682,7 @@ struct gpio_desc *acpi_find_gpio(struct device *dev,
	}

	if (info.gpioint &&
	    (flags == GPIOD_OUT_LOW || flags == GPIOD_OUT_HIGH)) {
	    (*dflags == GPIOD_OUT_LOW || *dflags == GPIOD_OUT_HIGH)) {
		dev_dbg(dev, "refusing GpioInt() entry when doing GPIOD_OUT_* lookup\n");
		return ERR_PTR(-ENOENT);
	}
@@ -658,6 +690,10 @@ struct gpio_desc *acpi_find_gpio(struct device *dev,
	if (info.polarity == GPIO_ACTIVE_LOW)
		*lookupflags |= GPIO_ACTIVE_LOW;

	err = acpi_gpio_update_gpiod_flags(dflags, info.flags);
	if (err)
		dev_dbg(dev, "Override GPIO initialization flags\n");

	return desc;
}

@@ -711,12 +747,16 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
 * used to translate from the GPIO offset in the resource to the Linux IRQ
 * number.
 *
 * The function is idempotent, though each time it runs it will configure GPIO
 * pin direction according to the flags in GpioInt resource.
 *
 * Return: Linux IRQ number (>%0) on success, negative errno on failure.
 */
int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
{
	int idx, i;
	unsigned int irq_flags;
	int ret;

	for (i = 0, idx = 0; idx <= index; i++) {
		struct acpi_gpio_info info;
@@ -729,6 +769,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
			return PTR_ERR(desc);

		if (info.gpioint && idx++ == index) {
			char label[32];
			int irq;

			if (IS_ERR(desc))
@@ -738,6 +779,11 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
			if (irq < 0)
				return irq;

			snprintf(label, sizeof(label), "GpioInt() %d", index);
			ret = gpiod_configure_flags(desc, label, 0, info.flags);
			if (ret < 0)
				return ret;

			irq_flags = acpi_dev_get_irq_type(info.triggering,
							  info.polarity);

+6 −2
Original line number Diff line number Diff line
@@ -3286,7 +3286,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
			desc = of_find_gpio(dev, con_id, idx, &lookupflags);
		} else if (ACPI_COMPANION(dev)) {
			dev_dbg(dev, "using ACPI for GPIO lookup\n");
			desc = acpi_find_gpio(dev, con_id, idx, flags, &lookupflags);
			desc = acpi_find_gpio(dev, con_id, idx, &flags, &lookupflags);
		}
	}

@@ -3367,8 +3367,12 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
		struct acpi_gpio_info info;

		desc = acpi_node_get_gpiod(fwnode, propname, index, &info);
		if (!IS_ERR(desc))
		if (!IS_ERR(desc)) {
			active_low = info.polarity == GPIO_ACTIVE_LOW;
			ret = acpi_gpio_update_gpiod_flags(&dflags, info.flags);
			if (ret)
				pr_debug("Override GPIO initialization flags\n");
		}
	}

	if (IS_ERR(desc))
+13 −2
Original line number Diff line number Diff line
@@ -75,11 +75,13 @@ struct gpio_device {

/**
 * struct acpi_gpio_info - ACPI GPIO specific information
 * @flags: GPIO initialization flags
 * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
 * @polarity: interrupt polarity as provided by ACPI
 * @triggering: triggering type as provided by ACPI
 */
struct acpi_gpio_info {
	enum gpiod_flags flags;
	bool gpioint;
	int polarity;
	int triggering;
@@ -121,10 +123,13 @@ void acpi_gpiochip_remove(struct gpio_chip *chip);
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);

int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags,
				 enum gpiod_flags update);

struct gpio_desc *acpi_find_gpio(struct device *dev,
				 const char *con_id,
				 unsigned int idx,
				 enum gpiod_flags flags,
				 enum gpiod_flags *dflags,
				 enum gpio_lookup_flags *lookupflags);
struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
				      const char *propname, int index,
@@ -143,9 +148,15 @@ acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
static inline void
acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }

static inline int
acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update)
{
	return 0;
}

static inline struct gpio_desc *
acpi_find_gpio(struct device *dev, const char *con_id,
	       unsigned int idx, enum gpiod_flags flags,
	       unsigned int idx, enum gpiod_flags *dflags,
	       enum gpio_lookup_flags *lookupflags)
{
	return ERR_PTR(-ENOENT);