* [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA
@ 2025-06-11 9:00 Thomas Richard
2025-06-11 9:00 ` [PATCH v8 01/10] gpiolib: add support to register sparse pin range Thomas Richard
` (11 more replies)
0 siblings, 12 replies; 18+ messages in thread
From: Thomas Richard @ 2025-06-11 9:00 UTC (permalink / raw)
To: Linus Walleij, Andy Shevchenko, Bartosz Golaszewski,
Geert Uytterhoeven, Kees Cook, Andy Shevchenko
Cc: linux-gpio, linux-kernel, thomas.petazzoni, DanieleCleri,
GaryWang, linux-hardening, Thomas Richard
This is the eighth version of this series. I just added a missing header
file in gpio-aggregator driver to fix a build warning reported by a kernel
test robot [1].
[1] https://lore.kernel.org/oe-kbuild-all/202506092324.XqSwWl1z-lkp@intel.com/
Best Regards,
Thomas
Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
---
Changes in v8:
- gpio: aggregator: add missing export.h header file.
- Link to v7: https://lore.kernel.org/r/20250609-aaeon-up-board-pinctrl-support-v7-0-1ab73ec0cb98@bootlin.com
Changes in v7:
- all: rebase on v6.16-rc1.
- pinctrl: take Reviewed-by tag
- pinctrl: handle negative error code returned by
upboard_pinctrl_pin_get_mode() in upboard_pinctrl_dbg_show().
- Link to v6: https://lore.kernel.org/r/20250520-aaeon-up-board-pinctrl-support-v6-0-dcb3756be3c6@bootlin.com
Changes in v6:
- all: take Reviewed-by tags.
- all: fix some nitpicks.
- gpiolib: fix error reported by kernel test robot.
- gpio: aggregator: handle correctly err_ptr returned by
devm_gpiochip_fwd_alloc().
- gpio: aggregator: rework naming of GPIO fowarder API.
- gpio: aggregator: all functions of GPIO fowarder API now take a gpiochip_fwd ptr as
parameter.
- gpio: aggregator: fix some typos in kernel-doc and comments.
- gpio: aggregator: in forwarder.h, remove unused linux/gpio/consumer.h and
linux/gpio/driver.h header files.
- gpio: aggregator: add missing forward declaration in forwarder.h (struct
gpio_desc and struct gpio_chip).
- gpio: aggregator: get_direction() operation now returns -ENODEV if there is no
GPIO descriptor for the line.
- gpio: aggregator: handle correctly ptr returned by devm_gpiochip_fwd_alloc().
- gpio: aggregator: free GPIO desc array after gpiochip_fwd_create().
- pinctrl-upboard: remove useless cast in UPBOARD_UP_PIN_MUX() UPBOARD_UP_PIN_FUNC() macros.
- pinctrl-upboard: rework the pinctrl mapping part (new struct upboard_pinctrl_map).
- Link to v5: https://lore.kernel.org/r/20250506-aaeon-up-board-pinctrl-support-v5-0-3906529757d2@bootlin.com
Changes in v5:
- all: improve commit messages, fix some typos and nitpicks.
- pinctrl: machine.h: add "Suggested-by: Andy Shevchenko <andy@kernel.org>"
and "Reviewed-by: Andy Shevchenko <andy@kernel.org>" tags.
- pinctrl: core: fix kernel doc for devm_pinctrl_register_mappings().
- pinctrl: core: do not cast pointer in devm_pinctrl_unregister_mappings().
- gpio: aggregator: remove a useless check in patch 5/12.
- gpio: aggregator: fix condition to identify if the gpiochip forwarder can
sleep or not.
- gpio: aggregator: add "Reviewed-by: Andy Shevchenko <andy@kernel.org>" tag
in patch 10/12
- string_choices: add "Suggested-by: Andy Shevchenko <andy@kernel.org>" and
"Reviewed-by: Andy Shevchenko <andy@kernel.org>" tags.
- string_choices: add missing parameter for str_output_input() macro.
- Link to v4: https://lore.kernel.org/r/20250429-aaeon-up-board-pinctrl-support-v4-0-b3fffc11417d@bootlin.com
Changes in v4:
- gpiolib: use positive conditonal in gpiochip_add_pin_range_with_pins().
- pinctrl: fix warning reported by kernel robot in
include/linux/pinctrl/machine.h.
- pinctrl: add a patch to remove the extern specifier in machine.h.
- pinctrl: use devm_add_action_or_reset() in
devm_pinctrl_register_mappings().
- string_choices: add a patch to define str_input_output() and
str_output_input() helpers.
- gpio: aggregator: set gpiochip_fwd as opaque and define getters
gpio_fwd_get_gpiochip() and gpio_fwd_get_data().
- gpio: aggregator: add valid_mask in gpiochip_fwd struct to track already
registered gpio descs.
- gpio: aggregator: add gpio_fwd_gpio_free() helper.
- gpio: aggregator: add kdoc sections for exported functions.
- gpio: aggregator: fix some nitpicks.
- pinctrl-upboard: use str_input_output() helper.
- pinctrl-upboard: fix some nitpicks.
- pinctrl-upboard: add missing headers stddef.h and types.h.
- pinctrl-upboard: add intermediate cast (unsigned long) for dmi_id->driver_data.
- pinctrl-upboard: use getter gpio_fwd_get_gpiochip() and
gpio_fwd_get_data().
- pinctrl-upboard: fix kernel robot warning 'unmet direct dependencies detected
for GPIO_AGGREGATOR when selected by PINCTRL_UPBOARD'.
- pinctrl-upboard: use gpio_fwd_gpio_free() helper.
- Link to v3: https://lore.kernel.org/r/20250416-aaeon-up-board-pinctrl-support-v3-0-f40776bd06ee@bootlin.com
Changes in v3:
- pinctrl: add devm_pinctrl_register_mappings()
- gpiolib: rename gpiochip_add_pin_range() to
gpiochip_add_pin_range_with_pins() and add pins parameter
- gpiolib: add stubs gpiochip_add_pin_range() and
gpiochip_add_sparse_pin_range()
- aggregator: split to more simpler patches
- aggregator: add a namespace for the forwarder library
- aggregator: rename header file to forwarder.h
- aggregator: add some missing headers and declaration in forwarder.h
- aggregator: forwarder.h provides consumer.h and driver.h
- aggregator: fix error code returned by gpio_fwd_request()
- pinctrl-upboard: fix order of header files
- pinctrl-upboard: fix some nitpicks
- pinctrl-upboard: rework macros to define pin groups
- pinctrl-upboard: add missing container_of.h and err.h header files
- pinctrl-upboard: handle correctly pointer returned by dmi_first_match()
- pinctrl-upboard: use devm_pinctrl_register_mappings()
- pinctrl-upboard: import GPIO_FORWARDER namespace
- Link to v2: https://lore.kernel.org/r/20250317-aaeon-up-board-pinctrl-support-v2-0-36126e30aa62@bootlin.com
Changes in v2:
- mfd: removed driver (already merged)
- led: removed driver (already merged)
- gpio-aggregator: refactor code to create a gpio-fwd library
- pinctrl: refactor gpio part to use the gpio-fwd library
- pinctrl: add pinctrl mappings for each board
---
Thomas Richard (10):
gpiolib: add support to register sparse pin range
gpio: aggregator: move GPIO forwarder allocation in a dedicated function
gpio: aggregator: refactor the code to add GPIO desc in the forwarder
gpio: aggregator: refactor the forwarder registration part
gpio: aggregator: update gpiochip_fwd_setup_delay_line() parameters
gpio: aggregator: export symbols of the GPIO forwarder library
gpio: aggregator: handle runtime registration of gpio_desc in gpiochip_fwd
gpio: aggregator: add possibility to attach data to the forwarder
lib/string_choices: Add str_input_output() helper
pinctrl: Add pin controller driver for AAEON UP boards
drivers/gpio/gpio-aggregator.c | 388 ++++++++++++--
drivers/gpio/gpiolib.c | 29 +-
drivers/pinctrl/Kconfig | 19 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/pinctrl-upboard.c | 1070 +++++++++++++++++++++++++++++++++++++
include/linux/gpio/driver.h | 51 +-
include/linux/gpio/forwarder.h | 41 ++
include/linux/string_choices.h | 6 +
8 files changed, 1547 insertions(+), 58 deletions(-)
---
base-commit: d9946fe286439c2aeaa7953b8c316efe5b83d515
change-id: 20240930-aaeon-up-board-pinctrl-support-98fa4a030490
Best regards,
--
Thomas Richard <thomas.richard@bootlin.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v8 01/10] gpiolib: add support to register sparse pin range
2025-06-11 9:00 [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Thomas Richard
@ 2025-06-11 9:00 ` Thomas Richard
2025-06-11 9:00 ` [PATCH v8 02/10] gpio: aggregator: move GPIO forwarder allocation in a dedicated function Thomas Richard
` (10 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Thomas Richard @ 2025-06-11 9:00 UTC (permalink / raw)
To: Linus Walleij, Andy Shevchenko, Bartosz Golaszewski,
Geert Uytterhoeven, Kees Cook, Andy Shevchenko
Cc: linux-gpio, linux-kernel, thomas.petazzoni, DanieleCleri,
GaryWang, linux-hardening, Thomas Richard
Add support to register for GPIO<->pin mapping using a list of non
consecutive pins. The core already supports sparse pin range (pins member
of struct pinctrl_gpio_range), but it was not possible to register one. If
pins is not NULL the core uses it, otherwise it assumes that a consecutive
pin range was registered and it uses pin_base.
The function gpiochip_add_pin_range() which allocates and fills the struct
pinctrl_gpio_range was renamed to gpiochip_add_pin_range_with_pins() and
the pins parameter was added.
Two new functions were added, gpiochip_add_pin_range() and
gpiochip_add_sparse_pin_range() to register a consecutive or sparse pins
range. Both use gpiochip_add_pin_range_with_pins().
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
---
drivers/gpio/gpiolib.c | 29 ++++++++++++++++++--------
include/linux/gpio/driver.h | 51 ++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 68 insertions(+), 12 deletions(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index fdafa0df1b43..e196463e7c04 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2340,11 +2340,13 @@ int gpiochip_add_pingroup_range(struct gpio_chip *gc,
EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range);
/**
- * gpiochip_add_pin_range() - add a range for GPIO <-> pin mapping
+ * gpiochip_add_pin_range_with_pins() - add a range for GPIO <-> pin mapping
* @gc: the gpiochip to add the range for
* @pinctl_name: the dev_name() of the pin controller to map to
* @gpio_offset: the start offset in the current gpio_chip number space
* @pin_offset: the start offset in the pin controller number space
+ * @pins: the list of non consecutive pins to accumulate in this range (if not
+ * NULL, pin_offset is ignored by pinctrl core)
* @npins: the number of pins from the offset of each pin space (GPIO and
* pin controller) to accumulate in this range
*
@@ -2356,9 +2358,12 @@ EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range);
* Returns:
* 0 on success, or a negative errno on failure.
*/
-int gpiochip_add_pin_range(struct gpio_chip *gc, const char *pinctl_name,
- unsigned int gpio_offset, unsigned int pin_offset,
- unsigned int npins)
+int gpiochip_add_pin_range_with_pins(struct gpio_chip *gc,
+ const char *pinctl_name,
+ unsigned int gpio_offset,
+ unsigned int pin_offset,
+ unsigned int const *pins,
+ unsigned int npins)
{
struct gpio_pin_range *pin_range;
struct gpio_device *gdev = gc->gpiodev;
@@ -2376,6 +2381,7 @@ int gpiochip_add_pin_range(struct gpio_chip *gc, const char *pinctl_name,
pin_range->range.name = gc->label;
pin_range->range.base = gdev->base + gpio_offset;
pin_range->range.pin_base = pin_offset;
+ pin_range->range.pins = pins;
pin_range->range.npins = npins;
pin_range->pctldev = pinctrl_find_and_add_gpio_range(pinctl_name,
&pin_range->range);
@@ -2385,16 +2391,21 @@ int gpiochip_add_pin_range(struct gpio_chip *gc, const char *pinctl_name,
kfree(pin_range);
return ret;
}
- chip_dbg(gc, "created GPIO range %d->%d ==> %s PIN %d->%d\n",
- gpio_offset, gpio_offset + npins - 1,
- pinctl_name,
- pin_offset, pin_offset + npins - 1);
+ if (pin_range->range.pins)
+ chip_dbg(gc, "created GPIO range %d->%d ==> %s %d sparse PIN range { %d, ... }",
+ gpio_offset, gpio_offset + npins - 1,
+ pinctl_name, npins, pins[0]);
+ else
+ chip_dbg(gc, "created GPIO range %d->%d ==> %s PIN %d->%d\n",
+ gpio_offset, gpio_offset + npins - 1,
+ pinctl_name,
+ pin_offset, pin_offset + npins - 1);
list_add_tail(&pin_range->node, &gdev->pin_ranges);
return 0;
}
-EXPORT_SYMBOL_GPL(gpiochip_add_pin_range);
+EXPORT_SYMBOL_GPL(gpiochip_add_pin_range_with_pins);
/**
* gpiochip_remove_pin_ranges() - remove all the GPIO <-> pin mappings
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index b53233051bee..58492c57063f 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -785,16 +785,50 @@ struct gpio_pin_range {
#ifdef CONFIG_PINCTRL
-int gpiochip_add_pin_range(struct gpio_chip *gc, const char *pinctl_name,
- unsigned int gpio_offset, unsigned int pin_offset,
- unsigned int npins);
+int gpiochip_add_pin_range_with_pins(struct gpio_chip *gc,
+ const char *pinctl_name,
+ unsigned int gpio_offset,
+ unsigned int pin_offset,
+ unsigned int const *pins,
+ unsigned int npins);
int gpiochip_add_pingroup_range(struct gpio_chip *gc,
struct pinctrl_dev *pctldev,
unsigned int gpio_offset, const char *pin_group);
void gpiochip_remove_pin_ranges(struct gpio_chip *gc);
+static inline int
+gpiochip_add_pin_range(struct gpio_chip *gc,
+ const char *pinctl_name,
+ unsigned int gpio_offset,
+ unsigned int pin_offset,
+ unsigned int npins)
+{
+ return gpiochip_add_pin_range_with_pins(gc, pinctl_name, gpio_offset,
+ pin_offset, NULL, npins);
+}
+
+static inline int
+gpiochip_add_sparse_pin_range(struct gpio_chip *gc,
+ const char *pinctl_name,
+ unsigned int gpio_offset,
+ unsigned int const *pins,
+ unsigned int npins)
+{
+ return gpiochip_add_pin_range_with_pins(gc, pinctl_name, gpio_offset, 0,
+ pins, npins);
+}
#else /* ! CONFIG_PINCTRL */
+static inline int
+gpiochip_add_pin_range_with_pins(struct gpio_chip *gc,
+ const char *pinctl_name,
+ unsigned int gpio_offset,
+ unsigned int pin_offset,
+ unsigned int npins)
+{
+ return 0;
+}
+
static inline int
gpiochip_add_pin_range(struct gpio_chip *gc, const char *pinctl_name,
unsigned int gpio_offset, unsigned int pin_offset,
@@ -802,6 +836,17 @@ gpiochip_add_pin_range(struct gpio_chip *gc, const char *pinctl_name,
{
return 0;
}
+
+static inline int
+gpiochip_add_sparse_pin_range(struct gpio_chip *gc,
+ const char *pinctl_name,
+ unsigned int gpio_offset,
+ unsigned int const *pins,
+ unsigned int npins)
+{
+ return 0;
+}
+
static inline int
gpiochip_add_pingroup_range(struct gpio_chip *gc,
struct pinctrl_dev *pctldev,
--
2.39.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 02/10] gpio: aggregator: move GPIO forwarder allocation in a dedicated function
2025-06-11 9:00 [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Thomas Richard
2025-06-11 9:00 ` [PATCH v8 01/10] gpiolib: add support to register sparse pin range Thomas Richard
@ 2025-06-11 9:00 ` Thomas Richard
2025-06-11 9:00 ` [PATCH v8 03/10] gpio: aggregator: refactor the code to add GPIO desc in the forwarder Thomas Richard
` (9 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Thomas Richard @ 2025-06-11 9:00 UTC (permalink / raw)
To: Linus Walleij, Andy Shevchenko, Bartosz Golaszewski,
Geert Uytterhoeven, Kees Cook, Andy Shevchenko
Cc: linux-gpio, linux-kernel, thomas.petazzoni, DanieleCleri,
GaryWang, linux-hardening, Thomas Richard
Move the GPIO forwarder allocation and static initialization in a dedicated
function.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
---
drivers/gpio/gpio-aggregator.c | 50 +++++++++++++++++++++++++++---------------
1 file changed, 32 insertions(+), 18 deletions(-)
diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c
index 6f941db02c04..f79bb4e12b20 100644
--- a/drivers/gpio/gpio-aggregator.c
+++ b/drivers/gpio/gpio-aggregator.c
@@ -475,6 +475,35 @@ static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *c
}
#endif /* !CONFIG_OF_GPIO */
+static struct gpiochip_fwd *
+devm_gpiochip_fwd_alloc(struct device *dev, unsigned int ngpios)
+{
+ struct gpiochip_fwd *fwd;
+ struct gpio_chip *chip;
+
+ fwd = devm_kzalloc(dev, struct_size(fwd, tmp, fwd_tmp_size(ngpios)), GFP_KERNEL);
+ if (!fwd)
+ return ERR_PTR(-ENOMEM);
+
+ chip = &fwd->chip;
+
+ chip->label = dev_name(dev);
+ chip->parent = dev;
+ chip->owner = THIS_MODULE;
+ chip->get_direction = gpio_fwd_get_direction;
+ chip->direction_input = gpio_fwd_direction_input;
+ chip->direction_output = gpio_fwd_direction_output;
+ chip->get = gpio_fwd_get;
+ chip->get_multiple = gpio_fwd_get_multiple_locked;
+ chip->set_rv = gpio_fwd_set;
+ chip->set_multiple_rv = gpio_fwd_set_multiple_locked;
+ chip->to_irq = gpio_fwd_to_irq;
+ chip->base = -1;
+ chip->ngpio = ngpios;
+
+ return fwd;
+}
+
/**
* gpiochip_fwd_create() - Create a new GPIO forwarder
* @dev: Parent device pointer
@@ -495,16 +524,14 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev,
struct gpio_desc *descs[],
unsigned long features)
{
- const char *label = dev_name(dev);
struct gpiochip_fwd *fwd;
struct gpio_chip *chip;
unsigned int i;
int error;
- fwd = devm_kzalloc(dev, struct_size(fwd, tmp, fwd_tmp_size(ngpios)),
- GFP_KERNEL);
- if (!fwd)
- return ERR_PTR(-ENOMEM);
+ fwd = devm_gpiochip_fwd_alloc(dev, ngpios);
+ if (IS_ERR(fwd))
+ return fwd;
chip = &fwd->chip;
@@ -526,19 +553,6 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev,
chip->set_config = gpio_fwd_set_config;
}
- chip->label = label;
- chip->parent = dev;
- chip->owner = THIS_MODULE;
- chip->get_direction = gpio_fwd_get_direction;
- chip->direction_input = gpio_fwd_direction_input;
- chip->direction_output = gpio_fwd_direction_output;
- chip->get = gpio_fwd_get;
- chip->get_multiple = gpio_fwd_get_multiple_locked;
- chip->set_rv = gpio_fwd_set;
- chip->set_multiple_rv = gpio_fwd_set_multiple_locked;
- chip->to_irq = gpio_fwd_to_irq;
- chip->base = -1;
- chip->ngpio = ngpios;
fwd->descs = descs;
if (chip->can_sleep)
--
2.39.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 03/10] gpio: aggregator: refactor the code to add GPIO desc in the forwarder
2025-06-11 9:00 [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Thomas Richard
2025-06-11 9:00 ` [PATCH v8 01/10] gpiolib: add support to register sparse pin range Thomas Richard
2025-06-11 9:00 ` [PATCH v8 02/10] gpio: aggregator: move GPIO forwarder allocation in a dedicated function Thomas Richard
@ 2025-06-11 9:00 ` Thomas Richard
2025-06-11 9:00 ` [PATCH v8 04/10] gpio: aggregator: refactor the forwarder registration part Thomas Richard
` (8 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Thomas Richard @ 2025-06-11 9:00 UTC (permalink / raw)
To: Linus Walleij, Andy Shevchenko, Bartosz Golaszewski,
Geert Uytterhoeven, Kees Cook, Andy Shevchenko
Cc: linux-gpio, linux-kernel, thomas.petazzoni, DanieleCleri,
GaryWang, linux-hardening, Thomas Richard
Create a dedicated function to add a GPIO desc in the forwarder. Instead of
saving a GPIO descs array pointer, now the GPIO descs are passed one by one
to the forwarder which registers them in its own array. So after the call
of gpiochip_fwd_create(), the passed array can be free.
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
---
drivers/gpio/gpio-aggregator.c | 59 ++++++++++++++++++++++++++++--------------
1 file changed, 40 insertions(+), 19 deletions(-)
diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c
index f79bb4e12b20..6285c3e8f6b8 100644
--- a/drivers/gpio/gpio-aggregator.c
+++ b/drivers/gpio/gpio-aggregator.c
@@ -485,6 +485,10 @@ devm_gpiochip_fwd_alloc(struct device *dev, unsigned int ngpios)
if (!fwd)
return ERR_PTR(-ENOMEM);
+ fwd->descs = devm_kcalloc(dev, ngpios, sizeof(*fwd->descs), GFP_KERNEL);
+ if (!fwd->descs)
+ return ERR_PTR(-ENOMEM);
+
chip = &fwd->chip;
chip->label = dev_name(dev);
@@ -504,13 +508,43 @@ devm_gpiochip_fwd_alloc(struct device *dev, unsigned int ngpios)
return fwd;
}
+static int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd,
+ struct gpio_desc *desc,
+ unsigned int offset)
+{
+ struct gpio_chip *parent = gpiod_to_chip(desc);
+ struct gpio_chip *chip = &fwd->chip;
+
+ if (offset > chip->ngpio)
+ return -EINVAL;
+
+ /*
+ * If any of the GPIO lines are sleeping, then the entire forwarder
+ * will be sleeping.
+ * If any of the chips support .set_config(), then the forwarder will
+ * support setting configs.
+ */
+ if (gpiod_cansleep(desc))
+ chip->can_sleep = true;
+
+ if (parent && parent->set_config)
+ chip->set_config = gpio_fwd_set_config;
+
+ fwd->descs[offset] = desc;
+
+ dev_dbg(chip->parent, "%u => gpio %d irq %d\n", offset,
+ desc_to_gpio(desc), gpiod_to_irq(desc));
+
+ return 0;
+}
+
/**
* gpiochip_fwd_create() - Create a new GPIO forwarder
* @dev: Parent device pointer
* @ngpios: Number of GPIOs in the forwarder.
* @descs: Array containing the GPIO descriptors to forward to.
- * This array must contain @ngpios entries, and must not be deallocated
- * before the forwarder has been destroyed again.
+ * This array must contain @ngpios entries, and can be deallocated
+ * as the forwarder has its own array.
* @features: Bitwise ORed features as defined with FWD_FEATURE_*.
*
* This function creates a new gpiochip, which forwards all GPIO operations to
@@ -535,26 +569,12 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev,
chip = &fwd->chip;
- /*
- * If any of the GPIO lines are sleeping, then the entire forwarder
- * will be sleeping.
- * If any of the chips support .set_config(), then the forwarder will
- * support setting configs.
- */
for (i = 0; i < ngpios; i++) {
- struct gpio_chip *parent = gpiod_to_chip(descs[i]);
-
- dev_dbg(dev, "%u => gpio %d irq %d\n", i,
- desc_to_gpio(descs[i]), gpiod_to_irq(descs[i]));
-
- if (gpiod_cansleep(descs[i]))
- chip->can_sleep = true;
- if (parent && parent->set_config)
- chip->set_config = gpio_fwd_set_config;
+ error = gpiochip_fwd_desc_add(fwd, descs[i], i);
+ if (error)
+ return ERR_PTR(error);
}
- fwd->descs = descs;
-
if (chip->can_sleep)
mutex_init(&fwd->mlock);
else
@@ -1348,6 +1368,7 @@ static int gpio_aggregator_probe(struct platform_device *pdev)
return PTR_ERR(fwd);
platform_set_drvdata(pdev, fwd);
+ devm_kfree(dev, descs);
return 0;
}
--
2.39.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 04/10] gpio: aggregator: refactor the forwarder registration part
2025-06-11 9:00 [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Thomas Richard
` (2 preceding siblings ...)
2025-06-11 9:00 ` [PATCH v8 03/10] gpio: aggregator: refactor the code to add GPIO desc in the forwarder Thomas Richard
@ 2025-06-11 9:00 ` Thomas Richard
2025-06-11 9:00 ` [PATCH v8 05/10] gpio: aggregator: update gpiochip_fwd_setup_delay_line() parameters Thomas Richard
` (7 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Thomas Richard @ 2025-06-11 9:00 UTC (permalink / raw)
To: Linus Walleij, Andy Shevchenko, Bartosz Golaszewski,
Geert Uytterhoeven, Kees Cook, Andy Shevchenko
Cc: linux-gpio, linux-kernel, thomas.petazzoni, DanieleCleri,
GaryWang, linux-hardening, Thomas Richard
Add a new function gpiochip_fwd_register(), which finalizes the
initialization of the forwarder and registers the corresponding gpiochip.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
---
drivers/gpio/gpio-aggregator.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c
index 6285c3e8f6b8..028ac79758d2 100644
--- a/drivers/gpio/gpio-aggregator.c
+++ b/drivers/gpio/gpio-aggregator.c
@@ -538,6 +538,18 @@ static int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd,
return 0;
}
+static int gpiochip_fwd_register(struct gpiochip_fwd *fwd)
+{
+ struct gpio_chip *chip = &fwd->chip;
+
+ if (chip->can_sleep)
+ mutex_init(&fwd->mlock);
+ else
+ spin_lock_init(&fwd->slock);
+
+ return devm_gpiochip_add_data(chip->parent, chip, fwd);
+}
+
/**
* gpiochip_fwd_create() - Create a new GPIO forwarder
* @dev: Parent device pointer
@@ -575,18 +587,13 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev,
return ERR_PTR(error);
}
- if (chip->can_sleep)
- mutex_init(&fwd->mlock);
- else
- spin_lock_init(&fwd->slock);
-
if (features & FWD_FEATURE_DELAY) {
error = gpiochip_fwd_setup_delay_line(dev, chip, fwd);
if (error)
return ERR_PTR(error);
}
- error = devm_gpiochip_add_data(dev, chip, fwd);
+ error = gpiochip_fwd_register(fwd);
if (error)
return ERR_PTR(error);
--
2.39.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 05/10] gpio: aggregator: update gpiochip_fwd_setup_delay_line() parameters
2025-06-11 9:00 [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Thomas Richard
` (3 preceding siblings ...)
2025-06-11 9:00 ` [PATCH v8 04/10] gpio: aggregator: refactor the forwarder registration part Thomas Richard
@ 2025-06-11 9:00 ` Thomas Richard
2025-06-11 9:00 ` [PATCH v8 06/10] gpio: aggregator: export symbols of the GPIO forwarder library Thomas Richard
` (6 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Thomas Richard @ 2025-06-11 9:00 UTC (permalink / raw)
To: Linus Walleij, Andy Shevchenko, Bartosz Golaszewski,
Geert Uytterhoeven, Kees Cook, Andy Shevchenko
Cc: linux-gpio, linux-kernel, thomas.petazzoni, DanieleCleri,
GaryWang, linux-hardening, Thomas Richard
Remove useless parameters of gpiochip_fwd_setup_delay_line().
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
---
drivers/gpio/gpio-aggregator.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c
index 028ac79758d2..f1f48ceed75f 100644
--- a/drivers/gpio/gpio-aggregator.c
+++ b/drivers/gpio/gpio-aggregator.c
@@ -453,10 +453,11 @@ static int gpiochip_fwd_delay_of_xlate(struct gpio_chip *chip,
return line;
}
-static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *chip,
- struct gpiochip_fwd *fwd)
+static int gpiochip_fwd_setup_delay_line(struct gpiochip_fwd *fwd)
{
- fwd->delay_timings = devm_kcalloc(dev, chip->ngpio,
+ struct gpio_chip *chip = &fwd->chip;
+
+ fwd->delay_timings = devm_kcalloc(chip->parent, chip->ngpio,
sizeof(*fwd->delay_timings),
GFP_KERNEL);
if (!fwd->delay_timings)
@@ -468,8 +469,7 @@ static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *c
return 0;
}
#else
-static int gpiochip_fwd_setup_delay_line(struct device *dev, struct gpio_chip *chip,
- struct gpiochip_fwd *fwd)
+static int gpiochip_fwd_setup_delay_line(struct gpiochip_fwd *fwd)
{
return 0;
}
@@ -571,7 +571,6 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev,
unsigned long features)
{
struct gpiochip_fwd *fwd;
- struct gpio_chip *chip;
unsigned int i;
int error;
@@ -579,8 +578,6 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev,
if (IS_ERR(fwd))
return fwd;
- chip = &fwd->chip;
-
for (i = 0; i < ngpios; i++) {
error = gpiochip_fwd_desc_add(fwd, descs[i], i);
if (error)
@@ -588,7 +585,7 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev,
}
if (features & FWD_FEATURE_DELAY) {
- error = gpiochip_fwd_setup_delay_line(dev, chip, fwd);
+ error = gpiochip_fwd_setup_delay_line(fwd);
if (error)
return ERR_PTR(error);
}
--
2.39.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 06/10] gpio: aggregator: export symbols of the GPIO forwarder library
2025-06-11 9:00 [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Thomas Richard
` (4 preceding siblings ...)
2025-06-11 9:00 ` [PATCH v8 05/10] gpio: aggregator: update gpiochip_fwd_setup_delay_line() parameters Thomas Richard
@ 2025-06-11 9:00 ` Thomas Richard
2025-06-11 9:00 ` [PATCH v8 07/10] gpio: aggregator: handle runtime registration of gpio_desc in gpiochip_fwd Thomas Richard
` (5 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Thomas Richard @ 2025-06-11 9:00 UTC (permalink / raw)
To: Linus Walleij, Andy Shevchenko, Bartosz Golaszewski,
Geert Uytterhoeven, Kees Cook, Andy Shevchenko
Cc: linux-gpio, linux-kernel, thomas.petazzoni, DanieleCleri,
GaryWang, linux-hardening, Thomas Richard
Export all symbols and create header file for the GPIO forwarder library.
It will be used in the next changes.
Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
---
drivers/gpio/gpio-aggregator.c | 202 +++++++++++++++++++++++++++++++++++++++--
include/linux/gpio/forwarder.h | 37 ++++++++
2 files changed, 233 insertions(+), 6 deletions(-)
diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c
index f1f48ceed75f..6da14a5064c6 100644
--- a/drivers/gpio/gpio-aggregator.c
+++ b/drivers/gpio/gpio-aggregator.c
@@ -12,6 +12,7 @@
#include <linux/configfs.h>
#include <linux/ctype.h>
#include <linux/delay.h>
+#include <linux/export.h>
#include <linux/idr.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -28,6 +29,7 @@
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
+#include <linux/gpio/forwarder.h>
#include <linux/gpio/machine.h>
#include "dev-sync-probe.h"
@@ -475,8 +477,180 @@ static int gpiochip_fwd_setup_delay_line(struct gpiochip_fwd *fwd)
}
#endif /* !CONFIG_OF_GPIO */
-static struct gpiochip_fwd *
-devm_gpiochip_fwd_alloc(struct device *dev, unsigned int ngpios)
+/**
+ * gpiochip_fwd_get_gpiochip - Get the GPIO chip for the GPIO forwarder
+ * @fwd: GPIO forwarder
+ *
+ * Returns: The GPIO chip for the GPIO forwarder
+ */
+struct gpio_chip *gpiochip_fwd_get_gpiochip(struct gpiochip_fwd *fwd)
+{
+ return &fwd->chip;
+}
+EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_get_gpiochip, "GPIO_FORWARDER");
+
+/**
+ * gpiochip_fwd_gpio_get_direction - Return the current direction of a GPIO forwarder line
+ * @fwd: GPIO forwarder
+ * @offset: the offset of the line
+ *
+ * Returns: 0 for output, 1 for input, or an error code in case of error.
+ */
+int gpiochip_fwd_gpio_get_direction(struct gpiochip_fwd *fwd, unsigned int offset)
+{
+ struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
+
+ return gpio_fwd_get_direction(gc, offset);
+}
+EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_get_direction, "GPIO_FORWARDER");
+
+/**
+ * gpiochip_fwd_gpio_direction_output - Set a GPIO forwarder line direction to
+ * output
+ * @fwd: GPIO forwarder
+ * @offset: the offset of the line
+ * @value: value to set
+ *
+ * Returns: 0 on success, or negative errno on failure.
+ */
+int gpiochip_fwd_gpio_direction_output(struct gpiochip_fwd *fwd, unsigned int offset,
+ int value)
+{
+ struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
+
+ return gpio_fwd_direction_output(gc, offset, value);
+}
+EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_direction_output, "GPIO_FORWARDER");
+
+/**
+ * gpiochip_fwd_gpio_direction_input - Set a GPIO forwarder line direction to input
+ * @fwd: GPIO forwarder
+ * @offset: the offset of the line
+ *
+ * Returns: 0 on success, or negative errno on failure.
+ */
+int gpiochip_fwd_gpio_direction_input(struct gpiochip_fwd *fwd, unsigned int offset)
+{
+ struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
+
+ return gpio_fwd_direction_input(gc, offset);
+}
+EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_direction_input, "GPIO_FORWARDER");
+
+/**
+ * gpiochip_fwd_gpio_get - Return a GPIO forwarder line's value
+ * @fwd: GPIO forwarder
+ * @offset: the offset of the line
+ *
+ * Returns: The GPIO's logical value, i.e. taking the ACTIVE_LOW status into
+ * account, or negative errno on failure.
+ */
+int gpiochip_fwd_gpio_get(struct gpiochip_fwd *fwd, unsigned int offset)
+{
+ struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
+
+ return gpio_fwd_get(gc, offset);
+}
+EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_get, "GPIO_FORWARDER");
+
+/**
+ * gpiochip_fwd_gpio_get_multiple - Get values for multiple GPIO forwarder lines
+ * @fwd: GPIO forwarder
+ * @mask: bit mask array; one bit per line; BITS_PER_LONG bits per word defines
+ * which lines are to be read
+ * @bits: bit value array; one bit per line; BITS_PER_LONG bits per word will
+ * contains the read values for the lines specified by mask
+ *
+ * Returns: 0 on success, or negative errno on failure.
+ */
+int gpiochip_fwd_gpio_get_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
+ unsigned long *bits)
+{
+ struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
+
+ return gpio_fwd_get_multiple_locked(gc, mask, bits);
+}
+EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_get_multiple, "GPIO_FORWARDER");
+
+/**
+ * gpiochip_fwd_gpio_set - Assign value to a GPIO forwarder line.
+ * @fwd: GPIO forwarder
+ * @offset: the offset of the line
+ * @value: value to set
+ *
+ * Returns: 0 on success, or negative errno on failure.
+ */
+int gpiochip_fwd_gpio_set(struct gpiochip_fwd *fwd, unsigned int offset, int value)
+{
+ struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
+
+ return gpio_fwd_set(gc, offset, value);
+}
+EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_set, "GPIO_FORWARDER");
+
+/**
+ * gpiochip_fwd_gpio_set_multiple - Assign values to multiple GPIO forwarder lines
+ * @fwd: GPIO forwarder
+ * @mask: bit mask array; one bit per output; BITS_PER_LONG bits per word
+ * defines which outputs are to be changed
+ * @bits: bit value array; one bit per output; BITS_PER_LONG bits per word
+ * defines the values the outputs specified by mask are to be set to
+ *
+ * Returns: 0 on success, or negative errno on failure.
+ */
+int gpiochip_fwd_gpio_set_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
+ unsigned long *bits)
+{
+ struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
+
+ return gpio_fwd_set_multiple_locked(gc, mask, bits);
+}
+EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_set_multiple, "GPIO_FORWARDER");
+
+/**
+ * gpiochip_fwd_gpio_set_config - Set @config for a GPIO forwarder line
+ * @fwd: GPIO forwarder
+ * @offset: the offset of the line
+ * @config: Same packed config format as generic pinconf
+ *
+ * Returns: 0 on success, %-ENOTSUPP if the controller doesn't support setting
+ * the configuration.
+ */
+int gpiochip_fwd_gpio_set_config(struct gpiochip_fwd *fwd, unsigned int offset,
+ unsigned long config)
+{
+ struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
+
+ return gpio_fwd_set_config(gc, offset, config);
+}
+EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_set_config, "GPIO_FORWARDER");
+
+/**
+ * gpiochip_fwd_gpio_to_irq - Return the IRQ corresponding to a GPIO forwarder line
+ * @fwd: GPIO forwarder
+ * @offset: the offset of the line
+ *
+ * Returns: The Linux IRQ corresponding to the passed line, or an error code in
+ * case of error.
+ */
+int gpiochip_fwd_gpio_to_irq(struct gpiochip_fwd *fwd, unsigned int offset)
+{
+ struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
+
+ return gpio_fwd_to_irq(gc, offset);
+}
+EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_to_irq, "GPIO_FORWARDER");
+
+/**
+ * devm_gpiochip_fwd_alloc - Allocate and initialize a new GPIO forwarder
+ * @dev: Parent device pointer
+ * @ngpios: Number of GPIOs in the forwarder
+ *
+ * Returns: An opaque object pointer, or an ERR_PTR()-encoded negative error
+ * code on failure.
+ */
+struct gpiochip_fwd *devm_gpiochip_fwd_alloc(struct device *dev,
+ unsigned int ngpios)
{
struct gpiochip_fwd *fwd;
struct gpio_chip *chip;
@@ -507,10 +681,18 @@ devm_gpiochip_fwd_alloc(struct device *dev, unsigned int ngpios)
return fwd;
}
+EXPORT_SYMBOL_NS_GPL(devm_gpiochip_fwd_alloc, "GPIO_FORWARDER");
-static int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd,
- struct gpio_desc *desc,
- unsigned int offset)
+/**
+ * gpiochip_fwd_desc_add - Add a GPIO desc in the forwarder
+ * @fwd: GPIO forwarder
+ * @desc: GPIO descriptor to register
+ * @offset: offset for the GPIO in the forwarder
+ *
+ * Returns: 0 on success, or negative errno on failure.
+ */
+int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd, struct gpio_desc *desc,
+ unsigned int offset)
{
struct gpio_chip *parent = gpiod_to_chip(desc);
struct gpio_chip *chip = &fwd->chip;
@@ -537,8 +719,15 @@ static int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd,
return 0;
}
+EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_desc_add, "GPIO_FORWARDER");
-static int gpiochip_fwd_register(struct gpiochip_fwd *fwd)
+/**
+ * gpiochip_fwd_register - Register a GPIO forwarder
+ * @fwd: GPIO forwarder
+ *
+ * Returns: 0 on success, or negative errno on failure.
+ */
+int gpiochip_fwd_register(struct gpiochip_fwd *fwd)
{
struct gpio_chip *chip = &fwd->chip;
@@ -549,6 +738,7 @@ static int gpiochip_fwd_register(struct gpiochip_fwd *fwd)
return devm_gpiochip_add_data(chip->parent, chip, fwd);
}
+EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_register, "GPIO_FORWARDER");
/**
* gpiochip_fwd_create() - Create a new GPIO forwarder
diff --git a/include/linux/gpio/forwarder.h b/include/linux/gpio/forwarder.h
new file mode 100644
index 000000000000..e21a1b7b1905
--- /dev/null
+++ b/include/linux/gpio/forwarder.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LINUX_GPIO_FORWARDER_H
+#define __LINUX_GPIO_FORWARDER_H
+
+struct gpio_desc;
+struct gpio_chip;
+struct gpiochip_fwd;
+
+struct gpiochip_fwd *devm_gpiochip_fwd_alloc(struct device *dev,
+ unsigned int ngpios);
+int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd,
+ struct gpio_desc *desc, unsigned int offset);
+int gpiochip_fwd_register(struct gpiochip_fwd *fwd);
+
+struct gpio_chip *gpiochip_fwd_get_gpiochip(struct gpiochip_fwd *fwd);
+
+int gpiochip_fwd_gpio_get_direction(struct gpiochip_fwd *fwd,
+ unsigned int offset);
+int gpiochip_fwd_gpio_direction_input(struct gpiochip_fwd *fwd,
+ unsigned int offset);
+int gpiochip_fwd_gpio_direction_output(struct gpiochip_fwd *fwd,
+ unsigned int offset,
+ int value);
+int gpiochip_fwd_gpio_get(struct gpiochip_fwd *fwd, unsigned int offset);
+int gpiochip_fwd_gpio_get_multiple(struct gpiochip_fwd *fwd,
+ unsigned long *mask,
+ unsigned long *bits);
+int gpiochip_fwd_gpio_set(struct gpiochip_fwd *fwd, unsigned int offset,
+ int value);
+int gpiochip_fwd_gpio_set_multiple(struct gpiochip_fwd *fwd,
+ unsigned long *mask,
+ unsigned long *bits);
+int gpiochip_fwd_gpio_set_config(struct gpiochip_fwd *fwd, unsigned int offset,
+ unsigned long config);
+int gpiochip_fwd_gpio_to_irq(struct gpiochip_fwd *fwd, unsigned int offset);
+
+#endif
--
2.39.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 07/10] gpio: aggregator: handle runtime registration of gpio_desc in gpiochip_fwd
2025-06-11 9:00 [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Thomas Richard
` (5 preceding siblings ...)
2025-06-11 9:00 ` [PATCH v8 06/10] gpio: aggregator: export symbols of the GPIO forwarder library Thomas Richard
@ 2025-06-11 9:00 ` Thomas Richard
2025-06-11 9:00 ` [PATCH v8 08/10] gpio: aggregator: add possibility to attach data to the forwarder Thomas Richard
` (4 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Thomas Richard @ 2025-06-11 9:00 UTC (permalink / raw)
To: Linus Walleij, Andy Shevchenko, Bartosz Golaszewski,
Geert Uytterhoeven, Kees Cook, Andy Shevchenko
Cc: linux-gpio, linux-kernel, thomas.petazzoni, DanieleCleri,
GaryWang, linux-hardening, Thomas Richard
Add request() callback to check if the GPIO descriptor was well registered
in the gpiochip_fwd before using it. This is done to handle the case where
GPIO descriptor is added at runtime in the forwarder.
If at least one GPIO descriptor was not added before the forwarder
registration, we assume the forwarder can sleep as if a GPIO is added at
runtime it may sleep.
Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
---
drivers/gpio/gpio-aggregator.c | 63 ++++++++++++++++++++++++++++++++++++++----
include/linux/gpio/forwarder.h | 2 ++
2 files changed, 59 insertions(+), 6 deletions(-)
diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c
index 6da14a5064c6..8bdde022f292 100644
--- a/drivers/gpio/gpio-aggregator.c
+++ b/drivers/gpio/gpio-aggregator.c
@@ -246,6 +246,7 @@ struct gpiochip_fwd {
spinlock_t slock; /* protects tmp[] if !can_sleep */
};
struct gpiochip_fwd_timing *delay_timings;
+ unsigned long *valid_mask;
unsigned long tmp[]; /* values and descs for multiple ops */
};
@@ -254,10 +255,24 @@ struct gpiochip_fwd {
#define fwd_tmp_size(ngpios) (BITS_TO_LONGS((ngpios)) + (ngpios))
+static int gpio_fwd_request(struct gpio_chip *chip, unsigned int offset)
+{
+ struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
+
+ return test_bit(offset, fwd->valid_mask) ? 0 : -ENODEV;
+}
+
static int gpio_fwd_get_direction(struct gpio_chip *chip, unsigned int offset)
{
struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
+ /*
+ * get_direction() is called during gpiochip registration, return
+ * -ENODEV if there is no GPIO desc for the line.
+ */
+ if (!test_bit(offset, fwd->valid_mask))
+ return -ENODEV;
+
return gpiod_get_direction(fwd->descs[offset]);
}
@@ -489,6 +504,21 @@ struct gpio_chip *gpiochip_fwd_get_gpiochip(struct gpiochip_fwd *fwd)
}
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_get_gpiochip, "GPIO_FORWARDER");
+/**
+ * gpiochip_fwd_gpio_request - Request a line of the GPIO forwarder
+ * @fwd: GPIO forwarder
+ * @offset: the offset of the line to request
+ *
+ * Returns: 0 on success, or negative errno on failure.
+ */
+int gpiochip_fwd_gpio_request(struct gpiochip_fwd *fwd, unsigned int offset)
+{
+ struct gpio_chip *gc = gpiochip_fwd_get_gpiochip(fwd);
+
+ return gpio_fwd_request(gc, offset);
+}
+EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_gpio_request, "GPIO_FORWARDER");
+
/**
* gpiochip_fwd_gpio_get_direction - Return the current direction of a GPIO forwarder line
* @fwd: GPIO forwarder
@@ -663,11 +693,16 @@ struct gpiochip_fwd *devm_gpiochip_fwd_alloc(struct device *dev,
if (!fwd->descs)
return ERR_PTR(-ENOMEM);
+ fwd->valid_mask = devm_bitmap_zalloc(dev, ngpios, GFP_KERNEL);
+ if (!fwd->valid_mask)
+ return ERR_PTR(-ENOMEM);
+
chip = &fwd->chip;
chip->label = dev_name(dev);
chip->parent = dev;
chip->owner = THIS_MODULE;
+ chip->request = gpio_fwd_request;
chip->get_direction = gpio_fwd_get_direction;
chip->direction_input = gpio_fwd_direction_input;
chip->direction_output = gpio_fwd_direction_output;
@@ -694,24 +729,21 @@ EXPORT_SYMBOL_NS_GPL(devm_gpiochip_fwd_alloc, "GPIO_FORWARDER");
int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd, struct gpio_desc *desc,
unsigned int offset)
{
- struct gpio_chip *parent = gpiod_to_chip(desc);
struct gpio_chip *chip = &fwd->chip;
if (offset > chip->ngpio)
return -EINVAL;
+ if (test_and_set_bit(offset, fwd->valid_mask))
+ return -EEXIST;
+
/*
* If any of the GPIO lines are sleeping, then the entire forwarder
* will be sleeping.
- * If any of the chips support .set_config(), then the forwarder will
- * support setting configs.
*/
if (gpiod_cansleep(desc))
chip->can_sleep = true;
- if (parent && parent->set_config)
- chip->set_config = gpio_fwd_set_config;
-
fwd->descs[offset] = desc;
dev_dbg(chip->parent, "%u => gpio %d irq %d\n", offset,
@@ -721,6 +753,18 @@ int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd, struct gpio_desc *desc,
}
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_desc_add, "GPIO_FORWARDER");
+/**
+ * gpiochip_fwd_desc_free - Remove a GPIO desc from the forwarder
+ * @fwd: GPIO forwarder
+ * @offset: offset of GPIO desc to remove
+ */
+void gpiochip_fwd_desc_free(struct gpiochip_fwd *fwd, unsigned int offset)
+{
+ if (test_and_clear_bit(offset, fwd->valid_mask))
+ gpiod_put(fwd->descs[offset]);
+}
+EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_desc_free, "GPIO_FORWARDER");
+
/**
* gpiochip_fwd_register - Register a GPIO forwarder
* @fwd: GPIO forwarder
@@ -731,6 +775,13 @@ int gpiochip_fwd_register(struct gpiochip_fwd *fwd)
{
struct gpio_chip *chip = &fwd->chip;
+ /*
+ * Some gpio_desc were not registered. They will be registered at runtime
+ * but we have to suppose they can sleep.
+ */
+ if (!bitmap_full(fwd->valid_mask, chip->ngpio))
+ chip->can_sleep = true;
+
if (chip->can_sleep)
mutex_init(&fwd->mlock);
else
diff --git a/include/linux/gpio/forwarder.h b/include/linux/gpio/forwarder.h
index e21a1b7b1905..45e0190308f0 100644
--- a/include/linux/gpio/forwarder.h
+++ b/include/linux/gpio/forwarder.h
@@ -10,10 +10,12 @@ struct gpiochip_fwd *devm_gpiochip_fwd_alloc(struct device *dev,
unsigned int ngpios);
int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd,
struct gpio_desc *desc, unsigned int offset);
+void gpiochip_fwd_desc_free(struct gpiochip_fwd *fwd, unsigned int offset);
int gpiochip_fwd_register(struct gpiochip_fwd *fwd);
struct gpio_chip *gpiochip_fwd_get_gpiochip(struct gpiochip_fwd *fwd);
+int gpiochip_fwd_gpio_request(struct gpiochip_fwd *fwd, unsigned int offset);
int gpiochip_fwd_gpio_get_direction(struct gpiochip_fwd *fwd,
unsigned int offset);
int gpiochip_fwd_gpio_direction_input(struct gpiochip_fwd *fwd,
--
2.39.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 08/10] gpio: aggregator: add possibility to attach data to the forwarder
2025-06-11 9:00 [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Thomas Richard
` (6 preceding siblings ...)
2025-06-11 9:00 ` [PATCH v8 07/10] gpio: aggregator: handle runtime registration of gpio_desc in gpiochip_fwd Thomas Richard
@ 2025-06-11 9:00 ` Thomas Richard
2025-06-11 9:00 ` [PATCH v8 09/10] lib/string_choices: Add str_input_output() helper Thomas Richard
` (3 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Thomas Richard @ 2025-06-11 9:00 UTC (permalink / raw)
To: Linus Walleij, Andy Shevchenko, Bartosz Golaszewski,
Geert Uytterhoeven, Kees Cook, Andy Shevchenko
Cc: linux-gpio, linux-kernel, thomas.petazzoni, DanieleCleri,
GaryWang, linux-hardening, Thomas Richard
Add a data pointer to store private data in the forwarder.
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
---
drivers/gpio/gpio-aggregator.c | 20 ++++++++++++++++++--
include/linux/gpio/forwarder.h | 4 +++-
2 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c
index 8bdde022f292..c70912d4b39b 100644
--- a/drivers/gpio/gpio-aggregator.c
+++ b/drivers/gpio/gpio-aggregator.c
@@ -246,6 +246,7 @@ struct gpiochip_fwd {
spinlock_t slock; /* protects tmp[] if !can_sleep */
};
struct gpiochip_fwd_timing *delay_timings;
+ void *data;
unsigned long *valid_mask;
unsigned long tmp[]; /* values and descs for multiple ops */
};
@@ -504,6 +505,18 @@ struct gpio_chip *gpiochip_fwd_get_gpiochip(struct gpiochip_fwd *fwd)
}
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_get_gpiochip, "GPIO_FORWARDER");
+/**
+ * gpiochip_fwd_get_data - Get driver-private data for the GPIO forwarder
+ * @fwd: GPIO forwarder
+ *
+ * Returns: The driver-private data for the GPIO forwarder
+ */
+void *gpiochip_fwd_get_data(struct gpiochip_fwd *fwd)
+{
+ return fwd->data;
+}
+EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_get_data, "GPIO_FORWARDER");
+
/**
* gpiochip_fwd_gpio_request - Request a line of the GPIO forwarder
* @fwd: GPIO forwarder
@@ -768,10 +781,11 @@ EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_desc_free, "GPIO_FORWARDER");
/**
* gpiochip_fwd_register - Register a GPIO forwarder
* @fwd: GPIO forwarder
+ * @data: driver-private data associated with this forwarder
*
* Returns: 0 on success, or negative errno on failure.
*/
-int gpiochip_fwd_register(struct gpiochip_fwd *fwd)
+int gpiochip_fwd_register(struct gpiochip_fwd *fwd, void *data)
{
struct gpio_chip *chip = &fwd->chip;
@@ -787,6 +801,8 @@ int gpiochip_fwd_register(struct gpiochip_fwd *fwd)
else
spin_lock_init(&fwd->slock);
+ fwd->data = data;
+
return devm_gpiochip_add_data(chip->parent, chip, fwd);
}
EXPORT_SYMBOL_NS_GPL(gpiochip_fwd_register, "GPIO_FORWARDER");
@@ -831,7 +847,7 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev,
return ERR_PTR(error);
}
- error = gpiochip_fwd_register(fwd);
+ error = gpiochip_fwd_register(fwd, NULL);
if (error)
return ERR_PTR(error);
diff --git a/include/linux/gpio/forwarder.h b/include/linux/gpio/forwarder.h
index 45e0190308f0..ee5d8355f735 100644
--- a/include/linux/gpio/forwarder.h
+++ b/include/linux/gpio/forwarder.h
@@ -11,10 +11,12 @@ struct gpiochip_fwd *devm_gpiochip_fwd_alloc(struct device *dev,
int gpiochip_fwd_desc_add(struct gpiochip_fwd *fwd,
struct gpio_desc *desc, unsigned int offset);
void gpiochip_fwd_desc_free(struct gpiochip_fwd *fwd, unsigned int offset);
-int gpiochip_fwd_register(struct gpiochip_fwd *fwd);
+int gpiochip_fwd_register(struct gpiochip_fwd *fwd, void *data);
struct gpio_chip *gpiochip_fwd_get_gpiochip(struct gpiochip_fwd *fwd);
+void *gpiochip_fwd_get_data(struct gpiochip_fwd *fwd);
+
int gpiochip_fwd_gpio_request(struct gpiochip_fwd *fwd, unsigned int offset);
int gpiochip_fwd_gpio_get_direction(struct gpiochip_fwd *fwd,
unsigned int offset);
--
2.39.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 09/10] lib/string_choices: Add str_input_output() helper
2025-06-11 9:00 [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Thomas Richard
` (7 preceding siblings ...)
2025-06-11 9:00 ` [PATCH v8 08/10] gpio: aggregator: add possibility to attach data to the forwarder Thomas Richard
@ 2025-06-11 9:00 ` Thomas Richard
2025-06-11 9:00 ` [PATCH v8 10/10] pinctrl: Add pin controller driver for AAEON UP boards Thomas Richard
` (2 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Thomas Richard @ 2025-06-11 9:00 UTC (permalink / raw)
To: Linus Walleij, Andy Shevchenko, Bartosz Golaszewski,
Geert Uytterhoeven, Kees Cook, Andy Shevchenko
Cc: linux-gpio, linux-kernel, thomas.petazzoni, DanieleCleri,
GaryWang, linux-hardening, Thomas Richard
Add str_input_output() helper to return 'input' or 'output' string literal.
Also add the inversed variant str_output_input().
Suggested-by: Andy Shevchenko <andy@kernel.org>
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
---
include/linux/string_choices.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/include/linux/string_choices.h b/include/linux/string_choices.h
index f3ba4f52ff26..a27c87c954ae 100644
--- a/include/linux/string_choices.h
+++ b/include/linux/string_choices.h
@@ -41,6 +41,12 @@ static inline const char *str_high_low(bool v)
}
#define str_low_high(v) str_high_low(!(v))
+static inline const char *str_input_output(bool v)
+{
+ return v ? "input" : "output";
+}
+#define str_output_input(v) str_input_output(!(v))
+
static inline const char *str_on_off(bool v)
{
return v ? "on" : "off";
--
2.39.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v8 10/10] pinctrl: Add pin controller driver for AAEON UP boards
2025-06-11 9:00 [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Thomas Richard
` (8 preceding siblings ...)
2025-06-11 9:00 ` [PATCH v8 09/10] lib/string_choices: Add str_input_output() helper Thomas Richard
@ 2025-06-11 9:00 ` Thomas Richard
2025-06-25 8:26 ` [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Bartosz Golaszewski
2025-08-11 9:25 ` Bartosz Golaszewski
11 siblings, 0 replies; 18+ messages in thread
From: Thomas Richard @ 2025-06-11 9:00 UTC (permalink / raw)
To: Linus Walleij, Andy Shevchenko, Bartosz Golaszewski,
Geert Uytterhoeven, Kees Cook, Andy Shevchenko
Cc: linux-gpio, linux-kernel, thomas.petazzoni, DanieleCleri,
GaryWang, linux-hardening, Thomas Richard
This enables the pin control support of the onboard FPGA on AAEON UP
boards.
This FPGA acts as a level shifter between the Intel SoC pins and the pin
header, and also as a mux or switch.
+---------+ +--------------+ +---+
| | | | |
| PWM0 | \ | | H |
|----------|------ \-----|-------------| E |
| I2C0_SDA | | | A |
Intel SoC |----------|------\ | | D |
| GPIO0 | \------|-------------| E |
|----------|------ | | R |
| | FPGA | | |
----------+ +--------------+ +---+
For most of the pins, the FPGA opens/closes a switch to enable/disable
the access to the SoC pin from a pin header.
Each switch, has a direction flag that is set depending the status of the
SoC pin.
For some other pins, the FPGA acts as a mux, and routes one pin (or the
other one) to the header.
The driver also provides a GPIO chip. It requests SoC pins in GPIO mode,
and drives them in tandem with FPGA pins (switch/mux direction).
This commit adds support only for UP Squared board.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
---
drivers/pinctrl/Kconfig | 19 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/pinctrl-upboard.c | 1070 +++++++++++++++++++++++++++++++++++++
3 files changed, 1090 insertions(+)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 33db9104df17..53c923d491af 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -588,6 +588,25 @@ config PINCTRL_TH1520
This driver is needed for RISC-V development boards like
the BeagleV Ahead and the LicheePi 4A.
+config PINCTRL_UPBOARD
+ tristate "AAeon UP board FPGA pin controller"
+ depends on MFD_UPBOARD_FPGA
+ select PINMUX
+ select GENERIC_PINCTRL_GROUPS
+ select GENERIC_PINMUX_FUNCTIONS
+ select GPIOLIB
+ select GPIO_AGGREGATOR
+ help
+ Pin controller for the FPGA GPIO lines on UP boards. Due to the
+ hardware layout, the driver controls the FPGA pins in tandem with
+ their corresponding Intel SoC GPIOs.
+
+ Currently supported:
+ - UP Squared
+
+ To compile this driver as a module, choose M here: the module
+ will be called pinctrl-upboard.
+
config PINCTRL_ZYNQ
bool "Pinctrl driver for Xilinx Zynq"
depends on ARCH_ZYNQ
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index ac27e88677d1..f7246aead7b5 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_PINCTRL_SX150X) += pinctrl-sx150x.o
obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o
obj-$(CONFIG_PINCTRL_TPS6594) += pinctrl-tps6594.o
obj-$(CONFIG_PINCTRL_TH1520) += pinctrl-th1520.o
+obj-$(CONFIG_PINCTRL_UPBOARD) += pinctrl-upboard.o
obj-$(CONFIG_PINCTRL_ZYNQMP) += pinctrl-zynqmp.o
obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o
diff --git a/drivers/pinctrl/pinctrl-upboard.c b/drivers/pinctrl/pinctrl-upboard.c
new file mode 100644
index 000000000000..f8c8b9d84990
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-upboard.c
@@ -0,0 +1,1070 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * UP board pin control driver.
+ *
+ * Copyright (C) 2025 Bootlin
+ *
+ * Author: Thomas Richard <thomas.richard@bootlin.com>
+ */
+
+#include <linux/array_size.h>
+#include <linux/container_of.h>
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/err.h>
+#include <linux/gpio/forwarder.h>
+#include <linux/mfd/upboard-fpga.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/seq_file.h>
+#include <linux/stddef.h>
+#include <linux/string_choices.h>
+#include <linux/types.h>
+
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include <linux/gpio/driver.h>
+#include <linux/gpio/consumer.h>
+
+#include "core.h"
+#include "pinmux.h"
+
+enum upboard_pin_mode {
+ UPBOARD_PIN_MODE_FUNCTION,
+ UPBOARD_PIN_MODE_GPIO_IN,
+ UPBOARD_PIN_MODE_GPIO_OUT,
+ UPBOARD_PIN_MODE_DISABLED,
+};
+
+struct upboard_pin {
+ struct regmap_field *funcbit;
+ struct regmap_field *enbit;
+ struct regmap_field *dirbit;
+};
+
+struct upboard_pingroup {
+ struct pingroup grp;
+ enum upboard_pin_mode mode;
+ const enum upboard_pin_mode *modes;
+};
+
+struct upboard_pinctrl_data {
+ const struct upboard_pingroup *groups;
+ size_t ngroups;
+ const struct pinfunction *funcs;
+ size_t nfuncs;
+ const unsigned int *pin_header;
+ size_t ngpio;
+};
+
+struct upboard_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *pctldev;
+ const struct upboard_pinctrl_data *pctrl_data;
+ struct gpio_pin_range pin_range;
+ struct upboard_pin *pins;
+};
+
+struct upboard_pinctrl_map {
+ const struct pinctrl_map *maps;
+ size_t nmaps;
+};
+
+enum upboard_func0_fpgabit {
+ UPBOARD_FUNC_I2C0_EN = 8,
+ UPBOARD_FUNC_I2C1_EN = 9,
+ UPBOARD_FUNC_CEC0_EN = 12,
+ UPBOARD_FUNC_ADC0_EN = 14,
+};
+
+static const struct reg_field upboard_i2c0_reg =
+ REG_FIELD(UPBOARD_REG_FUNC_EN0, UPBOARD_FUNC_I2C0_EN, UPBOARD_FUNC_I2C0_EN);
+
+static const struct reg_field upboard_i2c1_reg =
+ REG_FIELD(UPBOARD_REG_FUNC_EN0, UPBOARD_FUNC_I2C1_EN, UPBOARD_FUNC_I2C1_EN);
+
+static const struct reg_field upboard_adc0_reg =
+ REG_FIELD(UPBOARD_REG_FUNC_EN0, UPBOARD_FUNC_ADC0_EN, UPBOARD_FUNC_ADC0_EN);
+
+#define UPBOARD_UP_BIT_TO_PIN(bit) UPBOARD_UP_BIT_##bit
+
+#define UPBOARD_UP_PIN_NAME(id) \
+ { \
+ .number = UPBOARD_UP_BIT_##id, \
+ .name = #id, \
+ }
+
+#define UPBOARD_UP_PIN_MUX(bit, data) \
+ { \
+ .number = UPBOARD_UP_BIT_##bit, \
+ .name = "PINMUX_"#bit, \
+ .drv_data = (void *)(data), \
+ }
+
+#define UPBOARD_UP_PIN_FUNC(id, data) \
+ { \
+ .number = UPBOARD_UP_BIT_##id, \
+ .name = #id, \
+ .drv_data = (void *)(data), \
+ }
+
+enum upboard_up_fpgabit {
+ UPBOARD_UP_BIT_I2C1_SDA,
+ UPBOARD_UP_BIT_I2C1_SCL,
+ UPBOARD_UP_BIT_ADC0,
+ UPBOARD_UP_BIT_UART1_RTS,
+ UPBOARD_UP_BIT_GPIO27,
+ UPBOARD_UP_BIT_GPIO22,
+ UPBOARD_UP_BIT_SPI_MOSI,
+ UPBOARD_UP_BIT_SPI_MISO,
+ UPBOARD_UP_BIT_SPI_CLK,
+ UPBOARD_UP_BIT_I2C0_SDA,
+ UPBOARD_UP_BIT_GPIO5,
+ UPBOARD_UP_BIT_GPIO6,
+ UPBOARD_UP_BIT_PWM1,
+ UPBOARD_UP_BIT_I2S_FRM,
+ UPBOARD_UP_BIT_GPIO26,
+ UPBOARD_UP_BIT_UART1_TX,
+ UPBOARD_UP_BIT_UART1_RX,
+ UPBOARD_UP_BIT_I2S_CLK,
+ UPBOARD_UP_BIT_GPIO23,
+ UPBOARD_UP_BIT_GPIO24,
+ UPBOARD_UP_BIT_GPIO25,
+ UPBOARD_UP_BIT_SPI_CS0,
+ UPBOARD_UP_BIT_SPI_CS1,
+ UPBOARD_UP_BIT_I2C0_SCL,
+ UPBOARD_UP_BIT_PWM0,
+ UPBOARD_UP_BIT_UART1_CTS,
+ UPBOARD_UP_BIT_I2S_DIN,
+ UPBOARD_UP_BIT_I2S_DOUT,
+};
+
+static const struct pinctrl_pin_desc upboard_up_pins[] = {
+ UPBOARD_UP_PIN_FUNC(I2C1_SDA, &upboard_i2c1_reg),
+ UPBOARD_UP_PIN_FUNC(I2C1_SCL, &upboard_i2c1_reg),
+ UPBOARD_UP_PIN_FUNC(ADC0, &upboard_adc0_reg),
+ UPBOARD_UP_PIN_NAME(UART1_RTS),
+ UPBOARD_UP_PIN_NAME(GPIO27),
+ UPBOARD_UP_PIN_NAME(GPIO22),
+ UPBOARD_UP_PIN_NAME(SPI_MOSI),
+ UPBOARD_UP_PIN_NAME(SPI_MISO),
+ UPBOARD_UP_PIN_NAME(SPI_CLK),
+ UPBOARD_UP_PIN_FUNC(I2C0_SDA, &upboard_i2c0_reg),
+ UPBOARD_UP_PIN_NAME(GPIO5),
+ UPBOARD_UP_PIN_NAME(GPIO6),
+ UPBOARD_UP_PIN_NAME(PWM1),
+ UPBOARD_UP_PIN_NAME(I2S_FRM),
+ UPBOARD_UP_PIN_NAME(GPIO26),
+ UPBOARD_UP_PIN_NAME(UART1_TX),
+ UPBOARD_UP_PIN_NAME(UART1_RX),
+ UPBOARD_UP_PIN_NAME(I2S_CLK),
+ UPBOARD_UP_PIN_NAME(GPIO23),
+ UPBOARD_UP_PIN_NAME(GPIO24),
+ UPBOARD_UP_PIN_NAME(GPIO25),
+ UPBOARD_UP_PIN_NAME(SPI_CS0),
+ UPBOARD_UP_PIN_NAME(SPI_CS1),
+ UPBOARD_UP_PIN_FUNC(I2C0_SCL, &upboard_i2c0_reg),
+ UPBOARD_UP_PIN_NAME(PWM0),
+ UPBOARD_UP_PIN_NAME(UART1_CTS),
+ UPBOARD_UP_PIN_NAME(I2S_DIN),
+ UPBOARD_UP_PIN_NAME(I2S_DOUT),
+};
+
+static const unsigned int upboard_up_pin_header[] = {
+ UPBOARD_UP_BIT_TO_PIN(I2C0_SDA),
+ UPBOARD_UP_BIT_TO_PIN(I2C0_SCL),
+ UPBOARD_UP_BIT_TO_PIN(I2C1_SDA),
+ UPBOARD_UP_BIT_TO_PIN(I2C1_SCL),
+ UPBOARD_UP_BIT_TO_PIN(ADC0),
+ UPBOARD_UP_BIT_TO_PIN(GPIO5),
+ UPBOARD_UP_BIT_TO_PIN(GPIO6),
+ UPBOARD_UP_BIT_TO_PIN(SPI_CS1),
+ UPBOARD_UP_BIT_TO_PIN(SPI_CS0),
+ UPBOARD_UP_BIT_TO_PIN(SPI_MISO),
+ UPBOARD_UP_BIT_TO_PIN(SPI_MOSI),
+ UPBOARD_UP_BIT_TO_PIN(SPI_CLK),
+ UPBOARD_UP_BIT_TO_PIN(PWM0),
+ UPBOARD_UP_BIT_TO_PIN(PWM1),
+ UPBOARD_UP_BIT_TO_PIN(UART1_TX),
+ UPBOARD_UP_BIT_TO_PIN(UART1_RX),
+ UPBOARD_UP_BIT_TO_PIN(UART1_CTS),
+ UPBOARD_UP_BIT_TO_PIN(UART1_RTS),
+ UPBOARD_UP_BIT_TO_PIN(I2S_CLK),
+ UPBOARD_UP_BIT_TO_PIN(I2S_FRM),
+ UPBOARD_UP_BIT_TO_PIN(I2S_DIN),
+ UPBOARD_UP_BIT_TO_PIN(I2S_DOUT),
+ UPBOARD_UP_BIT_TO_PIN(GPIO22),
+ UPBOARD_UP_BIT_TO_PIN(GPIO23),
+ UPBOARD_UP_BIT_TO_PIN(GPIO24),
+ UPBOARD_UP_BIT_TO_PIN(GPIO25),
+ UPBOARD_UP_BIT_TO_PIN(GPIO26),
+ UPBOARD_UP_BIT_TO_PIN(GPIO27),
+};
+
+static const unsigned int upboard_up_uart1_pins[] = {
+ UPBOARD_UP_BIT_TO_PIN(UART1_TX),
+ UPBOARD_UP_BIT_TO_PIN(UART1_RX),
+ UPBOARD_UP_BIT_TO_PIN(UART1_RTS),
+ UPBOARD_UP_BIT_TO_PIN(UART1_CTS),
+};
+
+static const enum upboard_pin_mode upboard_up_uart1_modes[] = {
+ UPBOARD_PIN_MODE_GPIO_OUT,
+ UPBOARD_PIN_MODE_GPIO_IN,
+ UPBOARD_PIN_MODE_GPIO_OUT,
+ UPBOARD_PIN_MODE_GPIO_IN,
+};
+
+static_assert(ARRAY_SIZE(upboard_up_uart1_modes) == ARRAY_SIZE(upboard_up_uart1_pins));
+
+static const unsigned int upboard_up_i2c0_pins[] = {
+ UPBOARD_UP_BIT_TO_PIN(I2C0_SCL),
+ UPBOARD_UP_BIT_TO_PIN(I2C0_SDA),
+};
+
+static const unsigned int upboard_up_i2c1_pins[] = {
+ UPBOARD_UP_BIT_TO_PIN(I2C1_SCL),
+ UPBOARD_UP_BIT_TO_PIN(I2C1_SDA),
+};
+
+static const unsigned int upboard_up_spi2_pins[] = {
+ UPBOARD_UP_BIT_TO_PIN(SPI_MOSI),
+ UPBOARD_UP_BIT_TO_PIN(SPI_MISO),
+ UPBOARD_UP_BIT_TO_PIN(SPI_CLK),
+ UPBOARD_UP_BIT_TO_PIN(SPI_CS0),
+ UPBOARD_UP_BIT_TO_PIN(SPI_CS1),
+};
+
+static const enum upboard_pin_mode upboard_up_spi2_modes[] = {
+ UPBOARD_PIN_MODE_GPIO_OUT,
+ UPBOARD_PIN_MODE_GPIO_IN,
+ UPBOARD_PIN_MODE_GPIO_OUT,
+ UPBOARD_PIN_MODE_GPIO_OUT,
+ UPBOARD_PIN_MODE_GPIO_OUT,
+};
+
+static_assert(ARRAY_SIZE(upboard_up_spi2_modes) == ARRAY_SIZE(upboard_up_spi2_pins));
+
+static const unsigned int upboard_up_i2s0_pins[] = {
+ UPBOARD_UP_BIT_TO_PIN(I2S_FRM),
+ UPBOARD_UP_BIT_TO_PIN(I2S_CLK),
+ UPBOARD_UP_BIT_TO_PIN(I2S_DIN),
+ UPBOARD_UP_BIT_TO_PIN(I2S_DOUT),
+};
+
+static const enum upboard_pin_mode upboard_up_i2s0_modes[] = {
+ UPBOARD_PIN_MODE_GPIO_OUT,
+ UPBOARD_PIN_MODE_GPIO_OUT,
+ UPBOARD_PIN_MODE_GPIO_IN,
+ UPBOARD_PIN_MODE_GPIO_OUT,
+};
+
+static_assert(ARRAY_SIZE(upboard_up_i2s0_pins) == ARRAY_SIZE(upboard_up_i2s0_modes));
+
+static const unsigned int upboard_up_pwm0_pins[] = {
+ UPBOARD_UP_BIT_TO_PIN(PWM0),
+};
+
+static const unsigned int upboard_up_pwm1_pins[] = {
+ UPBOARD_UP_BIT_TO_PIN(PWM1),
+};
+
+static const unsigned int upboard_up_adc0_pins[] = {
+ UPBOARD_UP_BIT_TO_PIN(ADC0),
+};
+
+#define UPBOARD_PINGROUP(n, p, m) \
+{ \
+ .grp = PINCTRL_PINGROUP(n, p, ARRAY_SIZE(p)), \
+ .mode = __builtin_choose_expr( \
+ __builtin_types_compatible_p(typeof(m), const enum upboard_pin_mode *), \
+ 0, m), \
+ .modes = __builtin_choose_expr( \
+ __builtin_types_compatible_p(typeof(m), const enum upboard_pin_mode *), \
+ m, NULL), \
+}
+
+static const struct upboard_pingroup upboard_up_pin_groups[] = {
+ UPBOARD_PINGROUP("uart1_grp", upboard_up_uart1_pins, &upboard_up_uart1_modes[0]),
+ UPBOARD_PINGROUP("i2c0_grp", upboard_up_i2c0_pins, UPBOARD_PIN_MODE_GPIO_OUT),
+ UPBOARD_PINGROUP("i2c1_grp", upboard_up_i2c1_pins, UPBOARD_PIN_MODE_GPIO_OUT),
+ UPBOARD_PINGROUP("spi2_grp", upboard_up_spi2_pins, &upboard_up_spi2_modes[0]),
+ UPBOARD_PINGROUP("i2s0_grp", upboard_up_i2s0_pins, &upboard_up_i2s0_modes[0]),
+ UPBOARD_PINGROUP("pwm0_grp", upboard_up_pwm0_pins, UPBOARD_PIN_MODE_GPIO_OUT),
+ UPBOARD_PINGROUP("pwm1_grp", upboard_up_pwm1_pins, UPBOARD_PIN_MODE_GPIO_OUT),
+ UPBOARD_PINGROUP("adc0_grp", upboard_up_adc0_pins, UPBOARD_PIN_MODE_GPIO_IN),
+};
+
+static const char * const upboard_up_uart1_groups[] = { "uart1_grp" };
+static const char * const upboard_up_i2c0_groups[] = { "i2c0_grp" };
+static const char * const upboard_up_i2c1_groups[] = { "i2c1_grp" };
+static const char * const upboard_up_spi2_groups[] = { "spi2_grp" };
+static const char * const upboard_up_i2s0_groups[] = { "i2s0_grp" };
+static const char * const upboard_up_pwm0_groups[] = { "pwm0_grp" };
+static const char * const upboard_up_pwm1_groups[] = { "pwm1_grp" };
+static const char * const upboard_up_adc0_groups[] = { "adc0_grp" };
+
+#define UPBOARD_FUNCTION(func, groups) PINCTRL_PINFUNCTION(func, groups, ARRAY_SIZE(groups))
+
+static const struct pinfunction upboard_up_pin_functions[] = {
+ UPBOARD_FUNCTION("uart1", upboard_up_uart1_groups),
+ UPBOARD_FUNCTION("i2c0", upboard_up_i2c0_groups),
+ UPBOARD_FUNCTION("i2c1", upboard_up_i2c1_groups),
+ UPBOARD_FUNCTION("spi2", upboard_up_spi2_groups),
+ UPBOARD_FUNCTION("i2s0", upboard_up_i2s0_groups),
+ UPBOARD_FUNCTION("pwm0", upboard_up_pwm0_groups),
+ UPBOARD_FUNCTION("pwm1", upboard_up_pwm1_groups),
+ UPBOARD_FUNCTION("adc0", upboard_up_adc0_groups),
+};
+
+static const struct upboard_pinctrl_data upboard_up_pinctrl_data = {
+ .groups = &upboard_up_pin_groups[0],
+ .ngroups = ARRAY_SIZE(upboard_up_pin_groups),
+ .funcs = &upboard_up_pin_functions[0],
+ .nfuncs = ARRAY_SIZE(upboard_up_pin_functions),
+ .pin_header = &upboard_up_pin_header[0],
+ .ngpio = ARRAY_SIZE(upboard_up_pin_header),
+};
+
+#define UPBOARD_UP2_BIT_TO_PIN(bit) UPBOARD_UP2_BIT_##bit
+
+#define UPBOARD_UP2_PIN_NAME(id) \
+ { \
+ .number = UPBOARD_UP2_BIT_##id, \
+ .name = #id, \
+ }
+
+#define UPBOARD_UP2_PIN_MUX(bit, data) \
+ { \
+ .number = UPBOARD_UP2_BIT_##bit, \
+ .name = "PINMUX_"#bit, \
+ .drv_data = (void *)(data), \
+ }
+
+#define UPBOARD_UP2_PIN_FUNC(id, data) \
+ { \
+ .number = UPBOARD_UP2_BIT_##id, \
+ .name = #id, \
+ .drv_data = (void *)(data), \
+ }
+
+enum upboard_up2_fpgabit {
+ UPBOARD_UP2_BIT_UART1_TXD,
+ UPBOARD_UP2_BIT_UART1_RXD,
+ UPBOARD_UP2_BIT_UART1_RTS,
+ UPBOARD_UP2_BIT_UART1_CTS,
+ UPBOARD_UP2_BIT_GPIO3_ADC0,
+ UPBOARD_UP2_BIT_GPIO5_ADC2,
+ UPBOARD_UP2_BIT_GPIO6_ADC3,
+ UPBOARD_UP2_BIT_GPIO11,
+ UPBOARD_UP2_BIT_EXHAT_LVDS1n,
+ UPBOARD_UP2_BIT_EXHAT_LVDS1p,
+ UPBOARD_UP2_BIT_SPI2_TXD,
+ UPBOARD_UP2_BIT_SPI2_RXD,
+ UPBOARD_UP2_BIT_SPI2_FS1,
+ UPBOARD_UP2_BIT_SPI2_FS0,
+ UPBOARD_UP2_BIT_SPI2_CLK,
+ UPBOARD_UP2_BIT_SPI1_TXD,
+ UPBOARD_UP2_BIT_SPI1_RXD,
+ UPBOARD_UP2_BIT_SPI1_FS1,
+ UPBOARD_UP2_BIT_SPI1_FS0,
+ UPBOARD_UP2_BIT_SPI1_CLK,
+ UPBOARD_UP2_BIT_I2C0_SCL,
+ UPBOARD_UP2_BIT_I2C0_SDA,
+ UPBOARD_UP2_BIT_I2C1_SCL,
+ UPBOARD_UP2_BIT_I2C1_SDA,
+ UPBOARD_UP2_BIT_PWM1,
+ UPBOARD_UP2_BIT_PWM0,
+ UPBOARD_UP2_BIT_EXHAT_LVDS0n,
+ UPBOARD_UP2_BIT_EXHAT_LVDS0p,
+ UPBOARD_UP2_BIT_GPIO24,
+ UPBOARD_UP2_BIT_GPIO10,
+ UPBOARD_UP2_BIT_GPIO2,
+ UPBOARD_UP2_BIT_GPIO1,
+ UPBOARD_UP2_BIT_EXHAT_LVDS3n,
+ UPBOARD_UP2_BIT_EXHAT_LVDS3p,
+ UPBOARD_UP2_BIT_EXHAT_LVDS4n,
+ UPBOARD_UP2_BIT_EXHAT_LVDS4p,
+ UPBOARD_UP2_BIT_EXHAT_LVDS5n,
+ UPBOARD_UP2_BIT_EXHAT_LVDS5p,
+ UPBOARD_UP2_BIT_I2S_SDO,
+ UPBOARD_UP2_BIT_I2S_SDI,
+ UPBOARD_UP2_BIT_I2S_WS_SYNC,
+ UPBOARD_UP2_BIT_I2S_BCLK,
+ UPBOARD_UP2_BIT_EXHAT_LVDS6n,
+ UPBOARD_UP2_BIT_EXHAT_LVDS6p,
+ UPBOARD_UP2_BIT_EXHAT_LVDS7n,
+ UPBOARD_UP2_BIT_EXHAT_LVDS7p,
+ UPBOARD_UP2_BIT_EXHAT_LVDS2n,
+ UPBOARD_UP2_BIT_EXHAT_LVDS2p,
+};
+
+static const struct pinctrl_pin_desc upboard_up2_pins[] = {
+ UPBOARD_UP2_PIN_NAME(UART1_TXD),
+ UPBOARD_UP2_PIN_NAME(UART1_RXD),
+ UPBOARD_UP2_PIN_NAME(UART1_RTS),
+ UPBOARD_UP2_PIN_NAME(UART1_CTS),
+ UPBOARD_UP2_PIN_NAME(GPIO3_ADC0),
+ UPBOARD_UP2_PIN_NAME(GPIO5_ADC2),
+ UPBOARD_UP2_PIN_NAME(GPIO6_ADC3),
+ UPBOARD_UP2_PIN_NAME(GPIO11),
+ UPBOARD_UP2_PIN_NAME(EXHAT_LVDS1n),
+ UPBOARD_UP2_PIN_NAME(EXHAT_LVDS1p),
+ UPBOARD_UP2_PIN_NAME(SPI2_TXD),
+ UPBOARD_UP2_PIN_NAME(SPI2_RXD),
+ UPBOARD_UP2_PIN_NAME(SPI2_FS1),
+ UPBOARD_UP2_PIN_NAME(SPI2_FS0),
+ UPBOARD_UP2_PIN_NAME(SPI2_CLK),
+ UPBOARD_UP2_PIN_NAME(SPI1_TXD),
+ UPBOARD_UP2_PIN_NAME(SPI1_RXD),
+ UPBOARD_UP2_PIN_NAME(SPI1_FS1),
+ UPBOARD_UP2_PIN_NAME(SPI1_FS0),
+ UPBOARD_UP2_PIN_NAME(SPI1_CLK),
+ UPBOARD_UP2_PIN_MUX(I2C0_SCL, &upboard_i2c0_reg),
+ UPBOARD_UP2_PIN_MUX(I2C0_SDA, &upboard_i2c0_reg),
+ UPBOARD_UP2_PIN_MUX(I2C1_SCL, &upboard_i2c1_reg),
+ UPBOARD_UP2_PIN_MUX(I2C1_SDA, &upboard_i2c1_reg),
+ UPBOARD_UP2_PIN_NAME(PWM1),
+ UPBOARD_UP2_PIN_NAME(PWM0),
+ UPBOARD_UP2_PIN_NAME(EXHAT_LVDS0n),
+ UPBOARD_UP2_PIN_NAME(EXHAT_LVDS0p),
+ UPBOARD_UP2_PIN_MUX(GPIO24, &upboard_i2c0_reg),
+ UPBOARD_UP2_PIN_MUX(GPIO10, &upboard_i2c0_reg),
+ UPBOARD_UP2_PIN_MUX(GPIO2, &upboard_i2c1_reg),
+ UPBOARD_UP2_PIN_MUX(GPIO1, &upboard_i2c1_reg),
+ UPBOARD_UP2_PIN_NAME(EXHAT_LVDS3n),
+ UPBOARD_UP2_PIN_NAME(EXHAT_LVDS3p),
+ UPBOARD_UP2_PIN_NAME(EXHAT_LVDS4n),
+ UPBOARD_UP2_PIN_NAME(EXHAT_LVDS4p),
+ UPBOARD_UP2_PIN_NAME(EXHAT_LVDS5n),
+ UPBOARD_UP2_PIN_NAME(EXHAT_LVDS5p),
+ UPBOARD_UP2_PIN_NAME(I2S_SDO),
+ UPBOARD_UP2_PIN_NAME(I2S_SDI),
+ UPBOARD_UP2_PIN_NAME(I2S_WS_SYNC),
+ UPBOARD_UP2_PIN_NAME(I2S_BCLK),
+ UPBOARD_UP2_PIN_NAME(EXHAT_LVDS6n),
+ UPBOARD_UP2_PIN_NAME(EXHAT_LVDS6p),
+ UPBOARD_UP2_PIN_NAME(EXHAT_LVDS7n),
+ UPBOARD_UP2_PIN_NAME(EXHAT_LVDS7p),
+ UPBOARD_UP2_PIN_NAME(EXHAT_LVDS2n),
+ UPBOARD_UP2_PIN_NAME(EXHAT_LVDS2p),
+};
+
+static const unsigned int upboard_up2_pin_header[] = {
+ UPBOARD_UP2_BIT_TO_PIN(GPIO10),
+ UPBOARD_UP2_BIT_TO_PIN(GPIO24),
+ UPBOARD_UP2_BIT_TO_PIN(GPIO1),
+ UPBOARD_UP2_BIT_TO_PIN(GPIO2),
+ UPBOARD_UP2_BIT_TO_PIN(GPIO3_ADC0),
+ UPBOARD_UP2_BIT_TO_PIN(GPIO11),
+ UPBOARD_UP2_BIT_TO_PIN(SPI2_CLK),
+ UPBOARD_UP2_BIT_TO_PIN(SPI1_FS1),
+ UPBOARD_UP2_BIT_TO_PIN(SPI1_FS0),
+ UPBOARD_UP2_BIT_TO_PIN(SPI1_RXD),
+ UPBOARD_UP2_BIT_TO_PIN(SPI1_TXD),
+ UPBOARD_UP2_BIT_TO_PIN(SPI1_CLK),
+ UPBOARD_UP2_BIT_TO_PIN(PWM0),
+ UPBOARD_UP2_BIT_TO_PIN(PWM1),
+ UPBOARD_UP2_BIT_TO_PIN(UART1_TXD),
+ UPBOARD_UP2_BIT_TO_PIN(UART1_RXD),
+ UPBOARD_UP2_BIT_TO_PIN(UART1_CTS),
+ UPBOARD_UP2_BIT_TO_PIN(UART1_RTS),
+ UPBOARD_UP2_BIT_TO_PIN(I2S_BCLK),
+ UPBOARD_UP2_BIT_TO_PIN(I2S_WS_SYNC),
+ UPBOARD_UP2_BIT_TO_PIN(I2S_SDI),
+ UPBOARD_UP2_BIT_TO_PIN(I2S_SDO),
+ UPBOARD_UP2_BIT_TO_PIN(GPIO6_ADC3),
+ UPBOARD_UP2_BIT_TO_PIN(SPI2_FS1),
+ UPBOARD_UP2_BIT_TO_PIN(SPI2_RXD),
+ UPBOARD_UP2_BIT_TO_PIN(SPI2_TXD),
+ UPBOARD_UP2_BIT_TO_PIN(SPI2_FS0),
+ UPBOARD_UP2_BIT_TO_PIN(GPIO5_ADC2),
+};
+
+static const unsigned int upboard_up2_uart1_pins[] = {
+ UPBOARD_UP2_BIT_TO_PIN(UART1_TXD),
+ UPBOARD_UP2_BIT_TO_PIN(UART1_RXD),
+ UPBOARD_UP2_BIT_TO_PIN(UART1_RTS),
+ UPBOARD_UP2_BIT_TO_PIN(UART1_CTS),
+};
+
+static const enum upboard_pin_mode upboard_up2_uart1_modes[] = {
+ UPBOARD_PIN_MODE_GPIO_OUT,
+ UPBOARD_PIN_MODE_GPIO_IN,
+ UPBOARD_PIN_MODE_GPIO_OUT,
+ UPBOARD_PIN_MODE_GPIO_IN,
+};
+
+static_assert(ARRAY_SIZE(upboard_up2_uart1_modes) == ARRAY_SIZE(upboard_up2_uart1_pins));
+
+static const unsigned int upboard_up2_i2c0_pins[] = {
+ UPBOARD_UP2_BIT_TO_PIN(I2C0_SCL),
+ UPBOARD_UP2_BIT_TO_PIN(I2C0_SDA),
+ UPBOARD_UP2_BIT_TO_PIN(GPIO24),
+ UPBOARD_UP2_BIT_TO_PIN(GPIO10),
+};
+
+static const unsigned int upboard_up2_i2c1_pins[] = {
+ UPBOARD_UP2_BIT_TO_PIN(I2C1_SCL),
+ UPBOARD_UP2_BIT_TO_PIN(I2C1_SDA),
+ UPBOARD_UP2_BIT_TO_PIN(GPIO2),
+ UPBOARD_UP2_BIT_TO_PIN(GPIO1),
+};
+
+static const unsigned int upboard_up2_spi1_pins[] = {
+ UPBOARD_UP2_BIT_TO_PIN(SPI1_TXD),
+ UPBOARD_UP2_BIT_TO_PIN(SPI1_RXD),
+ UPBOARD_UP2_BIT_TO_PIN(SPI1_FS1),
+ UPBOARD_UP2_BIT_TO_PIN(SPI1_FS0),
+ UPBOARD_UP2_BIT_TO_PIN(SPI1_CLK),
+};
+
+static const unsigned int upboard_up2_spi2_pins[] = {
+ UPBOARD_UP2_BIT_TO_PIN(SPI2_TXD),
+ UPBOARD_UP2_BIT_TO_PIN(SPI2_RXD),
+ UPBOARD_UP2_BIT_TO_PIN(SPI2_FS1),
+ UPBOARD_UP2_BIT_TO_PIN(SPI2_FS0),
+ UPBOARD_UP2_BIT_TO_PIN(SPI2_CLK),
+};
+
+static const enum upboard_pin_mode upboard_up2_spi_modes[] = {
+ UPBOARD_PIN_MODE_GPIO_OUT,
+ UPBOARD_PIN_MODE_GPIO_IN,
+ UPBOARD_PIN_MODE_GPIO_OUT,
+ UPBOARD_PIN_MODE_GPIO_OUT,
+ UPBOARD_PIN_MODE_GPIO_OUT,
+};
+
+static_assert(ARRAY_SIZE(upboard_up2_spi_modes) == ARRAY_SIZE(upboard_up2_spi1_pins));
+
+static_assert(ARRAY_SIZE(upboard_up2_spi_modes) == ARRAY_SIZE(upboard_up2_spi2_pins));
+
+static const unsigned int upboard_up2_i2s0_pins[] = {
+ UPBOARD_UP2_BIT_TO_PIN(I2S_BCLK),
+ UPBOARD_UP2_BIT_TO_PIN(I2S_WS_SYNC),
+ UPBOARD_UP2_BIT_TO_PIN(I2S_SDI),
+ UPBOARD_UP2_BIT_TO_PIN(I2S_SDO),
+};
+
+static const enum upboard_pin_mode upboard_up2_i2s0_modes[] = {
+ UPBOARD_PIN_MODE_GPIO_OUT,
+ UPBOARD_PIN_MODE_GPIO_OUT,
+ UPBOARD_PIN_MODE_GPIO_IN,
+ UPBOARD_PIN_MODE_GPIO_OUT,
+};
+
+static_assert(ARRAY_SIZE(upboard_up2_i2s0_modes) == ARRAY_SIZE(upboard_up2_i2s0_pins));
+
+static const unsigned int upboard_up2_pwm0_pins[] = {
+ UPBOARD_UP2_BIT_TO_PIN(PWM0),
+};
+
+static const unsigned int upboard_up2_pwm1_pins[] = {
+ UPBOARD_UP2_BIT_TO_PIN(PWM1),
+};
+
+static const unsigned int upboard_up2_adc0_pins[] = {
+ UPBOARD_UP2_BIT_TO_PIN(GPIO3_ADC0),
+};
+
+static const unsigned int upboard_up2_adc2_pins[] = {
+ UPBOARD_UP2_BIT_TO_PIN(GPIO5_ADC2),
+};
+
+static const unsigned int upboard_up2_adc3_pins[] = {
+ UPBOARD_UP2_BIT_TO_PIN(GPIO6_ADC3),
+};
+
+static const struct upboard_pingroup upboard_up2_pin_groups[] = {
+ UPBOARD_PINGROUP("uart1_grp", upboard_up2_uart1_pins, &upboard_up2_uart1_modes[0]),
+ UPBOARD_PINGROUP("i2c0_grp", upboard_up2_i2c0_pins, UPBOARD_PIN_MODE_FUNCTION),
+ UPBOARD_PINGROUP("i2c1_grp", upboard_up2_i2c1_pins, UPBOARD_PIN_MODE_FUNCTION),
+ UPBOARD_PINGROUP("spi1_grp", upboard_up2_spi1_pins, &upboard_up2_spi_modes[0]),
+ UPBOARD_PINGROUP("spi2_grp", upboard_up2_spi2_pins, &upboard_up2_spi_modes[0]),
+ UPBOARD_PINGROUP("i2s0_grp", upboard_up2_i2s0_pins, &upboard_up2_i2s0_modes[0]),
+ UPBOARD_PINGROUP("pwm0_grp", upboard_up2_pwm0_pins, UPBOARD_PIN_MODE_GPIO_OUT),
+ UPBOARD_PINGROUP("pwm1_grp", upboard_up2_pwm1_pins, UPBOARD_PIN_MODE_GPIO_OUT),
+ UPBOARD_PINGROUP("adc0_grp", upboard_up2_adc0_pins, UPBOARD_PIN_MODE_GPIO_IN),
+ UPBOARD_PINGROUP("adc2_grp", upboard_up2_adc2_pins, UPBOARD_PIN_MODE_GPIO_IN),
+ UPBOARD_PINGROUP("adc3_grp", upboard_up2_adc3_pins, UPBOARD_PIN_MODE_GPIO_IN),
+};
+
+static const char * const upboard_up2_uart1_groups[] = { "uart1_grp" };
+static const char * const upboard_up2_i2c0_groups[] = { "i2c0_grp" };
+static const char * const upboard_up2_i2c1_groups[] = { "i2c1_grp" };
+static const char * const upboard_up2_spi1_groups[] = { "spi1_grp" };
+static const char * const upboard_up2_spi2_groups[] = { "spi2_grp" };
+static const char * const upboard_up2_i2s0_groups[] = { "i2s0_grp" };
+static const char * const upboard_up2_pwm0_groups[] = { "pwm0_grp" };
+static const char * const upboard_up2_pwm1_groups[] = { "pwm1_grp" };
+static const char * const upboard_up2_adc0_groups[] = { "adc0_grp" };
+static const char * const upboard_up2_adc2_groups[] = { "adc2_grp" };
+static const char * const upboard_up2_adc3_groups[] = { "adc3_grp" };
+
+static const struct pinfunction upboard_up2_pin_functions[] = {
+ UPBOARD_FUNCTION("uart1", upboard_up2_uart1_groups),
+ UPBOARD_FUNCTION("i2c0", upboard_up2_i2c0_groups),
+ UPBOARD_FUNCTION("i2c1", upboard_up2_i2c1_groups),
+ UPBOARD_FUNCTION("spi1", upboard_up2_spi1_groups),
+ UPBOARD_FUNCTION("spi2", upboard_up2_spi2_groups),
+ UPBOARD_FUNCTION("i2s0", upboard_up2_i2s0_groups),
+ UPBOARD_FUNCTION("pwm0", upboard_up2_pwm0_groups),
+ UPBOARD_FUNCTION("pwm1", upboard_up2_pwm1_groups),
+ UPBOARD_FUNCTION("adc0", upboard_up2_adc0_groups),
+ UPBOARD_FUNCTION("adc2", upboard_up2_adc2_groups),
+ UPBOARD_FUNCTION("adc3", upboard_up2_adc3_groups),
+};
+
+static const struct upboard_pinctrl_data upboard_up2_pinctrl_data = {
+ .groups = &upboard_up2_pin_groups[0],
+ .ngroups = ARRAY_SIZE(upboard_up2_pin_groups),
+ .funcs = &upboard_up2_pin_functions[0],
+ .nfuncs = ARRAY_SIZE(upboard_up2_pin_functions),
+ .pin_header = &upboard_up2_pin_header[0],
+ .ngpio = ARRAY_SIZE(upboard_up2_pin_header),
+};
+
+static int upboard_pinctrl_set_function(struct pinctrl_dev *pctldev, unsigned int offset)
+{
+ struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ struct upboard_pin *p = &pctrl->pins[offset];
+ int ret;
+
+ if (!p->funcbit)
+ return -EPERM;
+
+ ret = regmap_field_write(p->enbit, 0);
+ if (ret)
+ return ret;
+
+ return regmap_field_write(p->funcbit, 1);
+}
+
+static int upboard_pinctrl_gpio_commit_enable(struct pinctrl_dev *pctldev, unsigned int offset)
+{
+ struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ struct upboard_pin *p = &pctrl->pins[offset];
+ int ret;
+
+ if (p->funcbit) {
+ ret = regmap_field_write(p->funcbit, 0);
+ if (ret)
+ return ret;
+ }
+
+ return regmap_field_write(p->enbit, 1);
+}
+
+static int upboard_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int offset)
+{
+ return upboard_pinctrl_gpio_commit_enable(pctldev, offset);
+}
+
+static void upboard_pinctrl_gpio_commit_disable(struct pinctrl_dev *pctldev, unsigned int offset)
+{
+ struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ struct upboard_pin *p = &pctrl->pins[offset];
+
+ regmap_field_write(p->enbit, 0);
+};
+
+static void upboard_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned int offset)
+{
+ return upboard_pinctrl_gpio_commit_disable(pctldev, offset);
+}
+
+static int upboard_pinctrl_gpio_commit_direction(struct pinctrl_dev *pctldev, unsigned int offset,
+ bool input)
+{
+ struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ struct upboard_pin *p = &pctrl->pins[offset];
+
+ return regmap_field_write(p->dirbit, input);
+}
+
+static int upboard_pinctrl_gpio_set_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int offset, bool input)
+{
+ return upboard_pinctrl_gpio_commit_direction(pctldev, offset, input);
+}
+
+static int upboard_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector,
+ unsigned int group_selector)
+{
+ struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ const struct upboard_pinctrl_data *pctrl_data = pctrl->pctrl_data;
+ const struct upboard_pingroup *upgroups = pctrl_data->groups;
+ struct group_desc *grp;
+ unsigned int mode, i;
+ int ret;
+
+ grp = pinctrl_generic_get_group(pctldev, group_selector);
+ if (!grp)
+ return -EINVAL;
+
+ for (i = 0; i < grp->grp.npins; i++) {
+ mode = upgroups[group_selector].mode ?: upgroups[group_selector].modes[i];
+ if (mode == UPBOARD_PIN_MODE_FUNCTION) {
+ ret = upboard_pinctrl_set_function(pctldev, grp->grp.pins[i]);
+ if (ret)
+ return ret;
+
+ continue;
+ }
+
+ ret = upboard_pinctrl_gpio_commit_enable(pctldev, grp->grp.pins[i]);
+ if (ret)
+ return ret;
+
+ ret = upboard_pinctrl_gpio_commit_direction(pctldev, grp->grp.pins[i],
+ mode == UPBOARD_PIN_MODE_GPIO_IN);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct pinmux_ops upboard_pinmux_ops = {
+ .get_functions_count = pinmux_generic_get_function_count,
+ .get_function_name = pinmux_generic_get_function_name,
+ .get_function_groups = pinmux_generic_get_function_groups,
+ .set_mux = upboard_pinctrl_set_mux,
+ .gpio_request_enable = upboard_pinctrl_gpio_request_enable,
+ .gpio_disable_free = upboard_pinctrl_gpio_disable_free,
+ .gpio_set_direction = upboard_pinctrl_gpio_set_direction,
+};
+
+static int upboard_pinctrl_pin_get_mode(struct pinctrl_dev *pctldev, unsigned int pin)
+{
+ struct upboard_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ struct upboard_pin *p = &pctrl->pins[pin];
+ unsigned int val;
+ int ret;
+
+ if (p->funcbit) {
+ ret = regmap_field_read(p->funcbit, &val);
+ if (ret)
+ return ret;
+ if (val)
+ return UPBOARD_PIN_MODE_FUNCTION;
+ }
+
+ ret = regmap_field_read(p->enbit, &val);
+ if (ret)
+ return ret;
+ if (!val)
+ return UPBOARD_PIN_MODE_DISABLED;
+
+ ret = regmap_field_read(p->dirbit, &val);
+ if (ret)
+ return ret;
+
+ return val ? UPBOARD_PIN_MODE_GPIO_IN : UPBOARD_PIN_MODE_GPIO_OUT;
+}
+
+static void upboard_pinctrl_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned int offset)
+{
+ int ret;
+
+ ret = upboard_pinctrl_pin_get_mode(pctldev, offset);
+ if (ret == UPBOARD_PIN_MODE_FUNCTION)
+ seq_puts(s, "mode function ");
+ else if (ret == UPBOARD_PIN_MODE_DISABLED)
+ seq_puts(s, "HIGH-Z ");
+ else if (ret < 0)
+ seq_puts(s, "N/A ");
+ else
+ seq_printf(s, "GPIO (%s) ", str_input_output(ret == UPBOARD_PIN_MODE_GPIO_IN));
+}
+
+static const struct pinctrl_ops upboard_pinctrl_ops = {
+ .get_groups_count = pinctrl_generic_get_group_count,
+ .get_group_name = pinctrl_generic_get_group_name,
+ .get_group_pins = pinctrl_generic_get_group_pins,
+ .pin_dbg_show = upboard_pinctrl_dbg_show,
+};
+
+static int upboard_gpio_request(struct gpio_chip *gc, unsigned int offset)
+{
+ struct gpiochip_fwd *fwd = gpiochip_get_data(gc);
+ struct upboard_pinctrl *pctrl = gpiochip_fwd_get_data(fwd);
+ unsigned int pin = pctrl->pctrl_data->pin_header[offset];
+ struct gpio_desc *desc;
+ int ret;
+
+ ret = pinctrl_gpio_request(gc, offset);
+ if (ret)
+ return ret;
+
+ desc = gpiod_get_index(pctrl->dev, "external", pin, 0);
+ if (IS_ERR(desc)) {
+ pinctrl_gpio_free(gc, offset);
+ return PTR_ERR(desc);
+ }
+
+ return gpiochip_fwd_desc_add(fwd, desc, offset);
+}
+
+static void upboard_gpio_free(struct gpio_chip *gc, unsigned int offset)
+{
+ struct gpiochip_fwd *fwd = gpiochip_get_data(gc);
+
+ gpiochip_fwd_desc_free(fwd, offset);
+ pinctrl_gpio_free(gc, offset);
+}
+
+static int upboard_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ struct gpiochip_fwd *fwd = gpiochip_get_data(gc);
+ struct upboard_pinctrl *pctrl = gpiochip_fwd_get_data(fwd);
+ unsigned int pin = pctrl->pctrl_data->pin_header[offset];
+ int mode;
+
+ /* If the pin is in function mode or high-z, input direction is returned */
+ mode = upboard_pinctrl_pin_get_mode(pctrl->pctldev, pin);
+ if (mode < 0)
+ return mode;
+
+ if (mode == UPBOARD_PIN_MODE_GPIO_OUT)
+ return GPIO_LINE_DIRECTION_OUT;
+
+ return GPIO_LINE_DIRECTION_IN;
+}
+
+static int upboard_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
+{
+ struct gpiochip_fwd *fwd = gpiochip_get_data(gc);
+ int ret;
+
+ ret = pinctrl_gpio_direction_input(gc, offset);
+ if (ret)
+ return ret;
+
+ return gpiochip_fwd_gpio_direction_input(fwd, offset);
+}
+
+static int upboard_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int value)
+{
+ struct gpiochip_fwd *fwd = gpiochip_get_data(gc);
+ int ret;
+
+ ret = pinctrl_gpio_direction_output(gc, offset);
+ if (ret)
+ return ret;
+
+ return gpiochip_fwd_gpio_direction_output(fwd, offset, value);
+}
+
+static int upboard_pinctrl_register_groups(struct upboard_pinctrl *pctrl)
+{
+ const struct upboard_pingroup *groups = pctrl->pctrl_data->groups;
+ size_t ngroups = pctrl->pctrl_data->ngroups;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < ngroups; i++) {
+ ret = pinctrl_generic_add_group(pctrl->pctldev, groups[i].grp.name,
+ groups[i].grp.pins, groups[i].grp.npins, pctrl);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int upboard_pinctrl_register_functions(struct upboard_pinctrl *pctrl)
+{
+ const struct pinfunction *funcs = pctrl->pctrl_data->funcs;
+ size_t nfuncs = pctrl->pctrl_data->nfuncs;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < nfuncs ; i++) {
+ ret = pinmux_generic_add_function(pctrl->pctldev, funcs[i].name,
+ funcs[i].groups, funcs[i].ngroups, NULL);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct pinctrl_map pinctrl_map_apl01[] = {
+ PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:00", "pwm0_grp", "pwm0"),
+ PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:00", "pwm1_grp", "pwm1"),
+ PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:00", "uart1_grp", "uart1"),
+ PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:02", "i2c0_grp", "i2c0"),
+ PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:02", "i2c1_grp", "i2c1"),
+ PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INT3452:01", "ssp0_grp", "ssp0"),
+};
+
+static const struct upboard_pinctrl_map upboard_pinctrl_map_apl01 = {
+ .maps = &pinctrl_map_apl01[0],
+ .nmaps = ARRAY_SIZE(pinctrl_map_apl01),
+};
+
+static const struct dmi_system_id dmi_platform_info[] = {
+ {
+ /* UP Squared */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AAEON"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "UP-APL01"),
+ },
+ .driver_data = (void *)&upboard_pinctrl_map_apl01,
+ },
+ { }
+};
+
+static int upboard_pinctrl_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct upboard_fpga *fpga = dev_get_drvdata(dev->parent);
+ const struct upboard_pinctrl_map *board_map;
+ const struct dmi_system_id *dmi_id;
+ struct pinctrl_desc *pctldesc;
+ struct upboard_pinctrl *pctrl;
+ struct upboard_pin *pins;
+ struct gpiochip_fwd *fwd;
+ struct pinctrl *pinctrl;
+ struct gpio_chip *chip;
+ unsigned int i;
+ int ret;
+
+ pctldesc = devm_kzalloc(dev, sizeof(*pctldesc), GFP_KERNEL);
+ if (!pctldesc)
+ return -ENOMEM;
+
+ pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL);
+ if (!pctrl)
+ return -ENOMEM;
+
+ switch (fpga->fpga_data->type) {
+ case UPBOARD_UP_FPGA:
+ pctldesc->pins = upboard_up_pins;
+ pctldesc->npins = ARRAY_SIZE(upboard_up_pins);
+ pctrl->pctrl_data = &upboard_up_pinctrl_data;
+ break;
+ case UPBOARD_UP2_FPGA:
+ pctldesc->pins = upboard_up2_pins;
+ pctldesc->npins = ARRAY_SIZE(upboard_up2_pins);
+ pctrl->pctrl_data = &upboard_up2_pinctrl_data;
+ break;
+ default:
+ return dev_err_probe(dev, -ENODEV, "Unsupported device type %d\n",
+ fpga->fpga_data->type);
+ }
+
+ dmi_id = dmi_first_match(dmi_platform_info);
+ if (!dmi_id)
+ return dev_err_probe(dev, -ENODEV, "Unsupported board\n");
+
+ board_map = (const struct upboard_pinctrl_map *)dmi_id->driver_data;
+
+ pctldesc->name = dev_name(dev);
+ pctldesc->owner = THIS_MODULE;
+ pctldesc->pctlops = &upboard_pinctrl_ops;
+ pctldesc->pmxops = &upboard_pinmux_ops;
+
+ pctrl->dev = dev;
+
+ pins = devm_kcalloc(dev, pctldesc->npins, sizeof(*pins), GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ /* Initialize pins */
+ for (i = 0; i < pctldesc->npins; i++) {
+ const struct pinctrl_pin_desc *pin_desc = &pctldesc->pins[i];
+ unsigned int regoff = pin_desc->number / UPBOARD_REGISTER_SIZE;
+ unsigned int lsb = pin_desc->number % UPBOARD_REGISTER_SIZE;
+ struct reg_field * const fld_func = pin_desc->drv_data;
+ struct upboard_pin *pin = &pins[i];
+ struct reg_field fldconf = {};
+
+ if (fld_func) {
+ pin->funcbit = devm_regmap_field_alloc(dev, fpga->regmap, *fld_func);
+ if (IS_ERR(pin->funcbit))
+ return PTR_ERR(pin->funcbit);
+ }
+
+ fldconf.reg = UPBOARD_REG_GPIO_EN0 + regoff;
+ fldconf.lsb = lsb;
+ fldconf.msb = lsb;
+ pin->enbit = devm_regmap_field_alloc(dev, fpga->regmap, fldconf);
+ if (IS_ERR(pin->enbit))
+ return PTR_ERR(pin->enbit);
+
+ fldconf.reg = UPBOARD_REG_GPIO_DIR0 + regoff;
+ fldconf.lsb = lsb;
+ fldconf.msb = lsb;
+ pin->dirbit = devm_regmap_field_alloc(dev, fpga->regmap, fldconf);
+ if (IS_ERR(pin->dirbit))
+ return PTR_ERR(pin->dirbit);
+ }
+
+ pctrl->pins = pins;
+
+ ret = devm_pinctrl_register_and_init(dev, pctldesc, pctrl, &pctrl->pctldev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register pinctrl\n");
+
+ ret = upboard_pinctrl_register_groups(pctrl);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register groups\n");
+
+ ret = upboard_pinctrl_register_functions(pctrl);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register functions\n");
+
+ ret = devm_pinctrl_register_mappings(dev, board_map->maps, board_map->nmaps);
+ if (ret)
+ return ret;
+
+ pinctrl = devm_pinctrl_get_select_default(dev);
+ if (IS_ERR(pinctrl))
+ return dev_err_probe(dev, PTR_ERR(pinctrl), "Failed to select pinctrl\n");
+
+ ret = pinctrl_enable(pctrl->pctldev);
+ if (ret)
+ return ret;
+
+ fwd = devm_gpiochip_fwd_alloc(dev, pctrl->pctrl_data->ngpio);
+ if (IS_ERR(fwd))
+ return dev_err_probe(dev, PTR_ERR(fwd), "Failed to allocate the gpiochip forwarder\n");
+
+ chip = gpiochip_fwd_get_gpiochip(fwd);
+ chip->request = upboard_gpio_request;
+ chip->free = upboard_gpio_free;
+ chip->get_direction = upboard_gpio_get_direction;
+ chip->direction_output = upboard_gpio_direction_output;
+ chip->direction_input = upboard_gpio_direction_input;
+
+ ret = gpiochip_fwd_register(fwd, pctrl);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register the gpiochip forwarder\n");
+
+ return gpiochip_add_sparse_pin_range(chip, dev_name(dev), 0, pctrl->pctrl_data->pin_header,
+ pctrl->pctrl_data->ngpio);
+}
+
+static struct platform_driver upboard_pinctrl_driver = {
+ .driver = {
+ .name = "upboard-pinctrl",
+ },
+ .probe = upboard_pinctrl_probe,
+};
+module_platform_driver(upboard_pinctrl_driver);
+
+MODULE_AUTHOR("Thomas Richard <thomas.richard@bootlin.com");
+MODULE_DESCRIPTION("UP Board HAT pin controller driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:upboard-pinctrl");
+MODULE_IMPORT_NS("GPIO_FORWARDER");
--
2.39.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA
2025-06-11 9:00 [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Thomas Richard
` (9 preceding siblings ...)
2025-06-11 9:00 ` [PATCH v8 10/10] pinctrl: Add pin controller driver for AAEON UP boards Thomas Richard
@ 2025-06-25 8:26 ` Bartosz Golaszewski
2025-07-15 13:13 ` Thomas Richard
2025-08-11 9:25 ` Bartosz Golaszewski
11 siblings, 1 reply; 18+ messages in thread
From: Bartosz Golaszewski @ 2025-06-25 8:26 UTC (permalink / raw)
To: Thomas Richard
Cc: Linus Walleij, Andy Shevchenko, Geert Uytterhoeven, Kees Cook,
Andy Shevchenko, linux-gpio, linux-kernel, thomas.petazzoni,
DanieleCleri, GaryWang, linux-hardening
On Wed, Jun 11, 2025 at 11:00 AM Thomas Richard
<thomas.richard@bootlin.com> wrote:
>
> This is the eighth version of this series. I just added a missing header
> file in gpio-aggregator driver to fix a build warning reported by a kernel
> test robot [1].
>
> [1] https://lore.kernel.org/oe-kbuild-all/202506092324.XqSwWl1z-lkp@intel.com/
>
> Best Regards,
>
> Thomas
>
> Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
> ---
This series looks pretty good now, any objections to picking it up? As
usual - I can take the GPIO patches and provide an immutable branch
for Linus to pull.
Bartosz
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA
2025-06-25 8:26 ` [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Bartosz Golaszewski
@ 2025-07-15 13:13 ` Thomas Richard
2025-07-15 13:17 ` Bartosz Golaszewski
0 siblings, 1 reply; 18+ messages in thread
From: Thomas Richard @ 2025-07-15 13:13 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Linus Walleij, Andy Shevchenko, Geert Uytterhoeven, Kees Cook,
Andy Shevchenko, linux-gpio, linux-kernel, thomas.petazzoni,
DanieleCleri, GaryWang, linux-hardening
On 6/25/25 10:26 AM, Bartosz Golaszewski wrote:
> On Wed, Jun 11, 2025 at 11:00 AM Thomas Richard
> <thomas.richard@bootlin.com> wrote:
>>
>> This is the eighth version of this series. I just added a missing header
>> file in gpio-aggregator driver to fix a build warning reported by a kernel
>> test robot [1].
>>
>> [1] https://lore.kernel.org/oe-kbuild-all/202506092324.XqSwWl1z-lkp@intel.com/
>>
>> Best Regards,
>>
>> Thomas
>>
>> Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
>> ---
>
> This series looks pretty good now, any objections to picking it up? As
> usual - I can take the GPIO patches and provide an immutable branch
> for Linus to pull.
Hi Bartosz,
When do you plan to pick the patches? Will it be ok for next merge window?
Best Regards,
Thomas
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA
2025-07-15 13:13 ` Thomas Richard
@ 2025-07-15 13:17 ` Bartosz Golaszewski
2025-07-23 8:43 ` Bartosz Golaszewski
0 siblings, 1 reply; 18+ messages in thread
From: Bartosz Golaszewski @ 2025-07-15 13:17 UTC (permalink / raw)
To: Thomas Richard
Cc: Linus Walleij, Andy Shevchenko, Geert Uytterhoeven, Kees Cook,
Andy Shevchenko, linux-gpio, linux-kernel, thomas.petazzoni,
DanieleCleri, GaryWang, linux-hardening
On Tue, Jul 15, 2025 at 3:13 PM Thomas Richard
<thomas.richard@bootlin.com> wrote:
>
> On 6/25/25 10:26 AM, Bartosz Golaszewski wrote:
> > On Wed, Jun 11, 2025 at 11:00 AM Thomas Richard
> > <thomas.richard@bootlin.com> wrote:
> >>
> >> This is the eighth version of this series. I just added a missing header
> >> file in gpio-aggregator driver to fix a build warning reported by a kernel
> >> test robot [1].
> >>
> >> [1] https://lore.kernel.org/oe-kbuild-all/202506092324.XqSwWl1z-lkp@intel.com/
> >>
> >> Best Regards,
> >>
> >> Thomas
> >>
> >> Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
> >> ---
> >
> > This series looks pretty good now, any objections to picking it up? As
> > usual - I can take the GPIO patches and provide an immutable branch
> > for Linus to pull.
>
> Hi Bartosz,
>
> When do you plan to pick the patches? Will it be ok for next merge window?
>
Well, nobody responded to my last email. This is a cross-tree series
so at least Linus must confirm he's ok.
Bart
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA
2025-07-15 13:17 ` Bartosz Golaszewski
@ 2025-07-23 8:43 ` Bartosz Golaszewski
2025-07-26 14:17 ` Linus Walleij
0 siblings, 1 reply; 18+ messages in thread
From: Bartosz Golaszewski @ 2025-07-23 8:43 UTC (permalink / raw)
To: Thomas Richard
Cc: Linus Walleij, Andy Shevchenko, Geert Uytterhoeven, Kees Cook,
Andy Shevchenko, linux-gpio, linux-kernel, thomas.petazzoni,
DanieleCleri, GaryWang, linux-hardening
On Tue, Jul 15, 2025 at 3:17 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> On Tue, Jul 15, 2025 at 3:13 PM Thomas Richard
> <thomas.richard@bootlin.com> wrote:
> >
> > On 6/25/25 10:26 AM, Bartosz Golaszewski wrote:
> > > On Wed, Jun 11, 2025 at 11:00 AM Thomas Richard
> > > <thomas.richard@bootlin.com> wrote:
> > >>
> > >> This is the eighth version of this series. I just added a missing header
> > >> file in gpio-aggregator driver to fix a build warning reported by a kernel
> > >> test robot [1].
> > >>
> > >> [1] https://lore.kernel.org/oe-kbuild-all/202506092324.XqSwWl1z-lkp@intel.com/
> > >>
> > >> Best Regards,
> > >>
> > >> Thomas
> > >>
> > >> Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
> > >> ---
> > >
> > > This series looks pretty good now, any objections to picking it up? As
> > > usual - I can take the GPIO patches and provide an immutable branch
> > > for Linus to pull.
> >
> > Hi Bartosz,
> >
> > When do you plan to pick the patches? Will it be ok for next merge window?
> >
>
> Well, nobody responded to my last email. This is a cross-tree series
> so at least Linus must confirm he's ok.
>
> Bart
Linus, I'm willing to queue at least the GPIO part for v6.17, does the
pinctrl part look good to you?
Bart
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA
2025-07-23 8:43 ` Bartosz Golaszewski
@ 2025-07-26 14:17 ` Linus Walleij
2025-07-29 8:03 ` Bartosz Golaszewski
0 siblings, 1 reply; 18+ messages in thread
From: Linus Walleij @ 2025-07-26 14:17 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Thomas Richard, Andy Shevchenko, Geert Uytterhoeven, Kees Cook,
Andy Shevchenko, linux-gpio, linux-kernel, thomas.petazzoni,
DanieleCleri, GaryWang, linux-hardening
On Wed, Jul 23, 2025 at 10:43 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> On Tue, Jul 15, 2025 at 3:17 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> > Well, nobody responded to my last email. This is a cross-tree series
> > so at least Linus must confirm he's ok.
> >
> > Bart
>
> Linus, I'm willing to queue at least the GPIO part for v6.17, does the
> pinctrl part look good to you?
Yes go ahead, sorry for late reply!
Acked-by: Linus Walleij <linus.walleij@linaro.org>
I was mainly waiting for Andy's review on this, so if Andy
is OK, I'm OK with it.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA
2025-07-26 14:17 ` Linus Walleij
@ 2025-07-29 8:03 ` Bartosz Golaszewski
0 siblings, 0 replies; 18+ messages in thread
From: Bartosz Golaszewski @ 2025-07-29 8:03 UTC (permalink / raw)
To: Linus Walleij
Cc: Thomas Richard, Andy Shevchenko, Geert Uytterhoeven, Kees Cook,
Andy Shevchenko, linux-gpio, linux-kernel, thomas.petazzoni,
DanieleCleri, GaryWang, linux-hardening
On Sat, Jul 26, 2025 at 4:17 PM Linus Walleij <linus.walleij@linaro.org> wrote:
>
> On Wed, Jul 23, 2025 at 10:43 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> > On Tue, Jul 15, 2025 at 3:17 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> > > Well, nobody responded to my last email. This is a cross-tree series
> > > so at least Linus must confirm he's ok.
> > >
> > > Bart
> >
> > Linus, I'm willing to queue at least the GPIO part for v6.17, does the
> > pinctrl part look good to you?
>
> Yes go ahead, sorry for late reply!
> Acked-by: Linus Walleij <linus.walleij@linaro.org>
>
> I was mainly waiting for Andy's review on this, so if Andy
> is OK, I'm OK with it.
>
Ah, I already sent my big PR for this cycle. :( Let's pick it up early
after rc1 and I'll prepare for you an immutable branch.
Bartosz
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA
2025-06-11 9:00 [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Thomas Richard
` (10 preceding siblings ...)
2025-06-25 8:26 ` [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Bartosz Golaszewski
@ 2025-08-11 9:25 ` Bartosz Golaszewski
11 siblings, 0 replies; 18+ messages in thread
From: Bartosz Golaszewski @ 2025-08-11 9:25 UTC (permalink / raw)
To: Thomas Richard
Cc: Linus Walleij, Andy Shevchenko, Geert Uytterhoeven, Kees Cook,
Andy Shevchenko, linux-gpio, linux-kernel, thomas.petazzoni,
DanieleCleri, GaryWang, linux-hardening
On Wed, Jun 11, 2025 at 11:00 AM Thomas Richard
<thomas.richard@bootlin.com> wrote:
>
> This is the eighth version of this series. I just added a missing header
> file in gpio-aggregator driver to fix a build warning reported by a kernel
> test robot [1].
>
> [1] https://lore.kernel.org/oe-kbuild-all/202506092324.XqSwWl1z-lkp@intel.com/
>
> Best Regards,
>
> Thomas
>
> Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
> ---
Thomas,
Can you please rebase on top of v6.17-rc1 and resend? I will pick up
patches 1-9 and provide an immutable branch for Linus to take the
pinctrl patch.
Bart
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2025-08-11 9:25 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-11 9:00 [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Thomas Richard
2025-06-11 9:00 ` [PATCH v8 01/10] gpiolib: add support to register sparse pin range Thomas Richard
2025-06-11 9:00 ` [PATCH v8 02/10] gpio: aggregator: move GPIO forwarder allocation in a dedicated function Thomas Richard
2025-06-11 9:00 ` [PATCH v8 03/10] gpio: aggregator: refactor the code to add GPIO desc in the forwarder Thomas Richard
2025-06-11 9:00 ` [PATCH v8 04/10] gpio: aggregator: refactor the forwarder registration part Thomas Richard
2025-06-11 9:00 ` [PATCH v8 05/10] gpio: aggregator: update gpiochip_fwd_setup_delay_line() parameters Thomas Richard
2025-06-11 9:00 ` [PATCH v8 06/10] gpio: aggregator: export symbols of the GPIO forwarder library Thomas Richard
2025-06-11 9:00 ` [PATCH v8 07/10] gpio: aggregator: handle runtime registration of gpio_desc in gpiochip_fwd Thomas Richard
2025-06-11 9:00 ` [PATCH v8 08/10] gpio: aggregator: add possibility to attach data to the forwarder Thomas Richard
2025-06-11 9:00 ` [PATCH v8 09/10] lib/string_choices: Add str_input_output() helper Thomas Richard
2025-06-11 9:00 ` [PATCH v8 10/10] pinctrl: Add pin controller driver for AAEON UP boards Thomas Richard
2025-06-25 8:26 ` [PATCH v8 00/10] Add pinctrl support for the AAEON UP board FPGA Bartosz Golaszewski
2025-07-15 13:13 ` Thomas Richard
2025-07-15 13:17 ` Bartosz Golaszewski
2025-07-23 8:43 ` Bartosz Golaszewski
2025-07-26 14:17 ` Linus Walleij
2025-07-29 8:03 ` Bartosz Golaszewski
2025-08-11 9:25 ` Bartosz Golaszewski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).