L9779: initial driver (#3897)
* smart_gpio.cpp: glue to L9779 * L9779: fill with some code * L9779: missed getDiag * L9779: no l9779 on subaru-eg33 board
This commit is contained in:
parent
ba65d56563
commit
a50f848857
|
@ -22,6 +22,9 @@ DDEFS += -DHW_SUBARU_EG33=1
|
|||
# Override DEFAULT_ENGINE_TYPE
|
||||
DDEFS += -DDEFAULT_ENGINE_TYPE=SUBARUEG33_DEFAULTS
|
||||
|
||||
# HW options
|
||||
DDEFS += -DBOARD_L9779_COUNT=0
|
||||
|
||||
#Some options override
|
||||
#ICU vs PAL/EXTI
|
||||
DDEFS += -DHAL_TRIGGER_USE_PAL=TRUE
|
||||
|
|
|
@ -6,8 +6,295 @@
|
|||
|
||||
#include "pch.h"
|
||||
|
||||
#include "gpio/l9779.h"
|
||||
|
||||
#if (BOARD_L9779_COUNT > 0)
|
||||
|
||||
#include "persistent_configuration.h"
|
||||
#include "hardware.h"
|
||||
#include "gpio/gpio_ext.h"
|
||||
#include "os_util.h"
|
||||
/*
|
||||
* TODO list:
|
||||
* - just write code
|
||||
*/
|
||||
/*==========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*==========================================================================*/
|
||||
#define DRIVER_NAME "l9779"
|
||||
|
||||
/* SPI communication helpers */
|
||||
/* Out frame */
|
||||
/* D0 - parity */
|
||||
/* D8:D1 - DATA OUT or SUBADDRESS if ADD[4:0] = 0x10 (for read) */
|
||||
#define MSG_SET_DATA(d) (((d) & 0xff) << 1)
|
||||
/* sub-address is 5 bit */
|
||||
#define MSG_SET_SUBADDR(s) (((s) & 0x1f) << 1)
|
||||
/* D9 - x */
|
||||
/* D14:D10 - ADDRESS */
|
||||
#define MSG_SET_ADDR(a) (((a) & 0x1f) << 10)
|
||||
/* D15 - x */
|
||||
|
||||
/* In frame */
|
||||
/* D0 - parity */
|
||||
#define MSG_GET_PARITY(rx) (((rx) >> 0) & 0x01)
|
||||
/* D8:D1 - DATA IN */
|
||||
#define MSG_GET_DATA(rx) (((rx) >> 1) & 0xff)
|
||||
/* D 9 - W/R flag, 1 if we read */
|
||||
#define MSG_GET_WR(rx) (((rx) >> 9) & 0x01)
|
||||
/* D14:D10 - Addr of DATA IN */
|
||||
#define MSG_GET_ADDR(rx) (((rx) >> 10) & 0x1f)
|
||||
/* D15 - SPI error flag */
|
||||
#define MSG_GET_SPIERROR(rx) (((rx) >> 15) & 0x01)
|
||||
|
||||
/* register address that never can be replyed */
|
||||
#define REG_INVALID 0xff
|
||||
|
||||
/*==========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*==========================================================================*/
|
||||
|
||||
/*==========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*==========================================================================*/
|
||||
|
||||
/* Driver private data */
|
||||
struct L9779 : public GpioChip {
|
||||
int init() override;
|
||||
int deinit() override;
|
||||
|
||||
int setPadMode(size_t pin, iomode_t mode) override;
|
||||
int writePad(size_t pin, int value) override;
|
||||
int readPad(size_t pin) override;
|
||||
brain_pin_diag_e getDiag(size_t pin) override;
|
||||
|
||||
bool spi_parity_odd(uint16_t x);
|
||||
int spi_validate(uint16_t rx);
|
||||
int spi_rw(uint16_t tx, uint16_t *rx_ptr);
|
||||
|
||||
brain_pin_diag_e getOutputDiag(size_t pin);
|
||||
brain_pin_diag_e getInputDiag(size_t pin);
|
||||
|
||||
const l9779_config *cfg;
|
||||
|
||||
/* last accessed register, for validation on next SPI access */
|
||||
uint8_t last_reg;
|
||||
|
||||
/* statistic */
|
||||
//int por_cnt;
|
||||
//int wdr_cnt;
|
||||
//int comfe_cnt;
|
||||
//int init_cnt;
|
||||
//int init_req_cnt;
|
||||
int spi_cnt;
|
||||
int spi_err_parity; /* parity errors in rx data */
|
||||
int spi_err_frame; /* rx messages with bit 15 set */
|
||||
int spi_err; /* rx messages with incorrect ADDR or WR fields */
|
||||
uint16_t tx;
|
||||
uint16_t rx;
|
||||
};
|
||||
|
||||
static L9779 chips[BOARD_L9779_COUNT];
|
||||
|
||||
static const char* l9779_pin_names[L9779_SIGNALS] = {
|
||||
"L9779.IGN1", "L9779.IGN2", "L9779.IGN3", "L9779.IGN4",
|
||||
"L9779.OUT1", "L9779.OUT2", "L9779.OUT3", "L9779.OUT4",
|
||||
"L9779.OUT5", "L9779.OUT6", "L9779.OUT7", "L9779.OUT8",
|
||||
"L9779.OUT9", "L9779.OUT10", "L9779.OUT11", "L9779.OUT12",
|
||||
"L9779.OUT13", "L9779.OUT14", "L9779.OUT15", "L9779.OUT16",
|
||||
"L9779.OUT17", "L9779.OUT18", "L9779.OUT19", "L9779.OUT20",
|
||||
"L9779.OUTA", "L9779.OUTB", "L9779.OUTC", "L9779.OUTD",
|
||||
"L9779.OUT21", "L9779.OUT22", "L9779.OUT23", "L9779.OUT24",
|
||||
"L9779.MRD", "L9779.KEY"
|
||||
};
|
||||
|
||||
/*==========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*==========================================================================*/
|
||||
|
||||
/* true if parity of input x is odd */
|
||||
bool L9779::spi_parity_odd(uint16_t x)
|
||||
{
|
||||
x ^= x >> 8;
|
||||
x ^= x >> 4;
|
||||
x ^= x >> 2;
|
||||
x ^= x >> 1;
|
||||
|
||||
return (x & 1);
|
||||
}
|
||||
|
||||
int L9779::spi_validate(uint16_t rx)
|
||||
{
|
||||
if (!spi_parity_odd(rx)) {
|
||||
spi_err_parity++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (MSG_GET_SPIERROR(rx)) {
|
||||
/* not clear what does this means */
|
||||
spi_err_frame++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t reg = MSG_GET_DATA(rx);
|
||||
|
||||
/* TODO: also check WR bit */
|
||||
if ((last_reg != REG_INVALID) && (last_reg != reg)) {
|
||||
/* unexpected SPI answer */
|
||||
spi_err++;
|
||||
|
||||
/* should ve restart? */
|
||||
//need_init = true;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns -1 in case of communication error
|
||||
*/
|
||||
int L9779::spi_rw(uint16_t tx, uint16_t *rx_ptr)
|
||||
{
|
||||
int ret;
|
||||
uint16_t rx;
|
||||
SPIDriver *spi = cfg->spi_bus;
|
||||
|
||||
/* set parity */
|
||||
tx |= !spi_parity_odd(tx);
|
||||
|
||||
/* Acquire ownership of the bus. */
|
||||
spiAcquireBus(spi);
|
||||
/* Setup transfer parameters. */
|
||||
spiStart(spi, &cfg->spi_config);
|
||||
/* Slave Select assertion. */
|
||||
spiSelect(spi);
|
||||
/* Atomic transfer operations. */
|
||||
rx = spiPolledExchange(spi, tx);
|
||||
/* Slave Select de-assertion. */
|
||||
spiUnselect(spi);
|
||||
/* Ownership release. */
|
||||
spiReleaseBus(spi);
|
||||
|
||||
/* statisctic and debug */
|
||||
this->tx = tx;
|
||||
this->rx = rx;
|
||||
this->spi_cnt++;
|
||||
|
||||
if (rx_ptr)
|
||||
*rx_ptr = rx;
|
||||
|
||||
/* validate reply and save last accessed register */
|
||||
ret = spi_validate(rx);
|
||||
last_reg = MSG_GET_ADDR(tx);
|
||||
|
||||
/* no errors for now */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*==========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*==========================================================================*/
|
||||
/*==========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*==========================================================================*/
|
||||
|
||||
int L9779::setPadMode(unsigned int pin, iomode_t mode) {
|
||||
if (pin >= L9779_SIGNALS)
|
||||
return -1;
|
||||
|
||||
(void)mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int L9779::writePad(unsigned int pin, int value) {
|
||||
if (pin >= L9779_OUTPUTS)
|
||||
return -1;
|
||||
|
||||
(void)value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
brain_pin_diag_e L9779::getOutputDiag(size_t pin)
|
||||
{
|
||||
(void)pin;
|
||||
|
||||
return PIN_OK;
|
||||
}
|
||||
|
||||
brain_pin_diag_e L9779::getInputDiag(unsigned int pin)
|
||||
{
|
||||
(void)pin;
|
||||
|
||||
return PIN_OK;
|
||||
}
|
||||
|
||||
int L9779::readPad(size_t pin) {
|
||||
if (pin >= L9779_SIGNALS)
|
||||
return -1;
|
||||
|
||||
/* unknown pin */
|
||||
return -1;
|
||||
}
|
||||
|
||||
brain_pin_diag_e L9779::getDiag(size_t pin)
|
||||
{
|
||||
if (pin >= TLE8888_SIGNALS)
|
||||
return PIN_INVALID;
|
||||
|
||||
if (pin < L9779_OUTPUTS)
|
||||
return getOutputDiag(pin);
|
||||
else
|
||||
return getInputDiag(pin);
|
||||
}
|
||||
|
||||
int L9779::init()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int L9779::deinit()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief L9779 driver add.
|
||||
* @details Checks for valid config
|
||||
* @return return gpio chip base
|
||||
*/
|
||||
|
||||
int l9779_add(brain_pin_e base, unsigned int index, const l9779_config *cfg) {
|
||||
|
||||
efiAssert(OBD_PCM_Processor_Fault, cfg != NULL, "L9779CFG", 0)
|
||||
|
||||
/* no config or no such chip */
|
||||
if ((!cfg) || (!cfg->spi_bus) || (index >= BOARD_L9779_COUNT))
|
||||
return -1;
|
||||
|
||||
L9779* chip = &chips[index];
|
||||
|
||||
/* already initted? */
|
||||
if (chip->cfg)
|
||||
return -1;
|
||||
|
||||
/* config */
|
||||
chip->cfg = cfg;
|
||||
/* reset to defaults */
|
||||
|
||||
|
||||
/* register */
|
||||
int ret = gpiochip_register(base, DRIVER_NAME, *chip, L9779_SIGNALS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* set default pin names, board init code can rewrite */
|
||||
gpiochips_setPinNames(base, l9779_pin_names);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* (BOARD_L9779_COUNT > 0) */
|
||||
|
||||
|
||||
|
|
|
@ -8,11 +8,22 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "efifeatures.h"
|
||||
#include "global.h"
|
||||
|
||||
#include <hal.h>
|
||||
#include "efifeatures.h"
|
||||
|
||||
struct l9779_config {
|
||||
#if HAL_USE_SPI
|
||||
SPIDriver *spi_bus;
|
||||
SPIConfig spi_config;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define L9779_OUTPUTS_IGN (4)
|
||||
#define L9779_OUTPUTS (L9779_OUTPUTS_IGN + 28 + 1)
|
||||
#define L9779_INPUTS (1)
|
||||
|
||||
#define L9779_SIGNALS (L9779_OUTPUTS + L9779_INPUTS)
|
||||
|
||||
int l9779_add(brain_pin_e base, unsigned int index, const l9779_config *cfg);
|
||||
|
|
|
@ -100,8 +100,23 @@ struct mc33972_config mc33972 = {
|
|||
static OutputPin l9779Cs;
|
||||
struct l9779_config l9779_cfg = {
|
||||
.spi_bus = NULL,
|
||||
.spi_config = {
|
||||
.circular = false,
|
||||
.end_cb = NULL,
|
||||
.ssport = NULL,
|
||||
.sspad = 0,
|
||||
.cr1 =
|
||||
SPI_CR1_16BIT_MODE |
|
||||
SPI_CR1_SSM |
|
||||
SPI_CR1_SSI |
|
||||
//SPI_CR1_LSBFIRST | //MSB first
|
||||
((3 << SPI_CR1_BR_Pos) & SPI_CR1_BR) | // div = 16, up to 8 MHz
|
||||
SPI_CR1_MSTR |
|
||||
SPI_CR1_CPHA |
|
||||
0,
|
||||
.cr2 = SPI_CR2_16BIT_MODE
|
||||
},
|
||||
};
|
||||
|
||||
#endif /* (BOARD_L9779_COUNT > 0) */
|
||||
|
||||
#if (BOARD_TLE8888_COUNT > 0)
|
||||
|
@ -206,6 +221,19 @@ void initSmartGpio() {
|
|||
}
|
||||
#endif /* (BOARD_MC33972_COUNT > 0) */
|
||||
|
||||
#if (BOARD_L9779_COUNT > 0)
|
||||
if (isBrainPinValid(engineConfiguration->l9779_cs)) {
|
||||
// todo: reuse initSpiCs method?
|
||||
l9779_cfg.spi_config.ssport = getHwPort("l9779 CS", engineConfiguration->l9779_cs);
|
||||
l9779_cfg.spi_config.sspad = getHwPin("l9779 CS", engineConfiguration->l9779_cs);
|
||||
l9779_cfg.spi_bus = getSpiDevice(engineConfiguration->l9779spiDevice);
|
||||
// todo: propogate 'basePinOffset' parameter
|
||||
int ret = l9779_add(L9779_IGN_1, 0, &l9779_cfg);
|
||||
|
||||
efiAssertVoid(OBD_PCM_Processor_Fault, ret == L9779_IGN_1, "l9779");
|
||||
}
|
||||
#endif /* (BOARD_L9779_COUNT > 0) */
|
||||
|
||||
#if (BOARD_TLE8888_COUNT > 0)
|
||||
if (isBrainPinValid(engineConfiguration->tle8888_cs)) {
|
||||
// todo: reuse initSpiCs method?
|
||||
|
|
Loading…
Reference in New Issue