The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH] gpio: regmap: Support sparsed fixed direction
@ 2026-05-07 12:10 Linus Walleij
  2026-05-07 22:13 ` Alex Elder
  0 siblings, 1 reply; 2+ messages in thread
From: Linus Walleij @ 2026-05-07 12:10 UTC (permalink / raw)
  To: Michael Walle, Bartosz Golaszewski
  Cc: linux-gpio, linux-kernel, Alex Elder, Linus Walleij

On some regmapped GPIOs apparently only a sparser selection
of the lines (not all) are actually fixed direction.

Support this situation by adding an optional bitmap indicating
which GPIOs are actually fixed direction and which are not.

Cc: Alex Elder <elder@riscstar.com>
Link: https://lore.kernel.org/linux-gpio/20260501155421.3329862-10-elder@riscstar.com/
Signed-off-by: Linus Walleij <linusw@kernel.org>
---
 drivers/gpio/gpio-regmap.c  | 38 +++++++++++++++++++++++++++++++++-----
 include/linux/gpio/regmap.h |  7 +++++++
 2 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index 9ae4a41a2427..37568dc611f5 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -31,6 +31,7 @@ struct gpio_regmap {
 	unsigned int reg_clr_base;
 	unsigned int reg_dir_in_base;
 	unsigned int reg_dir_out_base;
+	unsigned long *fixed_direction_sparse;
 	unsigned long *fixed_direction_output;
 
 #ifdef CONFIG_REGMAP_IRQ
@@ -138,14 +139,27 @@ static int gpio_regmap_set_with_clear(struct gpio_chip *chip,
 	return regmap_write(gpio->regmap, reg, mask);
 }
 
+static bool gpio_regmap_fixed_direction(struct gpio_regmap *gpio,
+					unsigned int offset)
+{
+	if (!gpio->fixed_direction_output)
+		return false;
+
+	/* In this case only some GPIOs are fixed as input/output */
+	if (gpio->fixed_direction_sparse &&
+	    !test_bit(offset, gpio->fixed_direction_sparse))
+		return false;
+
+	return true;
+}
+
 static int gpio_regmap_get_direction(struct gpio_chip *chip,
 				     unsigned int offset)
 {
 	struct gpio_regmap *gpio = gpiochip_get_data(chip);
 	unsigned int base, val, reg, mask;
 	int invert, ret;
-
-	if (gpio->fixed_direction_output) {
+	if (gpio_regmap_fixed_direction(gpio, offset)) {
 		if (test_bit(offset, gpio->fixed_direction_output))
 			return GPIO_LINE_DIRECTION_OUT;
 		else
@@ -302,12 +316,23 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
 			goto err_free_gpio;
 	}
 
+	if (config->fixed_direction_sparse) {
+		gpio->fixed_direction_sparse = bitmap_alloc(chip->ngpio,
+							    GFP_KERNEL);
+		if (!gpio->fixed_direction_sparse) {
+			ret = -ENOMEM;
+			goto err_free_gpio;
+		}
+		bitmap_copy(gpio->fixed_direction_sparse,
+			    config->fixed_direction_sparse, chip->ngpio);
+	}
+
 	if (config->fixed_direction_output) {
 		gpio->fixed_direction_output = bitmap_alloc(chip->ngpio,
 							    GFP_KERNEL);
 		if (!gpio->fixed_direction_output) {
 			ret = -ENOMEM;
-			goto err_free_gpio;
+			goto err_free_bitmap_sparse;
 		}
 		bitmap_copy(gpio->fixed_direction_output,
 			    config->fixed_direction_output, chip->ngpio);
@@ -329,7 +354,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
 
 	ret = gpiochip_add_data(chip, gpio);
 	if (ret < 0)
-		goto err_free_bitmap;
+		goto err_free_bitmap_output;
 
 #ifdef CONFIG_REGMAP_IRQ
 	if (config->regmap_irq_chip) {
@@ -355,8 +380,10 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
 
 err_remove_gpiochip:
 	gpiochip_remove(chip);
-err_free_bitmap:
+err_free_bitmap_output:
 	bitmap_free(gpio->fixed_direction_output);
+err_free_bitmap_sparse:
+	bitmap_free(gpio->fixed_direction_sparse);
 err_free_gpio:
 	kfree(gpio);
 	return ERR_PTR(ret);
@@ -376,6 +403,7 @@ void gpio_regmap_unregister(struct gpio_regmap *gpio)
 
 	gpiochip_remove(&gpio->gpio_chip);
 	bitmap_free(gpio->fixed_direction_output);
+	bitmap_free(gpio->fixed_direction_sparse);
 	kfree(gpio);
 }
 EXPORT_SYMBOL_GPL(gpio_regmap_unregister);
diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h
index 12d154732ca9..ff00b4aeaf1c 100644
--- a/include/linux/gpio/regmap.h
+++ b/include/linux/gpio/regmap.h
@@ -38,6 +38,12 @@ struct regmap;
  *			offset to a register/bitmask pair. If not
  *			given the default gpio_regmap_simple_xlate()
  *			is used.
+ * @fixed_direction_sparse:
+ *			(Optional) Bitmap representing the GPIO lines that
+ *			make use of the @fixed_direction_output list to
+ *			enforce direction of the GPIO. If this is NULL
+ *			and @fixed_direction_output is defined, ALL GPIOs
+ *			are assumed to be fixed direction (out or in).
  * @fixed_direction_output:
  *			(Optional) Bitmap representing the fixed direction of
  *			the GPIO lines. Useful when there are GPIO lines with a
@@ -89,6 +95,7 @@ struct gpio_regmap_config {
 	int reg_stride;
 	int ngpio_per_reg;
 	struct irq_domain *irq_domain;
+	unsigned long *fixed_direction_sparse;
 	unsigned long *fixed_direction_output;
 
 #ifdef CONFIG_REGMAP_IRQ

---
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
change-id: 20260507-regmap-gpio-sparse-fixed-dir-1d5c0d2e2c6f

Best regards,
--  
Linus Walleij <linusw@kernel.org>


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] gpio: regmap: Support sparsed fixed direction
  2026-05-07 12:10 [PATCH] gpio: regmap: Support sparsed fixed direction Linus Walleij
@ 2026-05-07 22:13 ` Alex Elder
  0 siblings, 0 replies; 2+ messages in thread
From: Alex Elder @ 2026-05-07 22:13 UTC (permalink / raw)
  To: Linus Walleij, Michael Walle, Bartosz Golaszewski
  Cc: linux-gpio, linux-kernel

On 5/7/26 7:10 AM, Linus Walleij wrote:
> On some regmapped GPIOs apparently only a sparser selection
> of the lines (not all) are actually fixed direction.
> 
> Support this situation by adding an optional bitmap indicating
> which GPIOs are actually fixed direction and which are not.
> 
> Cc: Alex Elder <elder@riscstar.com>
> Link: https://lore.kernel.org/linux-gpio/20260501155421.3329862-10-elder@riscstar.com/
> Signed-off-by: Linus Walleij <linusw@kernel.org>

Tested-by: Alex Elder <elder@riscstar.com>

> ---
>   drivers/gpio/gpio-regmap.c  | 38 +++++++++++++++++++++++++++++++++-----
>   include/linux/gpio/regmap.h |  7 +++++++
>   2 files changed, 40 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
> index 9ae4a41a2427..37568dc611f5 100644
> --- a/drivers/gpio/gpio-regmap.c
> +++ b/drivers/gpio/gpio-regmap.c
> @@ -31,6 +31,7 @@ struct gpio_regmap {
>   	unsigned int reg_clr_base;
>   	unsigned int reg_dir_in_base;
>   	unsigned int reg_dir_out_base;
> +	unsigned long *fixed_direction_sparse;
>   	unsigned long *fixed_direction_output;
>   
>   #ifdef CONFIG_REGMAP_IRQ
> @@ -138,14 +139,27 @@ static int gpio_regmap_set_with_clear(struct gpio_chip *chip,
>   	return regmap_write(gpio->regmap, reg, mask);
>   }
>   
> +static bool gpio_regmap_fixed_direction(struct gpio_regmap *gpio,
> +					unsigned int offset)
> +{
> +	if (!gpio->fixed_direction_output)
> +		return false;
> +
> +	/* In this case only some GPIOs are fixed as input/output */
> +	if (gpio->fixed_direction_sparse &&
> +	    !test_bit(offset, gpio->fixed_direction_sparse))
> +		return false;
> +
> +	return true;
> +}
> +
>   static int gpio_regmap_get_direction(struct gpio_chip *chip,
>   				     unsigned int offset)
>   {
>   	struct gpio_regmap *gpio = gpiochip_get_data(chip);
>   	unsigned int base, val, reg, mask;
>   	int invert, ret;
> -
> -	if (gpio->fixed_direction_output) {
> +	if (gpio_regmap_fixed_direction(gpio, offset)) {
>   		if (test_bit(offset, gpio->fixed_direction_output))
>   			return GPIO_LINE_DIRECTION_OUT;
>   		else
> @@ -302,12 +316,23 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
>   			goto err_free_gpio;
>   	}
>   
> +	if (config->fixed_direction_sparse) {
> +		gpio->fixed_direction_sparse = bitmap_alloc(chip->ngpio,
> +							    GFP_KERNEL);
> +		if (!gpio->fixed_direction_sparse) {
> +			ret = -ENOMEM;
> +			goto err_free_gpio;
> +		}
> +		bitmap_copy(gpio->fixed_direction_sparse,
> +			    config->fixed_direction_sparse, chip->ngpio);
> +	}
> +
>   	if (config->fixed_direction_output) {
>   		gpio->fixed_direction_output = bitmap_alloc(chip->ngpio,
>   							    GFP_KERNEL);
>   		if (!gpio->fixed_direction_output) {
>   			ret = -ENOMEM;
> -			goto err_free_gpio;
> +			goto err_free_bitmap_sparse;
>   		}
>   		bitmap_copy(gpio->fixed_direction_output,
>   			    config->fixed_direction_output, chip->ngpio);
> @@ -329,7 +354,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
>   
>   	ret = gpiochip_add_data(chip, gpio);
>   	if (ret < 0)
> -		goto err_free_bitmap;
> +		goto err_free_bitmap_output;
>   
>   #ifdef CONFIG_REGMAP_IRQ
>   	if (config->regmap_irq_chip) {
> @@ -355,8 +380,10 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
>   
>   err_remove_gpiochip:
>   	gpiochip_remove(chip);
> -err_free_bitmap:
> +err_free_bitmap_output:
>   	bitmap_free(gpio->fixed_direction_output);
> +err_free_bitmap_sparse:
> +	bitmap_free(gpio->fixed_direction_sparse);
>   err_free_gpio:
>   	kfree(gpio);
>   	return ERR_PTR(ret);
> @@ -376,6 +403,7 @@ void gpio_regmap_unregister(struct gpio_regmap *gpio)
>   
>   	gpiochip_remove(&gpio->gpio_chip);
>   	bitmap_free(gpio->fixed_direction_output);
> +	bitmap_free(gpio->fixed_direction_sparse);
>   	kfree(gpio);
>   }
>   EXPORT_SYMBOL_GPL(gpio_regmap_unregister);
> diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h
> index 12d154732ca9..ff00b4aeaf1c 100644
> --- a/include/linux/gpio/regmap.h
> +++ b/include/linux/gpio/regmap.h
> @@ -38,6 +38,12 @@ struct regmap;
>    *			offset to a register/bitmask pair. If not
>    *			given the default gpio_regmap_simple_xlate()
>    *			is used.
> + * @fixed_direction_sparse:
> + *			(Optional) Bitmap representing the GPIO lines that
> + *			make use of the @fixed_direction_output list to
> + *			enforce direction of the GPIO. If this is NULL
> + *			and @fixed_direction_output is defined, ALL GPIOs
> + *			are assumed to be fixed direction (out or in).
>    * @fixed_direction_output:
>    *			(Optional) Bitmap representing the fixed direction of
>    *			the GPIO lines. Useful when there are GPIO lines with a
> @@ -89,6 +95,7 @@ struct gpio_regmap_config {
>   	int reg_stride;
>   	int ngpio_per_reg;
>   	struct irq_domain *irq_domain;
> +	unsigned long *fixed_direction_sparse;
>   	unsigned long *fixed_direction_output;
>   
>   #ifdef CONFIG_REGMAP_IRQ
> 
> ---
> base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
> change-id: 20260507-regmap-gpio-sparse-fixed-dir-1d5c0d2e2c6f
> 
> Best regards,
> --
> Linus Walleij <linusw@kernel.org>
> 


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-05-07 22:13 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-07 12:10 [PATCH] gpio: regmap: Support sparsed fixed direction Linus Walleij
2026-05-07 22:13 ` Alex Elder

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox