@@ -415,6 +415,11 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
return 0;
}
+bool of_gpiochip_has_pin_range(struct gpio_chip *chip)
+{
+ return !!of_find_property(chip->of_node, "gpio-ranges", NULL);
+}
+
#else
static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { return 0; }
#endif
@@ -236,14 +236,23 @@ static int gpiochip_add_to_list(struct gpio_chip *chip)
* If chip->base is negative, this requests dynamic assignment of
* a range of valid GPIOs.
*/
-int gpiochip_add(struct gpio_chip *chip)
+int gpiochip_add_with_ranges(struct gpio_chip *chip, const char *pinctl_name,
+ const struct pinctrl_gpio_range *ranges,
+ unsigned int nranges)
{
unsigned long flags;
int status = 0;
- unsigned id;
+ unsigned id, i;
int base = chip->base;
struct gpio_desc *descs;
+ if ((nranges > 0) || of_gpiochip_has_pin_range(chip)) {
+ if (!chip->request)
+ chip->request = gpiochip_generic_request;
+ if (!chip->free)
+ chip->free = gpiochip_generic_free;
+ }
+
descs = kcalloc(chip->ngpio, sizeof(descs[0]), GFP_KERNEL);
if (!descs)
return -ENOMEM;
@@ -295,6 +304,16 @@ int gpiochip_add(struct gpio_chip *chip)
if (status)
goto err_remove_chip;
+ for (i = 0; i < nranges; i++) {
+ const struct pinctrl_gpio_range *range = ranges[i];
+
+ status = gpiochip_add_pin_range(chip, pinctl_name,
+ chip->base + range->base,
+ range->pinbase, range->npins);
+ if (status)
+ goto err_remove_chip;
+ }
+
acpi_gpiochip_add(chip);
status = gpiochip_sysfs_register(chip);
@@ -309,6 +328,7 @@ int gpiochip_add(struct gpio_chip *chip)
err_remove_chip:
acpi_gpiochip_remove(chip);
+ gpiochip_remove_pin_ranges(chip);
gpiochip_free_hogs(chip);
of_gpiochip_remove(chip);
spin_lock_irqsave(&gpio_lock, flags);
@@ -72,6 +72,15 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum);
+#if defined(CONFIG_OF_GPIO) && defined(CONFIG_PINCTRL)
+bool of_gpiochip_has_pin_range(struct gpio_chip *chip);
+#else
+static inline bool of_gpiochip_has_pin_range(struct gpio_chip *chip)
+{
+ return false;
+}
+#endif
+
extern struct spinlock gpio_lock;
extern struct list_head gpio_chips;
@@ -166,7 +166,14 @@ extern const char *gpiochip_is_requested(struct gpio_chip *chip,
unsigned offset);
/* add/remove chips */
-extern int gpiochip_add(struct gpio_chip *chip);
+static inline int gpiochip_add(struct gpio_chip *chip)
+{
+ return gpiochip_add_with_ranges(chip, NULL, NULL, 0);
+}
+
+int gpiochip_add_with_ranges(struct gpio_chip *chip, const char *pinctl_name,
+ const struct pinctrl_gpio_range *ranges,
+ unsigned int nranges);
extern void gpiochip_remove(struct gpio_chip *chip);
extern struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *chip, void *data));