[rtems commit] bsp/imx: Add a GPIO driver

Christian Mauderer christianm at rtems.org
Fri Jul 31 06:27:42 UTC 2020


Module:    rtems
Branch:    master
Commit:    0f4b911c0183fa11e68cd258444e3dd11fe0500e
Changeset: http://git.rtems.org/rtems/commit/?id=0f4b911c0183fa11e68cd258444e3dd11fe0500e

Author:    Christian Mauderer <christian.mauderer at embedded-brains.de>
Date:      Fri Jul 17 07:54:43 2020 +0200

bsp/imx: Add a GPIO driver

Update 3869

---

 bsps/arm/imx/gpio/imx-gpio.c         | 359 +++++++++++++++++++++++++++++++++++
 bsps/arm/imx/headers.am              |   1 +
 bsps/arm/imx/include/bsp/imx-gpio.h  | 196 +++++++++++++++++++
 bsps/arm/imx/include/bsp/irq.h       |   1 +
 bsps/arm/imx/start/bspstart.c        |   2 +-
 bsps/include/bsp/fatal.h             |   1 +
 c/src/lib/libbsp/arm/imx/Makefile.am |   3 +
 7 files changed, 562 insertions(+), 1 deletion(-)

diff --git a/bsps/arm/imx/gpio/imx-gpio.c b/bsps/arm/imx/gpio/imx-gpio.c
new file mode 100644
index 0000000..552e1d5
--- /dev/null
+++ b/bsps/arm/imx/gpio/imx-gpio.c
@@ -0,0 +1,359 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (C) 2019-2020 embedded brains GmbH.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <bsp/fatal.h>
+#include <bsp/fdt.h>
+#include <bsp/imx-gpio.h>
+#include <libfdt.h>
+#include <rtems.h>
+#include <rtems/sysinit.h>
+
+#define IMX_GPIO_ALIAS_NAME "gpioX"
+
+/*
+ * i.MX6ULL has 5, i.MX7D has 7
+ *
+ * Be careful when changing this. The attach() does a simple ASCII conversion.
+ */
+#define IMX_MAX_GPIO_MODULES 7
+
+struct imx_gpio_regs {
+  uint32_t dr;
+  uint32_t gdir;
+  uint32_t psr;
+  uint32_t icr1;
+#define IMX_GPIO_ICR_LOW_LEVEL 0
+#define IMX_GPIO_ICR_HIGH_LEVEL 1
+#define IMX_GPIO_ICR_RISING_EDGE 2
+#define IMX_GPIO_ICR_FALLING_EDGE 3
+  uint32_t icr2;
+  uint32_t imr;
+  uint32_t isr;
+  uint32_t edge_sel;
+};
+
+struct imx_gpio {
+  char name[sizeof(IMX_GPIO_ALIAS_NAME)];
+  struct imx_gpio_regs *regs;
+  rtems_interrupt_lock lock;
+};
+
+/* The GPIO modules. These will be initialized based on the FDT alias table. */
+struct imx_gpio imx_gpio[IMX_MAX_GPIO_MODULES];
+
+const char *imx_gpio_get_name(struct imx_gpio *imx_gpio)
+{
+  return imx_gpio->name;
+}
+
+static void imx_gpio_attach(void)
+{
+  size_t i;
+  const void *fdt;
+
+  fdt = bsp_fdt_get();
+
+  memset(imx_gpio, 0, sizeof(imx_gpio));
+
+  for (i = 0; i < IMX_MAX_GPIO_MODULES; ++i) {
+    const char *path;
+    int node;
+    const uint32_t *val;
+    uint32_t gpio_regs = 0;
+    int len;
+
+    memcpy(imx_gpio[i].name, IMX_GPIO_ALIAS_NAME, sizeof(IMX_GPIO_ALIAS_NAME));
+    imx_gpio[i].name[sizeof(IMX_GPIO_ALIAS_NAME)-2] = (char)('0' + i);
+
+    path = fdt_get_alias(fdt, imx_gpio[i].name);
+    if (path == NULL) {
+      continue;
+    }
+
+    node = fdt_path_offset(fdt, path);
+    if (node < 0) {
+      bsp_fatal(IMX_FATAL_GPIO_UNEXPECTED_FDT);
+    }
+
+    val = fdt_getprop(fdt, node, "reg", &len);
+    if (len > 0) {
+      gpio_regs = fdt32_to_cpu(val[0]);
+    } else {
+      bsp_fatal(IMX_FATAL_GPIO_UNEXPECTED_FDT);
+    }
+
+    imx_gpio[i].regs = (struct imx_gpio_regs *)gpio_regs;
+    rtems_interrupt_lock_initialize(&imx_gpio[i].lock, imx_gpio[i].name);
+  }
+}
+
+struct imx_gpio *imx_gpio_get_by_index(unsigned idx)
+{
+  if ((idx < IMX_MAX_GPIO_MODULES) && (imx_gpio[idx].regs != NULL)) {
+    return &imx_gpio[idx];
+  }
+  return NULL;
+}
+
+struct imx_gpio *imx_gpio_get_by_register(void *regs)
+{
+  size_t i;
+
+  for (i = 0; i < IMX_MAX_GPIO_MODULES; ++i) {
+    if (imx_gpio[i].regs == regs) {
+      return &imx_gpio[i];
+    }
+  }
+  return NULL;
+}
+
+static void imx_gpio_direction_input(struct imx_gpio_pin *pin)
+{
+  rtems_interrupt_lock_context lock_context;
+  rtems_interrupt_lock_acquire(&pin->gpio->lock, &lock_context);
+  pin->gpio->regs->gdir &= ~pin->mask;
+  rtems_interrupt_lock_release(&pin->gpio->lock, &lock_context);
+}
+
+static void imx_gpio_direction_output(struct imx_gpio_pin *pin)
+{
+  rtems_interrupt_lock_context lock_context;
+  rtems_interrupt_lock_acquire(&pin->gpio->lock, &lock_context);
+  pin->gpio->regs->gdir |= pin->mask;
+  rtems_interrupt_lock_release(&pin->gpio->lock, &lock_context);
+}
+
+static void imx_gpio_set_interrupt_any_edge(struct imx_gpio_pin *pin)
+{
+  rtems_interrupt_lock_context lock_context;
+  rtems_interrupt_lock_acquire(&pin->gpio->lock, &lock_context);
+  pin->gpio->regs->edge_sel |= pin->mask;
+  rtems_interrupt_lock_release(&pin->gpio->lock, &lock_context);
+}
+
+static void imx_gpio_set_interrupt_mode(struct imx_gpio_pin *pin, uint32_t mode)
+{
+  size_t i;
+
+  for (i=0; i < 32; ++i) {
+    if ((pin->mask & (1u << i)) != 0) {
+      volatile uint32_t *icr;
+      size_t shift;
+      rtems_interrupt_lock_context lock_context;
+
+      if (i < 16) {
+        icr = &pin->gpio->regs->icr1;
+        shift = 2 * i;
+      } else {
+        icr = &pin->gpio->regs->icr2;
+        shift = 2 * (i - 16);
+      }
+
+      rtems_interrupt_lock_acquire(&pin->gpio->lock, &lock_context);
+      *icr = (*icr & ~(3u << shift)) | (mode << shift);
+      rtems_interrupt_lock_release(&pin->gpio->lock, &lock_context);
+    }
+  }
+}
+
+rtems_status_code imx_gpio_init_from_fdt_property (
+  struct imx_gpio_pin *pin,
+  int node_offset,
+  const char *property,
+  enum imx_gpio_mode mode,
+  size_t index
+)
+{
+  int len;
+  const uint32_t *val;
+  rtems_status_code sc = RTEMS_SUCCESSFUL;
+  const void *fdt;
+  uint32_t gpio_regs;
+  const unsigned pin_length_dwords = 3;
+  const unsigned pin_length_bytes = (pin_length_dwords * sizeof(uint32_t));
+  uint32_t gpio_phandle;
+  uint32_t pin_nr;
+  int cfgnode;
+
+  memset(pin, 0, sizeof(*pin));
+
+  fdt = bsp_fdt_get();
+  val = fdt_getprop(fdt, node_offset, property, &len);
+  if (val == NULL || (len % pin_length_bytes != 0) ||
+      (index >= len / pin_length_bytes)) {
+    sc = RTEMS_UNSATISFIED;
+  }
+  if (sc == RTEMS_SUCCESSFUL) {
+    pin_nr = fdt32_to_cpu(val[1 + index * pin_length_dwords]);
+    gpio_phandle = fdt32_to_cpu(val[0 + index * pin_length_dwords]);
+
+    cfgnode = fdt_node_offset_by_phandle(fdt, gpio_phandle);
+    val = fdt_getprop(fdt, cfgnode, "reg", &len);
+    if (len > 0) {
+      gpio_regs = fdt32_to_cpu(val[0]);
+    } else {
+      sc = RTEMS_UNSATISFIED;
+    }
+  }
+  if (sc == RTEMS_SUCCESSFUL) {
+    pin->gpio = imx_gpio_get_by_register((void *)gpio_regs);
+    pin->mask = 1u << pin_nr;
+    pin->shift = pin_nr;
+    pin->mode = mode;
+  }
+  if (sc == RTEMS_SUCCESSFUL) {
+    imx_gpio_init(pin);
+  }
+
+  return sc;
+}
+
+rtems_vector_number imx_gpio_get_irq_of_node(
+  const void *fdt,
+  int node,
+  size_t index
+)
+{
+  const uint32_t *val;
+  uint32_t pin;
+  int parent;
+  size_t parent_index;
+  int len;
+
+  val = fdt_getprop(fdt, node, "interrupts", &len);
+  if (val == NULL || len < (int) ((index + 1) * 8)) {
+    return UINT32_MAX;
+  }
+  pin = fdt32_to_cpu(val[index * 2]);
+  if (pin < 16) {
+    parent_index = 0;
+  } else {
+    parent_index = 1;
+  }
+
+  val = fdt_getprop(fdt, node, "interrupt-parent", &len);
+  if (len != 4) {
+    return UINT32_MAX;
+  }
+  parent = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(val[0]));
+
+  return imx_get_irq_of_node(fdt, parent, parent_index);
+}
+
+void imx_gpio_init (struct imx_gpio_pin *pin)
+{
+  switch (pin->mode) {
+  case (IMX_GPIO_MODE_INTERRUPT_LOW):
+    imx_gpio_direction_input(pin);
+    imx_gpio_set_interrupt_mode(pin, IMX_GPIO_ICR_LOW_LEVEL);
+    break;
+  case (IMX_GPIO_MODE_INTERRUPT_HIGH):
+    imx_gpio_direction_input(pin);
+    imx_gpio_set_interrupt_mode(pin, IMX_GPIO_ICR_HIGH_LEVEL);
+    break;
+  case (IMX_GPIO_MODE_INTERRUPT_RISING):
+    imx_gpio_direction_input(pin);
+    imx_gpio_set_interrupt_mode(pin, IMX_GPIO_ICR_RISING_EDGE);
+    break;
+  case (IMX_GPIO_MODE_INTERRUPT_FALLING):
+    imx_gpio_direction_input(pin);
+    imx_gpio_set_interrupt_mode(pin, IMX_GPIO_ICR_FALLING_EDGE);
+    break;
+  case (IMX_GPIO_MODE_INTERRUPT_ANY_EDGE):
+    imx_gpio_direction_input(pin);
+    imx_gpio_set_interrupt_any_edge(pin);
+    /* Interrupt mode isn't really relevant here. Just set it to get
+     * a defined behaviour in case of a bug. */
+    imx_gpio_set_interrupt_mode(pin, IMX_GPIO_ICR_FALLING_EDGE);
+    break;
+  case (IMX_GPIO_MODE_INPUT):
+    imx_gpio_direction_input(pin);
+    break;
+  case (IMX_GPIO_MODE_OUTPUT):
+    imx_gpio_direction_output(pin);
+    break;
+  default:
+    assert(false);
+    break;
+  }
+}
+
+void imx_gpio_set_output(struct imx_gpio_pin *pin, uint32_t set)
+{
+  rtems_interrupt_lock_context lock_context;
+  set <<= pin->shift;
+  set &= pin->mask;
+  rtems_interrupt_lock_acquire(&pin->gpio->lock, &lock_context);
+  pin->gpio->regs->dr = (pin->gpio->regs->dr & ~pin->mask) | set;
+  rtems_interrupt_lock_release(&pin->gpio->lock, &lock_context);
+}
+
+void imx_gpio_toggle_output(struct imx_gpio_pin *pin)
+{
+  rtems_interrupt_lock_context lock_context;
+  rtems_interrupt_lock_acquire(&pin->gpio->lock, &lock_context);
+  pin->gpio->regs->dr = (pin->gpio->regs->dr ^ pin->mask);
+  rtems_interrupt_lock_release(&pin->gpio->lock, &lock_context);
+}
+
+uint32_t imx_gpio_get_input(struct imx_gpio_pin *pin)
+{
+  return (pin->gpio->regs->dr & pin->mask) >> pin->shift;
+}
+
+void imx_gpio_int_disable(struct imx_gpio_pin *pin)
+{
+  rtems_interrupt_lock_context lock_context;
+  rtems_interrupt_lock_acquire(&pin->gpio->lock, &lock_context);
+  pin->gpio->regs->imr &= ~pin->mask;
+  rtems_interrupt_lock_release(&pin->gpio->lock, &lock_context);
+}
+
+void imx_gpio_int_enable(struct imx_gpio_pin *pin)
+{
+  rtems_interrupt_lock_context lock_context;
+  rtems_interrupt_lock_acquire(&pin->gpio->lock, &lock_context);
+  pin->gpio->regs->imr |= pin->mask;
+  rtems_interrupt_lock_release(&pin->gpio->lock, &lock_context);
+}
+
+uint32_t imx_gpio_get_isr(struct imx_gpio_pin *pin)
+{
+  return (pin->gpio->regs->isr & pin->mask) >> pin->shift;
+}
+
+void imx_gpio_clear_isr(struct imx_gpio_pin *pin, uint32_t clr)
+{
+  pin->gpio->regs->isr = (clr << pin->shift) & pin->mask;
+}
+
+RTEMS_SYSINIT_ITEM(
+  imx_gpio_attach,
+  RTEMS_SYSINIT_DEVICE_DRIVERS,
+  RTEMS_SYSINIT_ORDER_FIRST
+);
diff --git a/bsps/arm/imx/headers.am b/bsps/arm/imx/headers.am
index dd18164..3a093b1 100644
--- a/bsps/arm/imx/headers.am
+++ b/bsps/arm/imx/headers.am
@@ -19,4 +19,5 @@ include_arm_freescale_imx_HEADERS += ../../../../../../bsps/arm/imx/include/arm/
 
 include_bspdir = $(includedir)/bsp
 include_bsp_HEADERS =
+include_bsp_HEADERS += ../../../../../../bsps/arm/imx/include/bsp/imx-gpio.h
 include_bsp_HEADERS += ../../../../../../bsps/arm/imx/include/bsp/irq.h
diff --git a/bsps/arm/imx/include/bsp/imx-gpio.h b/bsps/arm/imx/include/bsp/imx-gpio.h
new file mode 100644
index 0000000..dca2d0c
--- /dev/null
+++ b/bsps/arm/imx/include/bsp/imx-gpio.h
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BSP_IMX_GPIO_H
+#define BSP_IMX_GPIO_H
+
+#include <rtems.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** Hardware registers and locking mechanism for one hardware GPIO module. */
+struct imx_gpio;
+
+/** Mode of the pin. */
+enum imx_gpio_mode {
+  IMX_GPIO_MODE_OUTPUT,
+  IMX_GPIO_MODE_INPUT,
+  IMX_GPIO_MODE_INTERRUPT_LOW,
+  IMX_GPIO_MODE_INTERRUPT_HIGH,
+  IMX_GPIO_MODE_INTERRUPT_RISING,
+  IMX_GPIO_MODE_INTERRUPT_FALLING,
+  IMX_GPIO_MODE_INTERRUPT_ANY_EDGE,
+};
+
+/**
+ * A i.MX GPIO pin or set of pins.
+ *
+ * Use this structures to handle pins in the application. You can either get
+ * them from an FDT entry (with @ref imx_gpio_init_from_fde_property) or fill
+ * them by hand.
+ */
+struct imx_gpio_pin {
+  /** Management structure for the GPIO. Get with @ref imx_gpio_get_by_index. */
+  volatile struct imx_gpio* gpio;
+  /**
+   * Select the pins you want to handle with this mask. The mask is not
+   * influenced by the @a shift field.
+   */
+  uint32_t mask;
+  /** If set to something != 0: Shift the pins that many bits. */
+  unsigned int shift;
+  /** Whether the pin is an input, output, interrupt, ... */
+  enum imx_gpio_mode mode;
+};
+
+/**
+ * Initialize a GPIO pin. Only necessary for manually filled imx_gpio
+ * structures.
+ */
+void imx_gpio_init (struct imx_gpio_pin *pin);
+
+/**
+ * Initialize a GPIO pin from a FDT property.
+ *
+ * If you have for example the following property in an FDT node:
+ *
+ *     some-node {
+ *         gpios = <&gpio5 1 GPIO_ACTIVE_LOW>, <&gpio4 22 GPIO_ACTIVE_LOW>;
+ *     };
+ *
+ * you can use the following to initialize the second GPIO:
+ *
+ *     imx_gpio_init_from_fdt_property(&pin, node, "gpios",
+ *         IMX_GPIO_INTERRUPT_LOW, 1);
+ *
+ * NOTE: The information from the third parameter in the FDT (GPIO_ACTIVE_LOW in
+ * the example) is currently ignored.
+ */
+rtems_status_code imx_gpio_init_from_fdt_property(
+  struct imx_gpio_pin *pin,
+  int node_offset,
+  const char *property,
+  enum imx_gpio_mode mode,
+  size_t index);
+
+/**
+ * Return the RTEMS interrupt vector belonging to the GPIO interrupt of a given
+ * node. The node should look like follows:
+ *
+ *     some-node {
+ *         interrupt-parent = <&gpio4>;
+ *         interrupts = <15 IRQ_TYPE_EDGE_BOTH>, <22 IRQ_TYPE_EDGE_BOTH>;
+ *     };
+ *
+ * To get the interrupt vector from the first GPIO in interrupts use
+ *
+ *     imx_gpio_get_irq_of_node(fdt, node, 0);
+ *
+ * @returns the interrupt vector if successful.
+ * @returns BSP_INTERRUPT_VECTOR_INVALID on failure.
+ */
+rtems_vector_number imx_gpio_get_irq_of_node(
+  const void *fdt,
+  int node,
+  size_t index);
+
+/**
+ * Return the gpio management structure based on the GPIO index. The index is
+ * the one used in the FDT alias list. So index 0 is GPIO1 in the i.MX docs for
+ * most FDTs based on the Linux one.
+ */
+struct imx_gpio *imx_gpio_get_by_index(unsigned idx);
+
+/**
+ * Return the gpio management structure based on the GPIO registers.
+ */
+struct imx_gpio *imx_gpio_get_by_register(void *regs);
+
+/**
+ * Get the name of the gpio.
+ */
+const char *imx_gpio_get_name(struct imx_gpio *imx_gpio);
+
+/**
+ * Set the value of the output pin. @a set will be shifted and masked (in that
+ * order) based on the values of @a pin.
+ */
+void imx_gpio_set_output(struct imx_gpio_pin *pin, uint32_t set);
+
+/**
+ * Toggle the value of the output pin.
+ */
+void imx_gpio_toggle_output(struct imx_gpio_pin *pin);
+
+/**
+ * Get the value of the input pin. The input value will be masked and shifted
+ * (in that order) based on the values of @a pin.
+ */
+uint32_t imx_gpio_get_input(struct imx_gpio_pin *pin);
+
+/**
+ * Disable the interrupt of the given @a pin.
+ */
+void imx_gpio_int_disable(struct imx_gpio_pin *pin);
+
+/**
+ * Enable the interrupt of the given @a pin.
+ */
+void imx_gpio_int_enable(struct imx_gpio_pin *pin);
+
+/**
+ * Read the interrupt status register for the given @a pin.
+ */
+uint32_t imx_gpio_get_isr(struct imx_gpio_pin *pin);
+
+/**
+ * Clear the interrupt status register for the given @a pin.
+ */
+void imx_gpio_clear_isr(struct imx_gpio_pin *pin, uint32_t clr);
+
+/**
+ * Fast access macros for the GPIOs. Note that these assume a FDT based on the
+ * Linux FDTs.
+ */
+/** @{ */
+#define IMX_GPIO1 (imx_gpio_get_by_index(0))
+#define IMX_GPIO2 (imx_gpio_get_by_index(1))
+#define IMX_GPIO3 (imx_gpio_get_by_index(2))
+#define IMX_GPIO4 (imx_gpio_get_by_index(3))
+#define IMX_GPIO5 (imx_gpio_get_by_index(4))
+#define IMX_GPIO6 (imx_gpio_get_by_index(5))
+#define IMX_GPIO7 (imx_gpio_get_by_index(6))
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* BSP_IMX_GPIO_H */
diff --git a/bsps/arm/imx/include/bsp/irq.h b/bsps/arm/imx/include/bsp/irq.h
index 73d2e69..78b48e1 100644
--- a/bsps/arm/imx/include/bsp/irq.h
+++ b/bsps/arm/imx/include/bsp/irq.h
@@ -28,6 +28,7 @@ extern "C" {
 
 #define BSP_INTERRUPT_VECTOR_MIN 0
 #define BSP_INTERRUPT_VECTOR_MAX 159
+#define BSP_INTERRUPT_VECTOR_INVALID (UINT32_MAX)
 
 #ifdef __cplusplus
 }
diff --git a/bsps/arm/imx/start/bspstart.c b/bsps/arm/imx/start/bspstart.c
index 36f6299..5fb07bf 100644
--- a/bsps/arm/imx/start/bspstart.c
+++ b/bsps/arm/imx/start/bspstart.c
@@ -47,7 +47,7 @@ rtems_vector_number imx_get_irq_of_node(
 
   val = fdt_getprop(fdt, node, "interrupts", &len);
   if (val == NULL || len < (int) ((index + 1) * 12)) {
-    return UINT32_MAX;
+    return BSP_INTERRUPT_VECTOR_INVALID;
   }
 
   return fdt32_to_cpu(val[index * 3 + 1]) + MAGIC_IRQ_OFFSET;
diff --git a/bsps/include/bsp/fatal.h b/bsps/include/bsp/fatal.h
index 3f8e1eb..f95290b 100644
--- a/bsps/include/bsp/fatal.h
+++ b/bsps/include/bsp/fatal.h
@@ -138,6 +138,7 @@ typedef enum {
 
   /* i.MX fatal codes */
   IMX_FATAL_GENERIC_TIMER_FREQUENCY = BSP_FATAL_CODE_BLOCK(12),
+  IMX_FATAL_GPIO_UNEXPECTED_FDT,
 
   /* RISC-V fatal codes */
   RISCV_FATAL_NO_TIMEBASE_FREQUENCY_IN_DEVICE_TREE = BSP_FATAL_CODE_BLOCK(13),
diff --git a/c/src/lib/libbsp/arm/imx/Makefile.am b/c/src/lib/libbsp/arm/imx/Makefile.am
index 234995f..f71508a 100644
--- a/c/src/lib/libbsp/arm/imx/Makefile.am
+++ b/c/src/lib/libbsp/arm/imx/Makefile.am
@@ -64,6 +64,9 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/clock/clock-generic-t
 librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/cache/cache-cp15.c
 librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/cache/cache-v7ar-disable-data.S
 
+# GPIO
+librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/imx/gpio/imx-gpio.c
+
 # I2C
 librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/imx/i2c/imx-i2c.c
 



More information about the vc mailing list