488 lines
13 KiB
C
488 lines
13 KiB
C
/****************************************************************************
|
|
* boards/arm/s32k1xx/rddrone-bms772/src/s32k1xx_gpio.c
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/* Copyright 2022 NXP */
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <assert.h>
|
|
#include <debug.h>
|
|
#include <errno.h>
|
|
|
|
#include <nuttx/ioexpander/gpio.h>
|
|
|
|
#include "s32k1xx_pin.h"
|
|
|
|
#include "rddrone-bms772.h"
|
|
|
|
#if defined(CONFIG_DEV_GPIO) && !defined(CONFIG_GPIO_LOWER_HALF)
|
|
|
|
/****************************************************************************
|
|
* Private Types
|
|
****************************************************************************/
|
|
|
|
struct s32k1xx_gpio_dev_s
|
|
{
|
|
struct gpio_dev_s gpio;
|
|
uint8_t id;
|
|
pin_interrupt_t callback;
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
static int s32k1xx_gpio_interrupt(int irq, void *context, void *arg);
|
|
|
|
static int gpio_read(struct gpio_dev_s *dev, bool *value);
|
|
static int gpio_write(struct gpio_dev_s *dev, bool value);
|
|
#ifdef CONFIG_S32K1XX_GPIOIRQ
|
|
static int gpio_irqattach(struct gpio_dev_s *dev, pin_interrupt_t callback);
|
|
static int gpio_irqenable(struct gpio_dev_s *dev, bool enable);
|
|
#endif /* CONFIG_S32K1XX_GPIOIRQ */
|
|
static int gpio_setpintype(struct gpio_dev_s *dev,
|
|
enum gpio_pintype_e pintype);
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
/* Set of GPIO pins */
|
|
|
|
static uint32_t g_gpiopins[] =
|
|
{
|
|
GPIO0,
|
|
GPIO1,
|
|
GPIO2,
|
|
GPIO3,
|
|
GPIO4,
|
|
GPIO5,
|
|
GPIO6,
|
|
GPIO7,
|
|
GPIO8,
|
|
GPIO9,
|
|
GPIO10,
|
|
GPIO11,
|
|
};
|
|
|
|
#if NUM_OF_GPIO > 0
|
|
static struct s32k1xx_gpio_dev_s g_gpio[NUM_OF_GPIO];
|
|
#endif
|
|
|
|
/* Different pin types support different operations */
|
|
|
|
static const struct gpio_operations_s gpin_ops =
|
|
{
|
|
.go_read = gpio_read,
|
|
.go_write = NULL,
|
|
.go_attach = NULL,
|
|
.go_enable = NULL,
|
|
.go_setpintype = gpio_setpintype,
|
|
};
|
|
|
|
static const struct gpio_operations_s gpout_ops =
|
|
{
|
|
.go_read = gpio_read,
|
|
.go_write = gpio_write,
|
|
.go_attach = NULL,
|
|
.go_enable = NULL,
|
|
.go_setpintype = gpio_setpintype,
|
|
};
|
|
|
|
#ifdef CONFIG_S32K1XX_GPIOIRQ
|
|
static const struct gpio_operations_s gpint_ops =
|
|
{
|
|
.go_read = gpio_read,
|
|
.go_write = NULL,
|
|
.go_attach = gpio_irqattach,
|
|
.go_enable = gpio_irqenable,
|
|
.go_setpintype = gpio_setpintype,
|
|
};
|
|
#endif /* CONFIG_S32K1XX_GPIOIRQ */
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_S32K1XX_GPIOIRQ
|
|
static int s32k1xx_gpio_interrupt(int irq, void *context, void *arg)
|
|
{
|
|
struct s32k1xx_gpio_dev_s *s32k1xx_gpio = (struct s32k1xx_gpio_dev_s *)arg;
|
|
|
|
DEBUGASSERT(s32k1xx_gpio != NULL && s32k1xx_gpio->callback != NULL);
|
|
gpioinfo("Interrupt! callback=%p\n", s32k1xx_gpio->callback);
|
|
|
|
s32k1xx_gpio->callback(&s32k1xx_gpio->gpio, s32k1xx_gpio->id);
|
|
return OK;
|
|
}
|
|
#endif /* CONFIG_S32K1XX_GPIOIRQ */
|
|
|
|
static int gpio_read(struct gpio_dev_s *dev, bool *value)
|
|
{
|
|
struct s32k1xx_gpio_dev_s *s32k1xx_gpio = (struct s32k1xx_gpio_dev_s *)dev;
|
|
|
|
DEBUGASSERT(s32k1xx_gpio != NULL && value != NULL);
|
|
DEBUGASSERT(s32k1xx_gpio->id < NUM_OF_GPIO);
|
|
gpioinfo("Reading...\n");
|
|
|
|
*value = s32k1xx_gpioread(g_gpiopins[s32k1xx_gpio->id]);
|
|
return OK;
|
|
}
|
|
|
|
static int gpio_write(struct gpio_dev_s *dev, bool value)
|
|
{
|
|
struct s32k1xx_gpio_dev_s *s32k1xx_gpio = (struct s32k1xx_gpio_dev_s *)dev;
|
|
|
|
DEBUGASSERT(s32k1xx_gpio != NULL);
|
|
DEBUGASSERT(s32k1xx_gpio->id < NUM_OF_GPIO);
|
|
gpioinfo("Writing %d\n", (int) value);
|
|
|
|
s32k1xx_gpiowrite(g_gpiopins[s32k1xx_gpio->id], value);
|
|
return OK;
|
|
}
|
|
|
|
#ifdef CONFIG_S32K1XX_GPIOIRQ
|
|
static int gpio_irqattach(struct gpio_dev_s *dev, pin_interrupt_t callback)
|
|
{
|
|
struct s32k1xx_gpio_dev_s *s32k1xx_gpio = (struct s32k1xx_gpio_dev_s *)dev;
|
|
|
|
gpioinfo("Attaching the callback\n");
|
|
s32k1xx_pinirqattach(g_gpiopins[s32k1xx_gpio->id], s32k1xx_gpio_interrupt,
|
|
&g_gpio[s32k1xx_gpio->id]);
|
|
|
|
gpioinfo("Attach %p\n", callback);
|
|
s32k1xx_gpio->callback = callback;
|
|
return OK;
|
|
}
|
|
|
|
static int gpio_irqenable(struct gpio_dev_s *dev, bool enable)
|
|
{
|
|
struct s32k1xx_gpio_dev_s *s32k1xx_gpio = (struct s32k1xx_gpio_dev_s *)dev;
|
|
|
|
DEBUGASSERT(s32k1xx_gpio != NULL);
|
|
|
|
if (enable)
|
|
{
|
|
if (s32k1xx_gpio->callback != NULL)
|
|
{
|
|
gpioinfo("Enabling the interrupt\n");
|
|
s32k1xx_pinirqenable(g_gpiopins[s32k1xx_gpio->id]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gpioinfo("Disable the interrupt\n");
|
|
s32k1xx_pinirqdisable(g_gpiopins[s32k1xx_gpio->id]);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
#endif /* CONFIG_S32K1XX_GPIOIRQ */
|
|
|
|
static int gpio_setpintype(struct gpio_dev_s *dev,
|
|
enum gpio_pintype_e pintype)
|
|
{
|
|
int ret = OK;
|
|
uint32_t pinconfig;
|
|
const struct gpio_operations_s *gpio_ops;
|
|
struct s32k1xx_gpio_dev_s *s32k1xx_gpio = (struct s32k1xx_gpio_dev_s *)dev;
|
|
|
|
DEBUGASSERT(s32k1xx_gpio != NULL);
|
|
DEBUGASSERT(s32k1xx_gpio->id < NUM_OF_GPIO);
|
|
gpioinfo("Setpintype...\n");
|
|
|
|
/* Check if the new pintype is actually different from the old pintype */
|
|
|
|
if (s32k1xx_gpio->gpio.gp_pintype == pintype)
|
|
{
|
|
/* Pintype has not changed. We're done already. */
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Clear the pin mode, pin options and interrupt options */
|
|
|
|
pinconfig = (g_gpiopins[s32k1xx_gpio->id] &
|
|
~(_PIN_MODE_MASK | _PIN_OPTIONS_MASK | _PIN_INT_MASK));
|
|
|
|
/* Set the pinconfig and device operations according to the new pintype */
|
|
|
|
switch (pintype)
|
|
{
|
|
case GPIO_INPUT_PIN:
|
|
{
|
|
pinconfig |= GPIO_INPUT;
|
|
gpio_ops = &gpin_ops;
|
|
}
|
|
break;
|
|
|
|
case GPIO_INPUT_PIN_PULLUP:
|
|
{
|
|
pinconfig |= GPIO_PULLUP;
|
|
gpio_ops = &gpin_ops;
|
|
}
|
|
break;
|
|
|
|
case GPIO_INPUT_PIN_PULLDOWN:
|
|
{
|
|
pinconfig |= GPIO_PULLDOWN;
|
|
gpio_ops = &gpin_ops;
|
|
}
|
|
break;
|
|
|
|
case GPIO_OUTPUT_PIN:
|
|
{
|
|
pinconfig |= GPIO_OUTPUT;
|
|
gpio_ops = &gpout_ops;
|
|
}
|
|
break;
|
|
|
|
#ifdef CONFIG_S32K1XX_GPIOIRQ
|
|
case GPIO_INTERRUPT_HIGH_PIN:
|
|
{
|
|
pinconfig |= (GPIO_INPUT | PIN_INT_ONE);
|
|
gpio_ops = &gpint_ops;
|
|
}
|
|
break;
|
|
|
|
case GPIO_INTERRUPT_LOW_PIN:
|
|
{
|
|
pinconfig |= (GPIO_INPUT | PIN_INT_ZERO);
|
|
gpio_ops = &gpint_ops;
|
|
}
|
|
break;
|
|
|
|
case GPIO_INTERRUPT_RISING_PIN:
|
|
{
|
|
pinconfig |= (GPIO_INPUT | PIN_INT_RISING);
|
|
gpio_ops = &gpint_ops;
|
|
}
|
|
break;
|
|
|
|
case GPIO_INTERRUPT_FALLING_PIN:
|
|
{
|
|
pinconfig |= (GPIO_INPUT | PIN_INT_FALLING);
|
|
gpio_ops = &gpint_ops;
|
|
}
|
|
break;
|
|
|
|
case GPIO_INTERRUPT_BOTH_PIN:
|
|
case GPIO_INTERRUPT_PIN:
|
|
{
|
|
pinconfig |= (GPIO_INPUT | PIN_INT_BOTH);
|
|
gpio_ops = &gpint_ops;
|
|
}
|
|
break;
|
|
#endif /* CONFIG_S32K1XX_GPIOIRQ */
|
|
|
|
default:
|
|
{
|
|
/* Not implemented yet! */
|
|
|
|
return -EINVAL; /* Return without changing the pin settings */
|
|
}
|
|
break;
|
|
}
|
|
|
|
#ifdef CONFIG_S32K1XX_GPIOIRQ
|
|
/* If the pin previously had an interrupt pintype... */
|
|
|
|
if ((s32k1xx_gpio->gpio.gp_pintype >= GPIO_INTERRUPT_PIN) &&
|
|
(s32k1xx_gpio->gpio.gp_pintype < GPIO_NPINTYPES))
|
|
{
|
|
/* ...disable the interrupt... */
|
|
|
|
ret = gpio_irqenable(dev, false);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
/* ...and detach the old callback. */
|
|
|
|
ret = gpio_irqattach(dev, NULL);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
#endif /* CONFIG_S32K1XX_GPIOIRQ */
|
|
|
|
/* Change the pintype and set of operations */
|
|
|
|
s32k1xx_gpio->gpio.gp_pintype = pintype;
|
|
s32k1xx_gpio->gpio.gp_ops = gpio_ops;
|
|
|
|
/* Reconfigure the actual pin */
|
|
|
|
g_gpiopins[s32k1xx_gpio->id] = pinconfig;
|
|
ret = s32k1xx_pinconfig(pinconfig);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: s32k1xx_gpio_initialize
|
|
*
|
|
* Description:
|
|
* Initialize GPIO drivers for use with /apps/examples/gpio
|
|
*
|
|
****************************************************************************/
|
|
|
|
int s32k1xx_gpio_initialize(void)
|
|
{
|
|
int ret = OK;
|
|
|
|
#if NUM_OF_GPIO > 0
|
|
int i;
|
|
uint32_t pinset;
|
|
|
|
for (i = 0; i < NUM_OF_GPIO; i++)
|
|
{
|
|
DEBUGASSERT((g_gpiopins[i] & (_PIN_MODE_MASK)) == _PIN_MODE_GPIO);
|
|
|
|
g_gpio[i].id = i;
|
|
|
|
/* Find which pin type we are dealing with */
|
|
|
|
pinset = g_gpiopins[i];
|
|
|
|
if ((pinset & (_PIN_IO_MASK)) == _PIN_INPUT)
|
|
{
|
|
# ifdef CONFIG_S32K1XX_GPIOIRQ
|
|
/* Input pin (with or without interrupt) */
|
|
|
|
if (pinset & (_PIN_INTERRUPT))
|
|
{
|
|
/* Interrupt pin */
|
|
|
|
g_gpio[i].gpio.gp_ops = &gpint_ops;
|
|
|
|
/* Determine specific interrupt pin type */
|
|
|
|
switch (pinset & (_PIN_INTERRUPT))
|
|
{
|
|
case PIN_INT_ONE:
|
|
{
|
|
g_gpio[i].gpio.gp_pintype = GPIO_INTERRUPT_HIGH_PIN;
|
|
}
|
|
break;
|
|
|
|
case PIN_INT_ZERO:
|
|
{
|
|
g_gpio[i].gpio.gp_pintype = GPIO_INTERRUPT_LOW_PIN;
|
|
}
|
|
break;
|
|
|
|
case PIN_INT_RISING:
|
|
{
|
|
g_gpio[i].gpio.gp_pintype = GPIO_INTERRUPT_RISING_PIN;
|
|
}
|
|
break;
|
|
|
|
case PIN_INT_FALLING:
|
|
{
|
|
g_gpio[i].gpio.gp_pintype = GPIO_INTERRUPT_FALLING_PIN;
|
|
}
|
|
break;
|
|
|
|
case PIN_INT_BOTH:
|
|
{
|
|
g_gpio[i].gpio.gp_pintype = GPIO_INTERRUPT_BOTH_PIN;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
g_gpio[i].gpio.gp_pintype = GPIO_INTERRUPT_PIN;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
# endif /* CONFIG_S32K1XX_GPIOIRQ */
|
|
{
|
|
/* Input pin without interrupt */
|
|
|
|
g_gpio[i].gpio.gp_ops = &gpin_ops;
|
|
|
|
/* Determine specific input pin type */
|
|
|
|
switch (pinset & (_PIN_INPUT_PULLMASK))
|
|
{
|
|
case _PIN_INPUT_PULLUP:
|
|
{
|
|
g_gpio[i].gpio.gp_pintype = GPIO_INPUT_PIN_PULLUP;
|
|
}
|
|
break;
|
|
|
|
case _PIN_INPUT_PULLDOWN:
|
|
{
|
|
g_gpio[i].gpio.gp_pintype = GPIO_INPUT_PIN_PULLDOWN;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
g_gpio[i].gpio.gp_pintype = GPIO_INPUT_PIN;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Output pin */
|
|
|
|
g_gpio[i].gpio.gp_ops = &gpout_ops;
|
|
g_gpio[i].gpio.gp_pintype = GPIO_OUTPUT_PIN;
|
|
}
|
|
|
|
/* Configure and register the GPIO pin */
|
|
|
|
ret = s32k1xx_pinconfig(g_gpiopins[i]);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = gpio_pin_register(&g_gpio[i].gpio, i);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
#endif /* CONFIG_DEV_GPIO && !CONFIG_GPIO_LOWER_HALF */
|