aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
authorMarek Vasut2023-08-02 01:26:02 +0200
committerTom Rini2023-08-14 17:55:53 -0400
commitaaf5b5923054efbf1244dc7fbae68d0bd2a03cf7 (patch)
tree08e3baf6377c2ca050e116d5306841fa273dbceb /drivers/gpio
parentf7ee9f3d362a05cc3f7e04d0ceb373c2aea80de6 (diff)
gpio: Use separate bitfield array to indicate GPIO is claimed
The current gpio-uclass design uses name field in struct gpio_dev_priv as an indicator that GPIO is claimed by consumer. This overloads the function of name field and does not work well for named pins not configured as GPIO pins. Introduce separate bitfield array as the claim indicator. This unbreaks dual-purpose AF and GPIO operation on STM32MP since commit 2c38f7c31806 ("pinctrl: pinctrl_stm32: Populate uc_priv->name[] with pinmux node's name") where any pin which has already been configured as AF could no longer be claimed as dual-purpose GPIO. This is important for pins like STM32 MMCI st,cmd-gpios . Signed-off-by: Marek Vasut <marex@denx.de> Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/gpio-uclass.c64
1 files changed, 59 insertions, 5 deletions
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 31027f3d990..fc395c97a28 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -28,6 +28,8 @@
DECLARE_GLOBAL_DATA_PTR;
+#define GPIO_ALLOC_BITS 32
+
/**
* gpio_desc_init() - Initialize the GPIO descriptor
*
@@ -75,6 +77,46 @@ static int gpio_to_device(unsigned int gpio, struct gpio_desc *desc)
return -ENOENT;
}
+/**
+ * gpio_is_claimed() - Test whether GPIO is claimed by consumer
+ *
+ * Test whether GPIO is claimed by consumer already.
+ *
+ * @uc_priv: gpio_dev_priv pointer.
+ * @offset: gpio offset within the device
+ * @return: true if claimed, false if not claimed
+ */
+static bool gpio_is_claimed(struct gpio_dev_priv *uc_priv, unsigned int offset)
+{
+ return !!(uc_priv->claimed[offset / GPIO_ALLOC_BITS] & BIT(offset % GPIO_ALLOC_BITS));
+}
+
+/**
+ * gpio_set_claim() - Set GPIO claimed by consumer
+ *
+ * Set a bit which indicate the GPIO is claimed by consumer
+ *
+ * @uc_priv: gpio_dev_priv pointer.
+ * @offset: gpio offset within the device
+ */
+static void gpio_set_claim(struct gpio_dev_priv *uc_priv, unsigned int offset)
+{
+ uc_priv->claimed[offset / GPIO_ALLOC_BITS] |= BIT(offset % GPIO_ALLOC_BITS);
+}
+
+/**
+ * gpio_clear_claim() - Clear GPIO claimed by consumer
+ *
+ * Clear a bit which indicate the GPIO is claimed by consumer
+ *
+ * @uc_priv: gpio_dev_priv pointer.
+ * @offset: gpio offset within the device
+ */
+static void gpio_clear_claim(struct gpio_dev_priv *uc_priv, unsigned int offset)
+{
+ uc_priv->claimed[offset / GPIO_ALLOC_BITS] &= ~BIT(offset % GPIO_ALLOC_BITS);
+}
+
#if CONFIG_IS_ENABLED(DM_GPIO_LOOKUP_LABEL)
/**
* dm_gpio_lookup_label() - look for name in gpio device
@@ -94,7 +136,7 @@ static int dm_gpio_lookup_label(const char *name,
*offset = -1;
for (i = 0; i < uc_priv->gpio_count; i++) {
- if (!uc_priv->name[i])
+ if (!gpio_is_claimed(uc_priv, i))
continue;
if (!strcmp(name, uc_priv->name[i])) {
*offset = i;
@@ -350,7 +392,7 @@ int dm_gpio_request(struct gpio_desc *desc, const char *label)
int ret;
uc_priv = dev_get_uclass_priv(dev);
- if (uc_priv->name[desc->offset])
+ if (gpio_is_claimed(uc_priv, desc->offset))
return -EBUSY;
str = strdup(label);
if (!str)
@@ -362,6 +404,8 @@ int dm_gpio_request(struct gpio_desc *desc, const char *label)
return ret;
}
}
+
+ gpio_set_claim(uc_priv, desc->offset);
uc_priv->name[desc->offset] = str;
return 0;
@@ -438,7 +482,7 @@ int _dm_gpio_free(struct udevice *dev, uint offset)
int ret;
uc_priv = dev_get_uclass_priv(dev);
- if (!uc_priv->name[offset])
+ if (!gpio_is_claimed(uc_priv, offset))
return -ENXIO;
if (ops->rfree) {
ret = ops->rfree(dev, offset);
@@ -446,6 +490,7 @@ int _dm_gpio_free(struct udevice *dev, uint offset)
return ret;
}
+ gpio_clear_claim(uc_priv, offset);
free(uc_priv->name[offset]);
uc_priv->name[offset] = NULL;
@@ -480,7 +525,7 @@ static int check_reserved(const struct gpio_desc *desc, const char *func)
return -ENOENT;
uc_priv = dev_get_uclass_priv(desc->dev);
- if (!uc_priv->name[desc->offset]) {
+ if (!gpio_is_claimed(uc_priv, desc->offset)) {
printf("%s: %s: error: gpio %s%d not reserved\n",
desc->dev->name, func,
uc_priv->bank_name ? uc_priv->bank_name : "",
@@ -826,7 +871,7 @@ static int get_function(struct udevice *dev, int offset, bool skip_unused,
return -EINVAL;
if (namep)
*namep = uc_priv->name[offset];
- if (skip_unused && !uc_priv->name[offset])
+ if (skip_unused && !gpio_is_claimed(uc_priv, offset))
return GPIOF_UNUSED;
if (ops->get_function) {
int ret;
@@ -1341,6 +1386,14 @@ static int gpio_post_probe(struct udevice *dev)
if (!uc_priv->name)
return -ENOMEM;
+ uc_priv->claimed = calloc(DIV_ROUND_UP(uc_priv->gpio_count,
+ GPIO_ALLOC_BITS),
+ GPIO_ALLOC_BITS / 8);
+ if (!uc_priv->claimed) {
+ free(uc_priv->name);
+ return -ENOMEM;
+ }
+
return gpio_renumber(NULL);
}
@@ -1353,6 +1406,7 @@ static int gpio_pre_remove(struct udevice *dev)
if (uc_priv->name[i])
free(uc_priv->name[i]);
}
+ free(uc_priv->claimed);
free(uc_priv->name);
return gpio_renumber(dev);