From 551f2f5883dfce68675bfa6b5996aa15a4d50640 Mon Sep 17 00:00:00 2001 From: dron0gus Date: Wed, 10 Apr 2019 15:43:54 +0300 Subject: [PATCH] Gpiochips integration (#740) * gpio-chips core function renames * efi_gpio, pin_repository: add support for external gpios * gpio-chips update * gpio-chips: add api to name each pin of gpiochip * tle6240: provide individual names for each pin --- .../controllers/algo/auto_generated_enums.cpp | 6 ++ firmware/controllers/system/efi_gpio.cpp | 97 +++++++++++++------ firmware/controllers/system/efi_gpio.h | 5 + firmware/hw_layer/drivers/gpio/core.c | 72 +++++++++++--- firmware/hw_layer/drivers/gpio/gpio_ext.h | 8 +- firmware/hw_layer/drivers/gpio/tle6240.c | 15 ++- firmware/hw_layer/io_pins.cpp | 52 +++++++--- firmware/hw_layer/pin_repository.cpp | 71 +++++++++++--- 8 files changed, 252 insertions(+), 74 deletions(-) diff --git a/firmware/controllers/algo/auto_generated_enums.cpp b/firmware/controllers/algo/auto_generated_enums.cpp index d949586ab1..b63c04b8b5 100644 --- a/firmware/controllers/algo/auto_generated_enums.cpp +++ b/firmware/controllers/algo/auto_generated_enums.cpp @@ -7,6 +7,7 @@ #include "global.h" #include "rusefi_enums.h" +#include "drivers/gpio/gpio_ext.h" const char *getEngine_type_e(engine_type_e value){ switch(value) { case ACURA_RSX: @@ -805,6 +806,11 @@ case GPIOH_8: return "GPIOH_8"; case GPIOH_9: return "GPIOH_9"; +#if (BOARD_EXT_GPIOCHIPS > 0) + default: + /* gpichips */ + return gpiochips_getPinName(value); +#endif } return NULL; } diff --git a/firmware/controllers/system/efi_gpio.cpp b/firmware/controllers/system/efi_gpio.cpp index 715c354eaa..b630845713 100644 --- a/firmware/controllers/system/efi_gpio.cpp +++ b/firmware/controllers/system/efi_gpio.cpp @@ -9,6 +9,7 @@ #include "global.h" #include "engine.h" #include "efi_gpio.h" +#include "drivers/gpio/gpio_ext.h" #if EFI_GPIO_HARDWARE || defined(__DOXYGEN__) #include "pin_repository.h" @@ -68,7 +69,17 @@ EnginePins::EnginePins() { (outputPin)->currentLogicValue = (logicValue); \ } \ } + +#define gpiochip_setPinValue(outputPin, electricalValue, logicValue) \ + { \ + if ((outputPin)->currentLogicValue != (logicValue)) { \ + gpiochips_writePad((outputPin)->brainPin, (electricalValue)); \ + (outputPin)->currentLogicValue = (logicValue); \ + } \ + } + #else /* EFI_PROD_CODE */ + #define setPinValue(outputPin, electricalValue, logicValue) \ { \ if ((outputPin)->currentLogicValue != (logicValue)) { \ @@ -295,13 +306,26 @@ void OutputPin::toggle() { } void OutputPin::setValue(int logicValue) { #if EFI_PROD_CODE - if (port != GPIO_NULL) { - efiAssertVoid(CUSTOM_ERR_6621, modePtr!=NULL, "pin mode not initialized"); - pin_output_mode_e mode = *modePtr; - efiAssertVoid(CUSTOM_ERR_6622, mode <= OM_OPENDRAIN_INVERTED, "invalid pin_output_mode_e"); - int eValue = getElectricalValue(logicValue, mode); - setPinValue(this, eValue, logicValue); - } + efiAssertVoid(CUSTOM_ERR_6621, modePtr!=NULL, "pin mode not initialized"); + pin_output_mode_e mode = *modePtr; + efiAssertVoid(CUSTOM_ERR_6622, mode <= OM_OPENDRAIN_INVERTED, "invalid pin_output_mode_e"); + int eValue = getElectricalValue(logicValue, mode); + + #if (BOARD_EXT_GPIOCHIPS > 0) + if (!this->ext) { + /* onchip pin */ + if (port != GPIO_NULL) { + setPinValue(this, eValue, logicValue); + } + } else { + /* external pin */ + gpiochip_setPinValue(this, this->brainPin, logicValue); + } + #else + if (port != GPIO_NULL) { + setPinValue(this, eValue, logicValue); + } + #endif #else /* EFI_PROD_CODE */ setPinValue(this, eValue, logicValue); @@ -381,37 +405,50 @@ void OutputPin::initPin(const char *msg, brain_pin_e brainPin, const pin_output_ #if EFI_GPIO_HARDWARE || defined(__DOXYGEN__) if (brainPin == GPIO_UNASSIGNED) return; - ioportid_t port = getHwPort(msg, brainPin); - int pin = getHwPin(msg, brainPin); - - /** - * This method is used for digital GPIO pins only, for peripheral pins see mySetPadMode - */ - if (port == GPIO_NULL) { - // that's for GRIO_NONE - this->port = port; - return; - } assertOMode(*outputMode); iomode_t mode = (*outputMode == OM_DEFAULT || *outputMode == OM_INVERTED) ? PAL_MODE_OUTPUT_PUSHPULL : PAL_MODE_OUTPUT_OPENDRAIN; - /** - * @brief Initialize the hardware output pin while also assigning it a logical name - */ - if (this->port != NULL && (this->port != port || this->pin != pin)) { + #if (BOARD_EXT_GPIOCHIPS > 0) + this->ext = false; + #endif + if (brain_pin_is_onchip(brainPin)) { + ioportid_t port = getHwPort(msg, brainPin); + int pin = getHwPin(msg, brainPin); + /** - * here we check if another physical pin is already assigned to this logical output + * This method is used for digital GPIO pins only, for peripheral pins see mySetPadMode */ - // todo: need to clear '&outputs' in io_pins.c - warning(CUSTOM_OBD_PIN_CONFLICT, "outputPin [%s] already assigned to %x%d", msg, this->port, this->pin); - engine->withError = true; - return; + if (port == GPIO_NULL) { + // that's for GRIO_NONE + this->port = port; + return; + } + + /** + * @brief Initialize the hardware output pin while also assigning it a logical name + */ + if (this->port != NULL && (this->port != port || this->pin != pin)) { + /** + * here we check if another physical pin is already assigned to this logical output + */ + // todo: need to clear '&outputs' in io_pins.c + warning(CUSTOM_OBD_PIN_CONFLICT, "outputPin [%s] already assigned to %x%d", msg, this->port, this->pin); + engine->withError = true; + return; + } + this->port = port; + this->pin = pin; } + #if (BOARD_EXT_GPIOCHIPS > 0) + else { + this->ext = true; + this->brainPin = brainPin; + } + #endif + this->currentLogicValue = INITIAL_PIN_STATE; - this->port = port; - this->pin = pin; efiSetPadMode(msg, brainPin, mode); @@ -492,5 +529,3 @@ const char *hwPortname(brain_pin_e brainPin) { return "N/A"; } #endif /* EFI_GPIO_HARDWARE */ - - diff --git a/firmware/controllers/system/efi_gpio.h b/firmware/controllers/system/efi_gpio.h index f52e5c1a5a..c6c282fe0d 100644 --- a/firmware/controllers/system/efi_gpio.h +++ b/firmware/controllers/system/efi_gpio.h @@ -51,6 +51,11 @@ public: #if EFI_GPIO_HARDWARE || defined(__DOXYGEN__) ioportid_t port; uint8_t pin; + #if (BOARD_EXT_GPIOCHIPS > 0) + /* used for external pins */ + brain_pin_e brainPin; + bool ext; + #endif #endif /* EFI_GPIO_HARDWARE */ int8_t currentLogicValue; /** diff --git a/firmware/hw_layer/drivers/gpio/core.c b/firmware/hw_layer/drivers/gpio/core.c index cf1237c983..db515180f6 100644 --- a/firmware/hw_layer/drivers/gpio/core.c +++ b/firmware/hw_layer/drivers/gpio/core.c @@ -16,8 +16,8 @@ /*==========================================================================*/ /* fist available gpio number after on-chip gpios */ -#define EXT_GPIOS_FIRST (GPIOH_15 + 1) -static size_t gpio_base_free = EXT_GPIOS_FIRST; +#define EXT_GPIOS_FIRST (BRAIN_PIN_LAST_ONCHIP + 1) +static brain_pin_e gpio_base_free = EXT_GPIOS_FIRST; /*==========================================================================*/ /* Exported variables. */ @@ -29,7 +29,7 @@ static size_t gpio_base_free = EXT_GPIOS_FIRST; /* TODO: chnage array to list? */ struct gpiochip { - size_t base; + brain_pin_e base; size_t size; struct gpiochip_ops *ops; const char *name; @@ -68,7 +68,7 @@ static struct gpiochip *gpiochip_find(unsigned int pin) * @details */ -int getHwPinExt(unsigned int pin) +int gpiochips_getPinOffset(unsigned int pin) { struct gpiochip *chip = gpiochip_find(pin); @@ -78,18 +78,36 @@ int getHwPinExt(unsigned int pin) return EFI_ERROR_CODE; } + /** - * @brief Register gpiochip - * @details return pin name or gpiochip name (if no pins names provided) + * @brief Get external chip name + * @details return gpiochip name */ -const char *portNameExt(unsigned int pin) +const char *gpiochips_getChipName(unsigned int pin) { struct gpiochip *chip = gpiochip_find(pin); + if (chip) + return chip->name; + + return NULL; +} + +/** + * @brief Get external chip port name + * @details return pin name or gpiochip name (if no pins names provided) + */ + +const char *gpiochips_getPinName(unsigned int pin) +{ + int offset; + struct gpiochip *chip = gpiochip_find(pin); + if (chip) { - if (chip->gpio_names) - return chip->gpio_names[pin - chip->base]; + offset = pin - chip->base; + if ((chip->gpio_names) && (chip->gpio_names[offset])) + return chip->gpio_names[offset]; else return chip->name; } @@ -142,6 +160,24 @@ int gpiochip_register(const char *name, struct gpiochip_ops *ops, size_t size, v return (chip->base); } +/** + * @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 + */ + +int gpiochips_setPinNames(brain_pin_e pin, const char **names) +{ + struct gpiochip *chip = gpiochip_find(pin); + + if (!chip) + return -1; + + chip->gpio_names = names; + + return 0; +} + /** * @brief Init all registered gpiochips * @details will call gpiochip init ops for all registered chips @@ -251,14 +287,21 @@ int gpiochips_get_total_pins(void) #else /* BOARD_EXT_GPIOCHIPS > 0 */ -int getHwPinExt(unsigned int pin) +int gpiochips_getPinOffset(unsigned int pin) { (void)pin; return -1; } -const char *portNameExt(unsigned int pin) +const char *gpiochips_getChipName(unsigned int pin) +{ + (void)pin; + + return NULL; +} + +const char *gpiochips_getPinName(unsigned int pin) { (void)pin; @@ -275,6 +318,13 @@ int gpiochip_register(const char *name, struct gpiochip_ops *ops, size_t size, v return 0; } +int gpiochips_setPinNames(brain_pin_e pin, const char **names) +{ + (void)pin; (void)names; + + return 0; +} + int gpiochips_init(void) { return 0; diff --git a/firmware/hw_layer/drivers/gpio/gpio_ext.h b/firmware/hw_layer/drivers/gpio/gpio_ext.h index 924a87e9f7..ba10d48ad1 100644 --- a/firmware/hw_layer/drivers/gpio/gpio_ext.h +++ b/firmware/hw_layer/drivers/gpio/gpio_ext.h @@ -38,12 +38,16 @@ struct gpiochip_ops { int (*deinit)(void *data); }; -int getHwPinExt(unsigned int pin); -const char *portNameExt(unsigned int pin); +int gpiochips_getPinOffset(unsigned int pin); +const char *gpiochips_getChipName(unsigned int pin); +const char *gpiochips_getPinName(unsigned int pin); /* register gpio cgip */ int gpiochip_register(const char *name, struct gpiochip_ops *ops, size_t size, void *priv); +/* Set individual names for pins */ +int gpiochips_setPinNames(brain_pin_e pin, const char **names); + /* gpio extenders subsystem init */ int gpiochips_init(void); diff --git a/firmware/hw_layer/drivers/gpio/tle6240.c b/firmware/hw_layer/drivers/gpio/tle6240.c index 7c890fba28..50ca401ab5 100644 --- a/firmware/hw_layer/drivers/gpio/tle6240.c +++ b/firmware/hw_layer/drivers/gpio/tle6240.c @@ -104,6 +104,13 @@ struct tle6240_priv { static struct tle6240_priv chips[BOARD_TLE6240_COUNT]; +static const char* tle6240_pin_names[TLE6240_OUTPUTS] = { + "tle6240.OUT1", "tle6240.OUT2", "tle6240.OUT3", "tle6240.OUT4", + "tle6240.OUT5", "tle6240.OUT6", "tle6240.OUT7", "tle6240.OUT8", + "tle6240.OUT9", "tle6240.OUT10", "tle6240.OUT11", "tle6240.OUT12", + "tle6240.OUT13", "tle6240.OUT14", "tle6240.OUT15", "tle6240.OUT16", +}; + /*==========================================================================*/ /* Driver local functions. */ /*==========================================================================*/ @@ -456,6 +463,7 @@ struct gpiochip_ops tle6240_ops = { int tle6240_add(unsigned int index, const struct tle6240_config *cfg) { int i; + int ret; struct tle6240_priv *chip; /* no config or no such chip */ @@ -485,7 +493,12 @@ int tle6240_add(unsigned int index, const struct tle6240_config *cfg) chip->drv_state = TLE6240_WAIT_INIT; /* register, return gpio chip base */ - return gpiochip_register(DRIVER_NAME, &tle6240_ops, TLE6240_OUTPUTS, chip); + ret = gpiochip_register(DRIVER_NAME, &tle6240_ops, TLE6240_OUTPUTS, chip); + + /* set default pin names, board init code can rewrite */ + gpiochips_setPinNames(ret, tle6240_pin_names); + + return ret; } #else /* BOARD_TLE6240_COUNT > 0 */ diff --git a/firmware/hw_layer/io_pins.cpp b/firmware/hw_layer/io_pins.cpp index 54e71cd1ca..a41a261e26 100644 --- a/firmware/hw_layer/io_pins.cpp +++ b/firmware/hw_layer/io_pins.cpp @@ -12,6 +12,7 @@ #if EFI_PROD_CODE #include "io_pins.h" #include "efi_gpio.h" +#include "drivers/gpio/gpio_ext.h" #include "pin_repository.h" #include "status_loop.h" @@ -40,29 +41,48 @@ ioportid_t getHwPort(const char *msg, brain_pin_e brainPin) { } bool efiReadPin(brain_pin_e pin) { - return palReadPad(getHwPort("readPin", pin), getHwPin("readPin", pin)); + if (brain_pin_is_onchip(pin)) + return palReadPad(getHwPort("readPin", pin), getHwPin("readPin", pin)); + #if (BOARD_EXT_GPIOCHIPS > 0) + else if (brain_pin_is_ext(pin)) + return (gpiochips_readPad(pin) > 0); + #endif + + /* incorrect pin */ + return false; } /** * This method would set an error condition if pin is already used */ -void efiSetPadMode(const char *msg, brain_pin_e brainPin, iomode_t mode) { - ioportid_t port = getHwPort(msg, brainPin); - ioportmask_t pin = getHwPin(msg, brainPin); +void efiSetPadMode(const char *msg, brain_pin_e brainPin, iomode_t mode) +{ + bool wasUsed; - if (port == GPIO_NULL) { - return; + //efiAssertVoid(OBD_PCM_Processor_Fault, pin != EFI_ERROR_CODE, "pin_error"); + + scheduleMsg(&logger, "%s on %s", msg, getBrain_pin_e(brainPin)); + + wasUsed = brain_pin_markUsed(brainPin, msg); + + if (!wasUsed) { + /*check if on-chip pin or external */ + if (brain_pin_is_onchip(brainPin)) { + /* on-cip */ + ioportid_t port = getHwPort(msg, brainPin); + ioportmask_t pin = getHwPin(msg, brainPin); + /* paranoid */ + if (port == GPIO_NULL) + return; + + palSetPadMode(port, pin, mode); + } + #if (BOARD_EXT_GPIOCHIPS > 0) + else { + gpiochips_setPadMode(brainPin, mode); + } + #endif } - efiAssertVoid(OBD_PCM_Processor_Fault, pin != EFI_ERROR_CODE, "pin_error"); - - scheduleMsg(&logger, "%s on %s%d", msg, portname(port), pin); - - bool wasUsed = gpio_pin_markUsed(port, pin, msg); - if (wasUsed) { - return; - } - - palSetPadMode(port, pin, mode); } iomode_t getInputMode(pin_input_mode_e mode) { diff --git a/firmware/hw_layer/pin_repository.cpp b/firmware/hw_layer/pin_repository.cpp index 70493f3229..e4a41a8d5b 100644 --- a/firmware/hw_layer/pin_repository.cpp +++ b/firmware/hw_layer/pin_repository.cpp @@ -15,6 +15,11 @@ #include "eficonsole.h" #include "memstreams.h" #include "chprintf.h" +#include "drivers/gpio/gpio_ext.h" + +#ifndef BOARD_EXT_PINREPOPINS + #define BOARD_EXT_PINREPOPINS 0 +#endif static ioportid_t ports[] = {GPIOA, GPIOB, @@ -44,7 +49,7 @@ static ioportid_t ports[] = {GPIOA, #define PIN_REPO_SIZE (sizeof(ports) / sizeof(ports[0])) * PORT_SIZE // todo: move this into PinRepository class -const char *PIN_USED[PIN_REPO_SIZE]; +const char *PIN_USED[PIN_REPO_SIZE + BOARD_EXT_PINREPOPINS]; static int initialized = FALSE; static LoggingWithStorage logger("pin repos"); @@ -110,15 +115,38 @@ static void reportPins(void) { unsigned int i; for (i = 0; i < PIN_REPO_SIZE; i++) { - const char *name = PIN_USED[i]; - int portIndex = i / PORT_SIZE; - int pin = i % PORT_SIZE; - ioportid_t port = ports[portIndex]; - if (name != NULL) { - scheduleMsg(&logger, "pin %s%d: %s", portname(port), pin, name); + const char *pin_user = PIN_USED[i]; + + /* show used pins */ + if (pin_user != NULL) { + int portIndex = i / PORT_SIZE; + int pin = i % PORT_SIZE; + ioportid_t port = ports[portIndex]; + + scheduleMsg(&logger, "pin %s%d: %s\n", portname(port), pin, pin_user); } } + #if (BOARD_EXT_GPIOCHIPS > 0) + for (i = PIN_REPO_SIZE ; i < PIN_REPO_SIZE + BOARD_EXT_PINREPOPINS /* gpiochips_get_total_pins()*/ ; i++) { + const char *pin_name; + const char *pin_user; + brain_pin_e brainPin = index_to_brainPin(i); + + pin_name = gpiochips_getPinName(brainPin); + pin_user = PIN_USED[i]; + + /* here show all pins, unused too */ + if (pin_name != NULL) { + scheduleMsg(&logger, "ext %s: %s\n", + pin_name, pin_user ? pin_user : "free"); + } else { + scheduleMsg(&logger, "ext %s.%d: %s\n", + gpiochips_getChipName(brainPin), gpiochips_getPinOffset(brainPin), pin_user ? pin_user : "free"); + } + } + #endif + scheduleMsg(&logger, "Total pins count: %d", totalPinsUsed); } @@ -155,14 +183,25 @@ const char *hwPortname(brain_pin_e brainPin) { if (brainPin == GPIO_INVALID) { return "INVALID"; } - ioportid_t hwPort = getHwPort("hostname", brainPin); - if (hwPort == GPIO_NULL) { - return "NONE"; - } - int hwPin = getHwPin("hostname", brainPin); portNameStream.eos = 0; // reset - chprintf((BaseSequentialStream *) &portNameStream, "%s%d", portname(hwPort), hwPin); + if (brain_pin_is_onchip(brainPin)) { + int hwPin; + + ioportid_t hwPort = getHwPort("hostname", brainPin); + if (hwPort == GPIO_NULL) { + return "NONE"; + } + hwPin = getHwPin("hostname", brainPin); + chprintf((BaseSequentialStream *) &portNameStream, "%s%d", portname(hwPort), hwPin); + } + #if (BOARD_EXT_GPIOCHIPS > 0) + else { + chprintf((BaseSequentialStream *) &portNameStream, "ext:%s.%d (%s)", + gpiochips_getChipName(brainPin), gpiochips_getPinOffset(brainPin), gpiochips_getPinName(brainPin)); + } + #endif portNameStream.buffer[portNameStream.eos] = 0; // need to terminate explicitly + return portNameBuffer; } @@ -176,6 +215,12 @@ void initPinRepository(void) { memset(PIN_USED, 0, sizeof(PIN_USED)); initialized = true; + + #if (BOARD_EXT_GPIOCHIPS > 0) + /* external chip init */ + gpiochips_init(); + #endif + addConsoleAction("pins", reportPins); }