This commit is contained in:
Andreika 2024-11-07 15:44:08 +02:00 committed by GitHub
parent 0a0ff11d5a
commit 7bd44fbfa3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 334 additions and 0 deletions

View File

@ -253,6 +253,10 @@
#define BOARD_TLE9104_COUNT 0
#endif
#ifndef BOARD_TLE9201_COUNT
#define BOARD_TLE9201_COUNT 0
#endif
#define EFI_ANALOG_SENSORS TRUE
#ifndef EFI_MAX_31855

View File

@ -31,6 +31,7 @@ HW_LAYER_DRIVERS_CPP = \
$(DRIVERS_DIR)/gpio/mc33810.cpp \
$(DRIVERS_DIR)/gpio/drv8860.cpp \
$(DRIVERS_DIR)/gpio/tle9104.cpp \
$(DRIVERS_DIR)/gpio/tle9201.cpp \
$(DRIVERS_DIR)/gpio/l9779.cpp \
$(DRIVERS_DIR)/gpio/protected_gpio.cpp \
$(DRIVERS_DIR)/sent/sent_hw_icu.cpp \

View File

@ -0,0 +1,291 @@
/*
* tle9201.c
*
* TLE9201 H-Bridge with SPI
*
* @date Nov 1, 2024
*
* @author andreika, (c) 2024
* @author Andrey Belomutskiy, (c) 2012-2024
*/
#include "pch.h"
#include "gpio/gpio_ext.h"
#include "gpio/tle9201.h"
#if EFI_PROD_CODE && (BOARD_TLE9201_COUNT > 0)
/*==========================================================================*/
/* Driver local definitions. */
/*==========================================================================*/
#define DRIVER_NAME "tle9201"
#define TLE9201_REG_RD_DIA 0x00 // read diagnosis register
#define TLE9201_REG_RES_DIA 0x80 // reset diagnosis register
#define TLE9201_REG_RD_REV 0x20 // read device revision number
#define TLE9201_REG_RD_CTRL 0x60 // read control register
#define TLE9201_REG_WR_CTRL 0xE0 // write control register
#define TLE9201_REG_WR_CTRL_RD_DIA 0xC0 // write control and read diagnosis
#define TLE9201_REV_MAJOR_MASK 0xF0
#define TLE9201_REV_MAJOR 0x20
#define TLE9201_DIAG_CL (1<<4) // over current
#define TLE9201_DIAG_TV (1<<5) // transmission validation
#define TLE9201_DIAG_OT (1<<6) // over temperature
#define TLE9201_DIAG_EN (1<<7) // outputs enabled
#define TLE9201_DIAG_OUT_MASK 0xf // bits 0..3
#define TLE9201_GET_VAL(rx) ((rx) & 0xff)
static bool drv_task_ready = false;
typedef enum {
TLE9201_DISABLED = 0,
TLE9201_READY,
TLE9201_FAILED
} tle9201_drv_state;
/*==========================================================================*/
/* Driver exported variables. */
/*==========================================================================*/
/*==========================================================================*/
/* Driver local variables and types. */
/*==========================================================================*/
// Output states
static const char *diagDiaOut[16] = { "?", "?", "?",
"VS Undervoltage", // 0x3
"?",
"Short to Bat at OUT1 and OUT2", // 0x5
"Short to GND at OUT1, short to Bat at OUT2", // 0x6
"Short to Bat at OUT2", // 0x7
"?",
"Short to Bat at OUT1, short to GND at OUT2", // 0x9
"Short to GND at OUT1 and OUT2", // 0xA
"Short to GND at OUT2", // 0xB
"Open Load", // 0xC
"Short to Bat at OUT1", // 0xD
"Short to GND at OUT1", // 0xE
"No failure" // 0xF
};
/* OS */
SEMAPHORE_DECL(tle9201_wake, 10 /* or BOARD_TLE9201_COUNT ? */);
static THD_WORKING_AREA(tle9201_thread_1_wa, 256);
/* Driver */
struct Tle9201 {
int init(int i);
int spi_rw(uint16_t tx, uint16_t *rx);
int read_reg(uint8_t addr, uint8_t *val);
bool get_diag_and_rev(uint8_t *diag, uint8_t *rev);
void process_diag_and_rev(uint8_t diag, uint8_t rev);
const tle9201_config *cfg = NULL;
tle9201_drv_state drv_state;
int idx;
int detectedRev = 0;
uint8_t savedDiag = 0;
char name[10];
};
static Tle9201 chips[BOARD_TLE9201_COUNT];
/*==========================================================================*/
/* Driver local functions. */
/*==========================================================================*/
/**
* @brief TLE9201 send+receive routine.
*/
int Tle9201::spi_rw(uint16_t tx, uint16_t *rx) {
SPIDriver *spi = cfg->spi_bus;
/* Acquire ownership of the bus. */
spiAcquireBus(spi);
/* Setup transfer parameters. */
spiStart(spi, &cfg->spi_config);
/* Slave Select assertion. */
spiSelect(spi);
/* Atomic transfer operations. */
uint16_t rxd = spiPolledExchange(spi, tx);
/* Slave Select de-assertion. */
spiUnselect(spi);
/* Ownership release. */
spiReleaseBus(spi);
// return data
if (rx) {
*rx = rxd;
}
return 0;
}
int Tle9201::read_reg(uint8_t addr, uint8_t *val) {
int ret;
ret = spi_rw(addr, nullptr);
if (ret) {
return ret;
}
uint16_t rxd;
ret = spi_rw(addr, &rxd);
if (ret) {
return ret;
}
if (val) {
*val = TLE9201_GET_VAL(rxd);
}
return 0;
}
bool Tle9201::get_diag_and_rev(uint8_t *diag, uint8_t *rev) {
int retDiag = read_reg(TLE9201_REG_RD_DIA, diag);
int retRev = read_reg(TLE9201_REG_RD_REV, rev);
return (retDiag == 0 && retRev == 0);
}
void Tle9201::process_diag_and_rev(uint8_t diag, uint8_t rev) {
// react on revision change
if (rev != detectedRev) {
if ((rev & TLE9201_REV_MAJOR_MASK) == TLE9201_REV_MAJOR) {
efiPrintf("%s Detected! (rev=%08x)", name, rev);
} else {
efiPrintf("%s ERROR: Unknown revision (%08x)!", name, rev);
}
detectedRev = rev;
}
// react on diagnosis byte change
if (diag != savedDiag) {
efiPrintf("%s Diag (%08x):", name, diag);
// this bit should be always 0
if (diag & TLE9201_DIAG_TV) {
efiPrintf("* Diag status incorrect!");
}
// these bits are 0 if something happened
if (!(diag & TLE9201_DIAG_CL)) {
efiPrintf("* Overcurrent shutdown!");
}
if (!(diag & TLE9201_DIAG_OT)) {
efiPrintf("* Overtemperature shutdown!");
}
if (!(diag & TLE9201_DIAG_EN)) {
efiPrintf("* Outputs disabled.");
}
// print the status of the outputs
efiPrintf("* %s", diagDiaOut[diag & TLE9201_DIAG_OUT_MASK]);
savedDiag = diag;
}
}
/*==========================================================================*/
/* Driver thread. */
/*==========================================================================*/
static THD_FUNCTION(tle9201_driver_thread, p) {
int i;
bool wasSpiFailure = false;
(void)p;
chRegSetThreadName(DRIVER_NAME);
while (1) {
chThdSleepMilliseconds(TLE9201_POLL_INTERVAL_MS);
for (i = 0; i < BOARD_TLE9201_COUNT; i++) {
auto chip = &chips[i];
if ((chip->cfg == NULL) ||
(chip->drv_state == TLE9201_DISABLED) ||
(chip->drv_state == TLE9201_FAILED))
continue;
uint8_t diag, rev;
// get diagnosis and revision bytes
if (!chip->get_diag_and_rev(&diag, &rev)) {
if (!wasSpiFailure) {
efiPrintf("%s ERROR: SPI failure!", chip->name);
wasSpiFailure = true;
}
} else {
wasSpiFailure = false;
}
chip->process_diag_and_rev(diag, rev);
}
}
}
/*==========================================================================*/
/* Driver interrupt handlers. */
/*==========================================================================*/
/*==========================================================================*/
/* Driver exported functions. */
/*==========================================================================*/
int Tle9201::init(int i) {
drv_state = TLE9201_READY;
idx = i;
sprintf(name, "TLE9201[%d]", idx);
if (!drv_task_ready) {
chThdCreateStatic(tle9201_thread_1_wa, sizeof(tle9201_thread_1_wa),
PRIO_GPIOCHIP, tle9201_driver_thread, NULL);
drv_task_ready = true;
}
return 0;
}
/**
* @brief TLE9201 driver add.
* @details Checks for valid config
*/
int tle9201_add(unsigned int index, const tle9201_config *cfg) {
/* no config or no such chip */
if ((!cfg) || (!cfg->spi_bus) || (index >= BOARD_TLE9201_COUNT))
return -1;
/* check for valid cs.
* TODO: remove this check? CS can be driven by SPI */
//if (cfg->spi_config.ssport == NULL)
// return -1;
auto& chip = chips[index];
/* already initted? */
if (chip.cfg != NULL)
return -1;
chip.cfg = cfg;
chip.init(index);
return 0;
}
#else /* BOARD_TLE9201_COUNT > 0 */
int tle9201_add(unsigned int index, const tle9201_config *cfg) {
(void)index; (void)cfg;
return -1;
}
#endif /* BOARD_TLE9201_COUNT */

View File

@ -0,0 +1,37 @@
/*
* tle9201.h
*
* TLE9201 H-Bridge with SPI
*
* @date Nov 1, 2024
*
* @author andreika, (c) 2024
* @author Andrey Belomutskiy, (c) 2012-2024
*/
#pragma once
#include "efifeatures.h"
#include <hal.h>
// 10 Hz
#define TLE9201_POLL_INTERVAL_MS 100
// used by tle9201_config.spi_config.cr1 & .cr2
#define TLE9201_CONFIG_CR1 (\
SPI_CR1_8BIT_MODE | \
SPI_CR1_SSM | \
SPI_CR1_SSI | \
((0b110 << SPI_CR1_BR_Pos) & SPI_CR1_BR) | \
SPI_CR1_MSTR | \
SPI_CR1_CPHA)
#define TLE9201_CONFIG_CR2 (SPI_CR2_8BIT_MODE)
struct tle9201_config {
#if HAL_USE_SPI
SPIDriver *spi_bus;
SPIConfig spi_config;
#endif
};
int tle9201_add(unsigned int index, const struct tle9201_config *cfg);

View File

@ -12,6 +12,7 @@
#include "drivers/gpio/tle6240.h"
#include "drivers/gpio/mc33972.h"
#include "drivers/gpio/tle8888.h"
#include "drivers/gpio/tle9201.h"
#include "drivers/gpio/drv8860.h"
#include "drivers/gpio/can_gpio_msiobox.h"
// we seem OK without L9779 here do we need those includes at all?