summaryrefslogtreecommitdiff
path: root/drivers/gpio/gpiolib-of.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-10-31 17:21:54 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2023-10-31 17:21:54 -1000
commitb05ddad00903b24931cb4b45516f1bc1b5c288f2 (patch)
treec7473f0416eea8035c1beb348edc56c3053164f2 /drivers/gpio/gpiolib-of.c
parentad1871ad8d9b3d252390ade8e2bcab7b773173ad (diff)
parent9bc633117d6a8411c6912cb0194b3e0f83ef9d56 (diff)
Merge tag 'gpio-updates-for-v6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski: "We don't have any new drivers. The loongson driver is getting extended with support for new models. There's a big refactor of gpio-pca953x and many small improvements to others. The GPIO code in the kernel has acquired a lot of cruft over the years as well as many abusers of the API across the kernel tree. This release cycle we have started a major cleanup and improvement effort that will most likely span several releases. We have started by converting external users of struct gpio_chip to accessing the wrapper around it - struct gpio_device. This is because the latter is reference counted while the former is removed when the provider is unbound. We also removed several instances of drivers accessing private GPIOLIB structures and including the private header from drivers/gpio/. To that end you'll see several commits aimed at different subsystems (acked by relevant maintainers) as well as two merges from the x86/platform tree. We'll then rework the locking in GPIOLIB which currently uses a big spinlock for many different things and could use becoming more fine-grained, especially as it doesn't even get the locking right. We'll also use SRCU for protecting the gpio_chip pointer against in-kernel hot-unplug crashes similar to what we saw triggered from user-space and fixed with semaphores in gpiolib-cdev. The core GPIOLIB is still vulnerable to these use-cases. I'm just mentioning the plans here, this is not part of this PR. You'll see some new instances of using __free(). We've added a gpio_device_put cleanup helper similar to the put_device one introduced by Peter Zijlstra and used it according to the preferred pattern except where it didn't make sense. GPIOLIB core: - provide interfaces allowing users to retrieve, manage and query the reference counted GPIO device instead of accessing the private gpio_chip structure - replace gpiochip_find() with gpio_device_find() - remove unused acpi_get_and_request_gpiod() - improve the ignore_interrupt functionality in GPIO ACPI - correct notifier return codes in gpiolib-of - unexport gpiod_set_transitory() as it's unused outside of core GPIO code - while there are still external users accessing struct gpio_chip, let's make gpiochip_get_desc() public so that they at least use the preferred helper - improve locking for lookup tables - annotate struct linereq with __counted_by - improve GPIOLIB docs - add an OF quirk for LED trigger sources Driver improvements: - convert all GPIO drivers with .remove() callbacks to using the new variant returning void instead of int - stop accessing the GPIOLIB private structures in gpio-mockup, i2c-mux-gpio, hte-tegra194, gpio-sim - use the recommended pattern for autofree variables in gpio-sim - add support for more models to gpio-loongson - use a notifier chain to notify other blocks about interrupts in gpio-eic-sprd instead of looking up GPIO devices on every interrupt - convert gpio-pca953x and gpio-fx6408 to using the maple tree regmap cache - don't include GPIOLIB internal headers in drivers which don't need them - move the ingenic NAND quirk into gpiolib-of - add an ignore interrupt quirk for Peaq C1010 - drop static GPIO base from gpio-omap, gpio-f7188x - use the preferred device_get_match_data() function in drivers that still don't - refactor gpio-pca953x: switch to using DEFINE_SIMPLE_DEV_PM_OPS(), use cleanup helpers, use dev_err_probe() where it makes sense, fully convert to using devres and some other minor tweaks DT bindings: - add support for a new model to gpio-vf610 and update existing properties - add support for more loongson models - add missing support for imx models that are used but undocumented - convert bindings for Intel IXP4xx to schema Minor stuff: - deprecate gpio-mockup in favor of gpio-sim - include missing headers here and there - stop using gpiochip_find() in OMAP1 board files - minor tweaks in gpio-vf610, gpio-hisi - remove unneeded 'extern' specifiers from headers" * tag 'gpio-updates-for-v6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (108 commits) hte: tegra194: add GPIOLIB dependency hte: tegra194: don't access struct gpio_chip gpiolib: provide gpio_device_get_base() i2c: mux: gpio: don't fiddle with GPIOLIB internals gpiolib: provide gpiod_to_gpio_device() gpiolib: provide gpio_device_to_device() gpio: hisi: Fix format specifier gpiolib: provide gpio_device_find_by_fwnode() gpio: acpi: remove acpi_get_and_request_gpiod() gpio: Use device_get_match_data() gpio: vf610: update comment for i.MX8ULP and i.MX93 legacy compatibles platform/x86: int3472: Switch to devm_get_gpiod() platform/x86: int3472: Stop using gpiod_toggle_active_low() platform/x86: int3472: Add new skl_int3472_gpiod_get_from_temp_lookup() helper platform/x86: int3472: Add new skl_int3472_fill_gpiod_lookup() helper gpio: vf610: simplify code by dropping data check gpio: vf610: add i.MX8ULP of_device_id entry dt-bindings: gpio: vf610: add i.MX95 compatible dt-bindings: gpio: vf610: correct i.MX8ULP and i.MX93 dt-bindings: gpio: vf610: update gpio-ranges ...
Diffstat (limited to 'drivers/gpio/gpiolib-of.c')
-rw-r--r--drivers/gpio/gpiolib-of.c86
1 files changed, 62 insertions, 24 deletions
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 531faabead0f..a4b48d53ab4d 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -127,10 +127,10 @@ static int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, void *data)
chip->of_xlate(chip, gpiospec, NULL) >= 0;
}
-static struct gpio_chip *of_find_gpiochip_by_xlate(
- struct of_phandle_args *gpiospec)
+static struct gpio_device *
+of_find_gpio_device_by_xlate(struct of_phandle_args *gpiospec)
{
- return gpiochip_find(gpiospec, of_gpiochip_match_node_and_xlate);
+ return gpio_device_find(gpiospec, of_gpiochip_match_node_and_xlate);
}
static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
@@ -192,6 +192,15 @@ static void of_gpio_try_fixup_polarity(const struct device_node *np,
*/
{ "himax,hx8357", "gpios-reset", false },
{ "himax,hx8369", "gpios-reset", false },
+ /*
+ * The rb-gpios semantics was undocumented and qi,lb60 (along with
+ * the ingenic driver) got it wrong. The active state encodes the
+ * NAND ready state, which is high level. Since there's no signal
+ * inverter on this board, it should be active-high. Let's fix that
+ * here for older DTs so we can re-use the generic nand_gpio_waitrdy()
+ * helper, and be consistent with what other drivers do.
+ */
+ { "qi,lb60", "rb-gpios", true },
#endif
};
unsigned int i;
@@ -363,7 +372,6 @@ static struct gpio_desc *of_get_named_gpiod_flags(const struct device_node *np,
const char *propname, int index, enum of_gpio_flags *flags)
{
struct of_phandle_args gpiospec;
- struct gpio_chip *chip;
struct gpio_desc *desc;
int ret;
@@ -375,13 +383,15 @@ static struct gpio_desc *of_get_named_gpiod_flags(const struct device_node *np,
return ERR_PTR(ret);
}
- chip = of_find_gpiochip_by_xlate(&gpiospec);
- if (!chip) {
+ struct gpio_device *gdev __free(gpio_device_put) =
+ of_find_gpio_device_by_xlate(&gpiospec);
+ if (!gdev) {
desc = ERR_PTR(-EPROBE_DEFER);
goto out;
}
- desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, flags);
+ desc = of_xlate_and_get_gpiod_flags(gpio_device_get_chip(gdev),
+ &gpiospec, flags);
if (IS_ERR(desc))
goto out;
@@ -611,6 +621,33 @@ static struct gpio_desc *of_find_mt2701_gpio(struct device_node *np,
return desc;
}
+/*
+ * Trigger sources are special, they allow us to use any GPIO as a LED trigger
+ * and have the name "trigger-sources" no matter which kind of phandle it is
+ * pointing to, whether to a GPIO, a USB host, a network PHY etc. So in this case
+ * we allow looking something up that is not named "foo-gpios".
+ */
+static struct gpio_desc *of_find_trigger_gpio(struct device_node *np,
+ const char *con_id,
+ unsigned int idx,
+ enum of_gpio_flags *of_flags)
+{
+ struct gpio_desc *desc;
+
+ if (!IS_ENABLED(CONFIG_LEDS_TRIGGER_GPIO))
+ return ERR_PTR(-ENOENT);
+
+ if (!con_id || strcmp(con_id, "trigger-sources"))
+ return ERR_PTR(-ENOENT);
+
+ desc = of_get_named_gpiod_flags(np, con_id, idx, of_flags);
+ if (!gpiod_not_found(desc))
+ pr_debug("%s is used as a trigger\n", of_node_full_name(np));
+
+ return desc;
+}
+
+
typedef struct gpio_desc *(*of_find_gpio_quirk)(struct device_node *np,
const char *con_id,
unsigned int idx,
@@ -618,6 +655,7 @@ typedef struct gpio_desc *(*of_find_gpio_quirk)(struct device_node *np,
static const of_find_gpio_quirk of_find_gpio_quirks[] = {
of_find_gpio_rename,
of_find_mt2701_gpio,
+ of_find_trigger_gpio,
NULL
};
@@ -813,16 +851,16 @@ static int of_gpiochip_match_node(struct gpio_chip *chip, void *data)
return device_match_of_node(&chip->gpiodev->dev, data);
}
-static struct gpio_chip *of_find_gpiochip_by_node(struct device_node *np)
+static struct gpio_device *of_find_gpio_device_by_node(struct device_node *np)
{
- return gpiochip_find(np, of_gpiochip_match_node);
+ return gpio_device_find(np, of_gpiochip_match_node);
}
static int of_gpio_notify(struct notifier_block *nb, unsigned long action,
void *arg)
{
+ struct gpio_device *gdev __free(gpio_device_put) = NULL;
struct of_reconfig_data *rd = arg;
- struct gpio_chip *chip;
int ret;
/*
@@ -834,38 +872,38 @@ static int of_gpio_notify(struct notifier_block *nb, unsigned long action,
switch (of_reconfig_get_state_change(action, arg)) {
case OF_RECONFIG_CHANGE_ADD:
if (!of_property_read_bool(rd->dn, "gpio-hog"))
- return NOTIFY_OK; /* not for us */
+ return NOTIFY_DONE; /* not for us */
if (of_node_test_and_set_flag(rd->dn, OF_POPULATED))
- return NOTIFY_OK;
+ return NOTIFY_DONE;
- chip = of_find_gpiochip_by_node(rd->dn->parent);
- if (chip == NULL)
- return NOTIFY_OK; /* not for us */
+ gdev = of_find_gpio_device_by_node(rd->dn->parent);
+ if (!gdev)
+ return NOTIFY_DONE; /* not for us */
- ret = of_gpiochip_add_hog(chip, rd->dn);
+ ret = of_gpiochip_add_hog(gpio_device_get_chip(gdev), rd->dn);
if (ret < 0) {
pr_err("%s: failed to add hogs for %pOF\n", __func__,
rd->dn);
of_node_clear_flag(rd->dn, OF_POPULATED);
return notifier_from_errno(ret);
}
- break;
+ return NOTIFY_OK;
case OF_RECONFIG_CHANGE_REMOVE:
if (!of_node_check_flag(rd->dn, OF_POPULATED))
- return NOTIFY_OK; /* already depopulated */
+ return NOTIFY_DONE; /* already depopulated */
- chip = of_find_gpiochip_by_node(rd->dn->parent);
- if (chip == NULL)
- return NOTIFY_OK; /* not for us */
+ gdev = of_find_gpio_device_by_node(rd->dn->parent);
+ if (!gdev)
+ return NOTIFY_DONE; /* not for us */
- of_gpiochip_remove_hog(chip, rd->dn);
+ of_gpiochip_remove_hog(gpio_device_get_chip(gdev), rd->dn);
of_node_clear_flag(rd->dn, OF_POPULATED);
- break;
+ return NOTIFY_OK;
}
- return NOTIFY_OK;
+ return NOTIFY_DONE;
}
struct notifier_block gpio_of_notifier = {