2019-03-12 07:12:37 -07:00
|
|
|
/**
|
|
|
|
* @file gpio/core.c
|
|
|
|
* @brief EFI-related GPIO code for external gpio chips
|
|
|
|
*
|
|
|
|
* @date Mar 8, 2019
|
|
|
|
* @author Andrey Gusakov, (c) 2019
|
|
|
|
*/
|
|
|
|
|
2021-08-03 19:05:01 -07:00
|
|
|
#include "pch.h"
|
2019-03-12 07:12:37 -07:00
|
|
|
#include "gpio/gpio_ext.h"
|
2020-04-06 11:13:29 -07:00
|
|
|
#include "smart_gpio.h"
|
2019-03-12 07:12:37 -07:00
|
|
|
|
2019-04-13 15:47:32 -07:00
|
|
|
#define STRING2(x) #x
|
|
|
|
#define STRING(x) STRING2(x)
|
|
|
|
#pragma message(STRING(BOARD_EXT_GPIOCHIPS))
|
|
|
|
|
2019-03-12 07:12:37 -07:00
|
|
|
#if (BOARD_EXT_GPIOCHIPS > 0)
|
|
|
|
|
|
|
|
/*==========================================================================*/
|
|
|
|
/* Local definitions. */
|
|
|
|
/*==========================================================================*/
|
|
|
|
|
|
|
|
/*==========================================================================*/
|
|
|
|
/* Exported variables. */
|
|
|
|
/*==========================================================================*/
|
|
|
|
|
|
|
|
/*==========================================================================*/
|
|
|
|
/* Local variables and types. */
|
|
|
|
/*==========================================================================*/
|
|
|
|
|
|
|
|
/* TODO: chnage array to list? */
|
|
|
|
struct gpiochip {
|
2019-04-10 05:43:54 -07:00
|
|
|
brain_pin_e base;
|
2019-03-12 07:12:37 -07:00
|
|
|
size_t size;
|
2021-06-10 01:11:01 -07:00
|
|
|
GpioChip *chip;
|
2019-03-12 07:12:37 -07:00
|
|
|
const char *name;
|
|
|
|
/* optional names of each gpio */
|
|
|
|
const char **gpio_names;
|
|
|
|
};
|
|
|
|
|
2021-05-16 22:42:56 -07:00
|
|
|
static gpiochip chips[BOARD_EXT_GPIOCHIPS];
|
2019-03-12 07:12:37 -07:00
|
|
|
|
|
|
|
/*==========================================================================*/
|
|
|
|
/* Local functions. */
|
|
|
|
/*==========================================================================*/
|
|
|
|
|
2019-08-10 08:13:41 -07:00
|
|
|
/**
|
|
|
|
* @return pointer to GPIO device for specified pin
|
|
|
|
*/
|
2021-05-16 22:42:56 -07:00
|
|
|
static gpiochip *gpiochip_find(brain_pin_e pin)
|
2019-03-12 07:12:37 -07:00
|
|
|
{
|
2019-08-10 08:13:41 -07:00
|
|
|
for (int i = 0; i < BOARD_EXT_GPIOCHIPS; i++) {
|
2021-05-16 22:42:56 -07:00
|
|
|
gpiochip *chip = &chips[i];
|
2019-03-12 07:12:37 -07:00
|
|
|
|
|
|
|
if ((pin >= chip->base) && (pin < (chip->base + chip->size)))
|
|
|
|
return chip;
|
|
|
|
}
|
|
|
|
|
2021-06-10 01:11:01 -07:00
|
|
|
return nullptr;
|
2019-03-12 07:12:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*==========================================================================*/
|
|
|
|
/* Exported functions. */
|
|
|
|
/*==========================================================================*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* return numeric part of EXTERNAL pin name.
|
|
|
|
* @details
|
|
|
|
*/
|
|
|
|
|
2019-08-10 08:13:41 -07:00
|
|
|
int gpiochips_getPinOffset(brain_pin_e pin)
|
2019-03-12 07:12:37 -07:00
|
|
|
{
|
2021-05-16 22:42:56 -07:00
|
|
|
gpiochip *chip = gpiochip_find(pin);
|
2019-03-12 07:12:37 -07:00
|
|
|
|
|
|
|
if (chip)
|
|
|
|
return pin - chip->base;
|
|
|
|
|
|
|
|
return EFI_ERROR_CODE;
|
|
|
|
}
|
|
|
|
|
2019-04-10 05:43:54 -07:00
|
|
|
|
2019-03-12 07:12:37 -07:00
|
|
|
/**
|
2019-04-10 05:43:54 -07:00
|
|
|
* @brief Get external chip name
|
|
|
|
* @details return gpiochip name
|
|
|
|
*/
|
|
|
|
|
2019-08-10 08:13:41 -07:00
|
|
|
const char *gpiochips_getChipName(brain_pin_e pin) {
|
2021-05-16 22:42:56 -07:00
|
|
|
gpiochip *chip = gpiochip_find(pin);
|
2019-04-10 05:43:54 -07:00
|
|
|
|
|
|
|
if (chip)
|
|
|
|
return chip->name;
|
|
|
|
|
2021-06-10 01:11:01 -07:00
|
|
|
return nullptr;
|
2019-04-10 05:43:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get external chip port name
|
2019-03-12 07:12:37 -07:00
|
|
|
* @details return pin name or gpiochip name (if no pins names provided)
|
|
|
|
*/
|
|
|
|
|
2019-08-10 08:13:41 -07:00
|
|
|
const char *gpiochips_getPinName(brain_pin_e pin)
|
2019-03-12 07:12:37 -07:00
|
|
|
{
|
2019-04-10 05:43:54 -07:00
|
|
|
int offset;
|
2021-05-16 22:42:56 -07:00
|
|
|
gpiochip *chip = gpiochip_find(pin);
|
2019-03-12 07:12:37 -07:00
|
|
|
|
|
|
|
if (chip) {
|
2019-04-10 05:43:54 -07:00
|
|
|
offset = pin - chip->base;
|
|
|
|
if ((chip->gpio_names) && (chip->gpio_names[offset]))
|
|
|
|
return chip->gpio_names[offset];
|
2019-03-12 07:12:37 -07:00
|
|
|
}
|
|
|
|
|
2021-06-10 01:11:01 -07:00
|
|
|
return nullptr;
|
2019-03-12 07:12:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Register gpiochip
|
|
|
|
* @details should be called from board file. Can be called before os ready.
|
|
|
|
* All chips should be registered before gpiochips_init() called.
|
|
|
|
* returns -1 in case of no free chips left
|
|
|
|
* returns -1 in case of no ops provided, incorrect chip size
|
|
|
|
* else returns chip base
|
|
|
|
*/
|
|
|
|
|
2021-06-10 01:11:01 -07:00
|
|
|
int gpiochip_register(brain_pin_e base, const char *name, GpioChip& gpioChip, size_t size)
|
2019-03-12 07:12:37 -07:00
|
|
|
{
|
2021-06-10 01:11:01 -07:00
|
|
|
/* zero size? */
|
|
|
|
if (!size)
|
2019-03-12 07:12:37 -07:00
|
|
|
return -1;
|
|
|
|
|
2021-01-06 15:29:47 -08:00
|
|
|
/* outside? */
|
|
|
|
if (((size_t)base + size - 1 > BRAIN_PIN_LAST) || (base <= BRAIN_PIN_ONCHIP_LAST))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* check for overlap with other chips */
|
2021-06-10 01:11:01 -07:00
|
|
|
for (int i = 0; i < BOARD_EXT_GPIOCHIPS; i++) {
|
2021-01-06 15:29:47 -08:00
|
|
|
if (chips[i].base != 0) {
|
|
|
|
#define in_range(a, b, c) (((a) > (b)) && ((a) < (c)))
|
|
|
|
if (in_range(base, chips[i].base, chips[i].base + chips[i].size))
|
|
|
|
return -1;
|
|
|
|
if (in_range(base + size, chips[i].base, chips[i].base + chips[i].size))
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-10 01:11:01 -07:00
|
|
|
gpiochip *chip = nullptr;
|
|
|
|
|
2019-03-12 07:12:37 -07:00
|
|
|
/* find free gpiochip struct */
|
2021-06-10 01:11:01 -07:00
|
|
|
for (int i = 0; i < BOARD_EXT_GPIOCHIPS; i++) {
|
2019-03-12 07:12:37 -07:00
|
|
|
if (chips[i].base == 0) {
|
|
|
|
chip = &chips[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no free chips left */
|
2020-01-21 21:45:09 -08:00
|
|
|
if (!chip) {
|
2019-03-12 07:12:37 -07:00
|
|
|
return -1;
|
2020-01-21 21:45:09 -08:00
|
|
|
}
|
2019-03-12 07:12:37 -07:00
|
|
|
|
|
|
|
/* register chip */
|
|
|
|
chip->name = name;
|
2021-06-10 01:11:01 -07:00
|
|
|
chip->chip = &gpioChip;
|
2021-01-06 15:29:47 -08:00
|
|
|
chip->base = base;
|
2019-03-12 07:12:37 -07:00
|
|
|
chip->size = size;
|
2021-06-10 01:11:01 -07:00
|
|
|
chip->gpio_names = nullptr;
|
2019-03-12 07:12:37 -07:00
|
|
|
|
2021-06-10 01:11:01 -07:00
|
|
|
return base;
|
2019-03-12 07:12:37 -07:00
|
|
|
}
|
|
|
|
|
2021-01-06 15:29:47 -08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Unregister gpiochip
|
|
|
|
* @details removes chip from list
|
|
|
|
* TODO: call deinit?
|
|
|
|
*/
|
|
|
|
|
|
|
|
int gpiochip_unregister(brain_pin_e base)
|
|
|
|
{
|
2021-05-16 22:42:56 -07:00
|
|
|
gpiochip *chip = gpiochip_find(base);
|
2021-01-06 15:29:47 -08:00
|
|
|
|
|
|
|
if (!chip)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* gpiochip_find - returns chip if base within its range, but we need it to be base */
|
|
|
|
if (chip->base != base)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* unregister chip */
|
2021-06-10 01:11:01 -07:00
|
|
|
chip->name = nullptr;
|
|
|
|
chip->chip = nullptr;
|
2021-05-16 22:42:56 -07:00
|
|
|
chip->base = GPIO_UNASSIGNED;
|
2021-01-06 15:29:47 -08:00
|
|
|
chip->size = 0;
|
2021-06-10 01:11:01 -07:00
|
|
|
chip->gpio_names = nullptr;
|
2021-01-06 15:29:47 -08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-04-10 05:43:54 -07:00
|
|
|
/**
|
|
|
|
* @brief Set pins names for registered gpiochip
|
|
|
|
* @details should be called after chip registration. May be called several times
|
|
|
|
* Names array size should be aqual to chip gpio count
|
|
|
|
*/
|
|
|
|
|
2021-01-06 15:29:47 -08:00
|
|
|
int gpiochips_setPinNames(brain_pin_e base, const char **names)
|
2019-04-10 05:43:54 -07:00
|
|
|
{
|
2021-05-16 22:42:56 -07:00
|
|
|
gpiochip *chip = gpiochip_find(base);
|
2019-04-10 05:43:54 -07:00
|
|
|
|
|
|
|
if (!chip)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
chip->gpio_names = names;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-03-12 07:12:37 -07:00
|
|
|
/**
|
|
|
|
* @brief Init all registered gpiochips
|
|
|
|
* @details will call gpiochip init ops for all registered chips
|
|
|
|
* calles when OS is ready, so gpiochip can start threads, use drivers and so on.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int gpiochips_init(void)
|
|
|
|
{
|
|
|
|
int pins_added = 0;
|
|
|
|
|
2021-06-10 01:11:01 -07:00
|
|
|
for (int i = 0; i < BOARD_EXT_GPIOCHIPS; i++) {
|
2021-05-16 22:42:56 -07:00
|
|
|
gpiochip *chip = &chips[i];
|
2019-03-12 07:12:37 -07:00
|
|
|
|
|
|
|
if (!chip->base)
|
|
|
|
continue;
|
|
|
|
|
2021-06-10 01:11:01 -07:00
|
|
|
if (chip->chip->init() < 0) {
|
2019-03-12 07:12:37 -07:00
|
|
|
/* remove chip if it fails to init */
|
|
|
|
/* TODO: we will have a gap, is it ok? */
|
2021-05-16 22:42:56 -07:00
|
|
|
chip->base = GPIO_UNASSIGNED;
|
2019-03-12 07:12:37 -07:00
|
|
|
} else {
|
|
|
|
pins_added += chip->size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pins_added;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set pin mode of gpiochip
|
|
|
|
* @details set pad mode for given pin.
|
|
|
|
* return -1 if driver does not implemet setPadMode ops
|
|
|
|
* else return value from gpiochip driver.
|
|
|
|
*/
|
2020-05-07 06:49:57 -07:00
|
|
|
/* this fuction uses iomode_t that is related to STM32 (or other MCU)
|
|
|
|
* output modes. Use some common enums? */
|
|
|
|
int gpiochips_setPadMode(brain_pin_e pin, iomode_t mode)
|
2019-03-12 07:12:37 -07:00
|
|
|
{
|
2021-05-16 22:42:56 -07:00
|
|
|
gpiochip *chip = gpiochip_find(pin);
|
2019-03-12 07:12:37 -07:00
|
|
|
|
|
|
|
if (!chip)
|
|
|
|
return -1;
|
|
|
|
|
2021-06-10 01:11:01 -07:00
|
|
|
return chip->chip->setPadMode(pin - chip->base, mode);
|
2019-03-12 07:12:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set value to gpio of gpiochip
|
|
|
|
* @details actual output value depent on current gpiochip implementation
|
|
|
|
* for smart switch inactive supposed to be closed switch (no current flows)
|
|
|
|
* returns -1 in case of pin not belong to any gpio chip
|
|
|
|
* returns -1 in case of chip does not support seting output value (input only)
|
|
|
|
* else return value from gpiochip driver;
|
|
|
|
*/
|
|
|
|
|
|
|
|
int gpiochips_writePad(brain_pin_e pin, int value)
|
|
|
|
{
|
2021-05-16 22:42:56 -07:00
|
|
|
gpiochip *chip = gpiochip_find(pin);
|
2019-03-12 07:12:37 -07:00
|
|
|
|
|
|
|
if (!chip)
|
|
|
|
return -1;
|
|
|
|
|
2021-06-10 01:11:01 -07:00
|
|
|
return chip->chip->writePad(pin - chip->base, value);
|
2019-03-12 07:12:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get value to gpio of gpiochip
|
|
|
|
* @details actual input value depent on current gpiochip implementation
|
|
|
|
* returns -1 in case of pin not belong to any gpio chip
|
|
|
|
* returns -1 in case of chip does not support getting output value (output only)
|
|
|
|
* else return value from gpiochip driver;
|
|
|
|
*/
|
|
|
|
|
|
|
|
int gpiochips_readPad(brain_pin_e pin)
|
|
|
|
{
|
2021-05-16 22:42:56 -07:00
|
|
|
gpiochip *chip = gpiochip_find(pin);
|
2019-03-12 07:12:37 -07:00
|
|
|
|
|
|
|
if (!chip)
|
|
|
|
return -1;
|
|
|
|
|
2021-06-10 01:11:01 -07:00
|
|
|
return chip->chip->readPad(pin - chip->base);
|
2019-03-12 07:12:37 -07:00
|
|
|
}
|
|
|
|
|
2020-01-12 07:20:10 -08:00
|
|
|
/**
|
|
|
|
* @brief Get diagnostic for given gpio
|
|
|
|
* @details actual output value depent on gpiochip capabilities
|
|
|
|
* returns -1 in case of pin not belong to any gpio chip
|
|
|
|
* returns PIN_OK in case of chip does not support getting diagnostic
|
|
|
|
* else return brain_pin_diag_e from gpiochip driver;
|
|
|
|
*/
|
|
|
|
|
|
|
|
brain_pin_diag_e gpiochips_getDiag(brain_pin_e pin)
|
|
|
|
{
|
2021-05-16 22:42:56 -07:00
|
|
|
gpiochip *chip = gpiochip_find(pin);
|
2020-01-12 07:20:10 -08:00
|
|
|
|
|
|
|
if (!chip)
|
|
|
|
return PIN_INVALID;
|
|
|
|
|
2021-06-10 01:11:01 -07:00
|
|
|
return chip->chip->getDiag(pin - chip->base);
|
2020-01-12 07:20:10 -08:00
|
|
|
}
|
|
|
|
|
2019-03-12 07:12:37 -07:00
|
|
|
/**
|
|
|
|
* @brief Get total pin count allocated for external gpio chips.
|
2019-08-10 08:13:41 -07:00
|
|
|
* @details Will also include unused pins for chips that was registered
|
2019-03-12 07:12:37 -07:00
|
|
|
* but later fails to init.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int gpiochips_get_total_pins(void)
|
|
|
|
{
|
2021-01-06 15:29:47 -08:00
|
|
|
int i;
|
|
|
|
int cnt = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < BOARD_EXT_GPIOCHIPS; i++) {
|
2021-05-16 22:42:56 -07:00
|
|
|
gpiochip *chip = &chips[i];
|
2021-01-06 15:29:47 -08:00
|
|
|
|
|
|
|
if (!chip->base)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
cnt += chip->size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cnt;
|
2019-03-12 07:12:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#else /* BOARD_EXT_GPIOCHIPS > 0 */
|
|
|
|
|
2019-08-10 08:13:41 -07:00
|
|
|
int gpiochips_getPinOffset(brain_pin_e pin) {
|
2019-03-12 07:12:37 -07:00
|
|
|
(void)pin;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-08-10 08:13:41 -07:00
|
|
|
const char *gpiochips_getChipName(brain_pin_e pin) {
|
2019-04-10 05:43:54 -07:00
|
|
|
(void)pin;
|
|
|
|
|
2021-06-10 01:11:01 -07:00
|
|
|
return nullptr;
|
2019-04-10 05:43:54 -07:00
|
|
|
}
|
|
|
|
|
2019-08-10 08:13:41 -07:00
|
|
|
const char *gpiochips_getPinName(brain_pin_e pin) {
|
2019-03-12 07:12:37 -07:00
|
|
|
(void)pin;
|
|
|
|
|
2021-06-10 01:11:01 -07:00
|
|
|
return nullptr;
|
2019-03-12 07:12:37 -07:00
|
|
|
}
|
|
|
|
|
2021-06-10 01:11:01 -07:00
|
|
|
int gpiochip_register(brain_pin_e base, const char *name, GpioChip&, size_t size)
|
2019-03-12 07:12:37 -07:00
|
|
|
{
|
2021-06-10 01:11:01 -07:00
|
|
|
(void)base; (void)name; (void)size;
|
2019-03-12 07:12:37 -07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-04-10 05:43:54 -07:00
|
|
|
int gpiochips_setPinNames(brain_pin_e pin, const char **names)
|
|
|
|
{
|
|
|
|
(void)pin; (void)names;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-03-12 07:12:37 -07:00
|
|
|
int gpiochips_init(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int gpiochips_get_total_pins(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* BOARD_EXT_GPIOCHIPS > 0 */
|