forked from Imagelibrary/rtems
@@ -4,3 +4,8 @@ include_arm_freescale_imxdir = $(includedir)/arm/freescale/imx
|
||||
include_arm_freescale_imx_HEADERS =
|
||||
include_arm_freescale_imx_HEADERS += ../../../../../../bsps/arm/shared/include/arm/freescale/imx/imx_iomuxreg.h
|
||||
include_arm_freescale_imx_HEADERS += ../../../../../../bsps/arm/shared/include/arm/freescale/imx/imx_iomuxvar.h
|
||||
|
||||
include_bspdir = $(includedir)/bsp
|
||||
include_bsp_HEADERS =
|
||||
include_bsp_HEADERS += ../../../../../../bsps/arm/shared/include/bsp/imx-gpio.h
|
||||
include_bsp_HEADERS += ../../../../../../bsps/arm/shared/include/bsp/imx-iomux.h
|
||||
|
||||
196
bsps/arm/shared/include/bsp/imx-gpio.h
Normal file
196
bsps/arm/shared/include/bsp/imx-gpio.h
Normal file
@@ -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 */
|
||||
359
bsps/arm/shared/pins/imx-gpio.c
Normal file
359
bsps/arm/shared/pins/imx-gpio.c
Normal file
@@ -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
|
||||
);
|
||||
Reference in New Issue
Block a user