TLE8888: initial support (#733)
This commit is contained in:
parent
6531c0c6de
commit
fde76155f2
|
@ -9,8 +9,7 @@ HW_LAYER_DRIVERS_CORE = \
|
||||||
|
|
||||||
HW_LAYER_DRIVERS = \
|
HW_LAYER_DRIVERS = \
|
||||||
$(DRIVERS_DIR)/gpio/tle6240.c \
|
$(DRIVERS_DIR)/gpio/tle6240.c \
|
||||||
|
$(DRIVERS_DIR)/gpio/tle8888.c
|
||||||
|
|
||||||
|
HW_LAYER_DRIVERS_CPP =
|
||||||
|
|
||||||
HW_LAYER_DRIVERS_CPP = \
|
|
||||||
$(DRIVERS_DIR)/gpio/tle8888.cpp \
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,290 @@
|
||||||
|
/*
|
||||||
|
* tle8888.c
|
||||||
|
*
|
||||||
|
* TLE8888 Engine Machine System IC driver
|
||||||
|
*
|
||||||
|
* @date Mar 25, 2019
|
||||||
|
* @author Andrey Belomutskiy, (c) 2012-2019
|
||||||
|
*
|
||||||
|
* Andrey Gusakov, (c) 2019
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* to be removed */
|
||||||
|
#include "engine_configuration.h"
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
#include "gpio/gpio_ext.h"
|
||||||
|
#include "gpio/tle8888.h"
|
||||||
|
#include "pin_repository.h"
|
||||||
|
|
||||||
|
/* TODO: move to board.h file */
|
||||||
|
#define BOARD_TLE8888_COUNT 1
|
||||||
|
|
||||||
|
#ifndef BOARD_TLE8888_COUNT
|
||||||
|
#define BOARD_TLE8888_COUNT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (BOARD_TLE8888_COUNT > 0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO list:
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*==========================================================================*/
|
||||||
|
/* Driver local definitions. */
|
||||||
|
/*==========================================================================*/
|
||||||
|
|
||||||
|
#define DRIVER_NAME "tle8888"
|
||||||
|
|
||||||
|
/*==========================================================================*/
|
||||||
|
/* Driver exported variables. */
|
||||||
|
/*==========================================================================*/
|
||||||
|
|
||||||
|
/* C0 */
|
||||||
|
#define CMD_READ (0 << 0)
|
||||||
|
#define CMD_WRITE (1 << 0)
|
||||||
|
/* C7:1 */
|
||||||
|
#define CMD_REG_ADDR(a) (((a) & 0x7f) << 1)
|
||||||
|
/* CD7:0 */
|
||||||
|
#define CMD_REG_DATA(d) (((d) & 0xff) << 8)
|
||||||
|
|
||||||
|
#define CMD_WR(a, d) (CMD_WRITE | CMD_REG_ADDR(a) | CMD_REG_DATA(d))
|
||||||
|
|
||||||
|
#define CMD_SR CMD_WR(0x1a, 0x03)
|
||||||
|
#define CMD_OE_SET CMD_WR(0x1c, 0x02)
|
||||||
|
#define CMD_OE_CLR CMD_WR(0x1c, 0x01)
|
||||||
|
#define CMD_LOCK CMD_WR(0x1e, 0x02)
|
||||||
|
#define CMD_UNLOCK CMD_WR(0x1e, 0x01)
|
||||||
|
#define CMD_INCONFIG(n, d) CMD_WR(0x53 + (n & 0x03), d)
|
||||||
|
#define CMD_DDCONFIG(n, d) CMD_WR(0x57 + (n & 0x03), d)
|
||||||
|
#define CMD_OECONFIG(n, d) CMD_WR(0x5b + (n & 0x03), d)
|
||||||
|
|
||||||
|
/*==========================================================================*/
|
||||||
|
/* Driver local variables and types. */
|
||||||
|
/*==========================================================================*/
|
||||||
|
|
||||||
|
/* Driver private data */
|
||||||
|
struct tle8888_priv {
|
||||||
|
const struct tle8888_config *cfg;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct tle8888_priv chips[BOARD_TLE8888_COUNT];
|
||||||
|
|
||||||
|
/*==========================================================================*/
|
||||||
|
/* Driver local functions. */
|
||||||
|
/*==========================================================================*/
|
||||||
|
|
||||||
|
static SPIDriver *get_bus(struct tle8888_priv *chip)
|
||||||
|
{
|
||||||
|
/* return non-const SPIDriver* from const struct cfg */
|
||||||
|
return chip->cfg->spi_bus;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tle8888_spi_rw(struct tle8888_priv *chip, uint16_t tx, uint16_t *rx)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint16_t rxb;
|
||||||
|
SPIDriver *spi = get_bus(chip);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 15.1 SPI Protocol
|
||||||
|
*
|
||||||
|
* after a read or write command: the address and content of the selected register
|
||||||
|
* is transmitted with the next SPI transmission (for not existing addresses or
|
||||||
|
* wrong access mode the data is always 0)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Acquire ownership of the bus. */
|
||||||
|
spiAcquireBus(spi);
|
||||||
|
/* Setup transfer parameters. */
|
||||||
|
spiStart(spi, &chip->cfg->spi_config);
|
||||||
|
/* Slave Select assertion. */
|
||||||
|
spiSelect(spi);
|
||||||
|
/* Atomic transfer operations. */
|
||||||
|
rxb = spiPolledExchange(spi, tx);
|
||||||
|
/* Slave Select de-assertion. */
|
||||||
|
spiUnselect(spi);
|
||||||
|
/* Ownership release. */
|
||||||
|
spiReleaseBus(spi);
|
||||||
|
|
||||||
|
if (rx)
|
||||||
|
*rx = rxb;
|
||||||
|
|
||||||
|
/* no errors for now */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*==========================================================================*/
|
||||||
|
/* Driver thread. */
|
||||||
|
/*==========================================================================*/
|
||||||
|
|
||||||
|
/*==========================================================================*/
|
||||||
|
/* Driver interrupt handlers. */
|
||||||
|
/*==========================================================================*/
|
||||||
|
|
||||||
|
/*==========================================================================*/
|
||||||
|
/* Driver exported functions. */
|
||||||
|
/*==========================================================================*/
|
||||||
|
|
||||||
|
int tle8888_chip_init(void * data)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int ret;
|
||||||
|
struct tle8888_priv *chip = (struct tle8888_priv *)data;
|
||||||
|
const struct tle8888_config *cfg = chip->cfg;
|
||||||
|
uint8_t dd[4] = {0, 0, 0, 0};
|
||||||
|
uint8_t oe[4] = {0, 0, 0, 0};
|
||||||
|
|
||||||
|
/* mark pins used */
|
||||||
|
ret = markUsed(cfg->spi_config.ssport, cfg->spi_config.sspad, DRIVER_NAME " CS");
|
||||||
|
if (cfg->reset.port != NULL)
|
||||||
|
ret |= markUsed(cfg->reset.port, cfg->reset.pad, DRIVER_NAME " RST");
|
||||||
|
for (i = 0; i < TLE8888_DIRECT_OUTPUTS; i++)
|
||||||
|
if (cfg->direct_io[i].port)
|
||||||
|
ret |= markUsed(cfg->direct_io[i].port, cfg->direct_io[i].pad, DRIVER_NAME " DIRECT IO");
|
||||||
|
if (ret) {
|
||||||
|
ret = -1;
|
||||||
|
goto err_gpios;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Software reset */
|
||||||
|
tle8888_spi_rw(chip, CMD_SR, NULL);
|
||||||
|
|
||||||
|
/* delay? */
|
||||||
|
|
||||||
|
/* Set LOCK bit to 0 */
|
||||||
|
tle8888_spi_rw(chip, CMD_UNLOCK, NULL);
|
||||||
|
|
||||||
|
/* enable direct drive of OUTPUT4..1
|
||||||
|
* ...still need INJEN signal */
|
||||||
|
dd[0] |= 0x0f;
|
||||||
|
oe[0] |= 0x0f;
|
||||||
|
/* enable direct drive of IGN4..1
|
||||||
|
* ...still need IGNEN signal */
|
||||||
|
dd[3] |= 0x0f;
|
||||||
|
oe[3] |= 0x0f;
|
||||||
|
|
||||||
|
/* map and enable outputs for direct driven channels */
|
||||||
|
for (i = 0; i < TLE8888_DIRECT_MISC; i++) {
|
||||||
|
int reg;
|
||||||
|
int mask;
|
||||||
|
int out = cfg->direct_map[i];
|
||||||
|
|
||||||
|
/* OUT1..4 driven direct only */
|
||||||
|
if (out < 5)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
reg = (out - 1)/ 8;
|
||||||
|
mask = 1 << ((out - 1) % 8);
|
||||||
|
|
||||||
|
/* check if output already ocupied */
|
||||||
|
if (dd[reg] & mask) {
|
||||||
|
/* incorrect config? */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable direct drive and output enable */
|
||||||
|
dd[reg] |= mask;
|
||||||
|
oe[reg] |= mask;
|
||||||
|
|
||||||
|
tle8888_spi_rw(chip, CMD_INCONFIG(reg, out - 5), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set registers */
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
tle8888_spi_rw(chip, CMD_OECONFIG(i, oe[i]), NULL);
|
||||||
|
tle8888_spi_rw(chip, CMD_DDCONFIG(i, dd[i]), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable outputs */
|
||||||
|
tle8888_spi_rw(chip, CMD_OE_SET, NULL);
|
||||||
|
|
||||||
|
err_gpios:
|
||||||
|
/* unmark pins */
|
||||||
|
markUnused(cfg->spi_config.ssport, cfg->spi_config.sspad);
|
||||||
|
if (cfg->reset.port != NULL)
|
||||||
|
markUnused(cfg->reset.port, cfg->reset.pad);
|
||||||
|
for (i = 0; i < TLE8888_DIRECT_OUTPUTS; i++)
|
||||||
|
if (cfg->direct_io[i].port)
|
||||||
|
markUnused(cfg->direct_io[i].port, cfg->direct_io[i].pad);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief TLE8888 driver add.
|
||||||
|
* @details Checks for valid config
|
||||||
|
*/
|
||||||
|
|
||||||
|
int tle8888_add(unsigned int index, const struct tle8888_config *cfg)
|
||||||
|
{
|
||||||
|
struct tle8888_priv *chip;
|
||||||
|
|
||||||
|
/* no config or no such chip */
|
||||||
|
osalDbgCheck((cfg != NULL) && (cfg->spi_bus != NULL) && (index < BOARD_TLE8888_COUNT));
|
||||||
|
|
||||||
|
/* check for valid cs.
|
||||||
|
* DOTO: remove this check? CS can be driven by SPI */
|
||||||
|
if (cfg->spi_config.ssport == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
chip = &chips[index];
|
||||||
|
|
||||||
|
/* already initted? */
|
||||||
|
if (chip->cfg != NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* TODO: remove this when gpiochips integrated */
|
||||||
|
return tle8888_chip_init(chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* BOARD_TLE8888_COUNT > 0 */
|
||||||
|
|
||||||
|
int tle8888_add(unsigned int index, const struct tle8888_config *cfg)
|
||||||
|
{
|
||||||
|
(void)index; (void)cfg;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* BOARD_TLE8888_COUNT */
|
||||||
|
|
||||||
|
/*********TO BE REMOVED FROM THIS FILE***************/
|
||||||
|
|
||||||
|
/* this should be in board file */
|
||||||
|
static const struct tle8888_config tle8888_cfg = {
|
||||||
|
.spi_bus = &SPID4,
|
||||||
|
.spi_config = {
|
||||||
|
.circular = false,
|
||||||
|
.end_cb = NULL,
|
||||||
|
.ssport = GPIOF,
|
||||||
|
.sspad = 0U,
|
||||||
|
.cr1 =
|
||||||
|
/* TODO: set LSB first mode !!!! */
|
||||||
|
/* SPI_CR1_CPOL | */ // = 0
|
||||||
|
SPI_CR1_CPHA | // = 1
|
||||||
|
(((3 << SPI_CR1_BR_Pos) & SPI_CR1_BR) |
|
||||||
|
SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_MSTR),
|
||||||
|
/* 16-bit transfer */
|
||||||
|
.cr2 = SPI_CR2_DS_3 | SPI_CR2_DS_2 | SPI_CR2_DS_1 | SPI_CR2_DS_0
|
||||||
|
},
|
||||||
|
/* not implemented yet, use STM32 gpios directly */
|
||||||
|
.direct_io = {
|
||||||
|
[0] = {.port = NULL},
|
||||||
|
[1] = {.port = NULL},
|
||||||
|
[2] = {.port = NULL},
|
||||||
|
[3] = {.port = NULL},
|
||||||
|
},
|
||||||
|
.direct_map = {
|
||||||
|
/* to be fixed */
|
||||||
|
9, 10, 11, 12
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void initTle8888(DECLARE_ENGINE_PARAMETER_SIGNATURE)
|
||||||
|
{
|
||||||
|
tle8888_add(0, &tle8888_cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********TO BE REMOVED FROM THIS FILE ENDS***********/
|
|
@ -1,86 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* TLE8888 driver
|
|
||||||
*
|
|
||||||
* at the moment only Enable Outputs is implemented - this command is needed to get parallel control pins
|
|
||||||
*
|
|
||||||
* @date Mar 25, 2019
|
|
||||||
* @author Andrey Belomutskiy, (c) 2012-2019
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "engine.h"
|
|
||||||
#include "tle8888.h"
|
|
||||||
#include "hardware.h"
|
|
||||||
|
|
||||||
#if EFI_TLE8888 || defined(__DOXYGEN__)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 15.2 SPI Frame Definition
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#define Cmd_write_access 1
|
|
||||||
#define CmdOE 0x1C
|
|
||||||
#define DATA_OE_ENABLE 0b00000010
|
|
||||||
|
|
||||||
static unsigned char tx_buff[2];
|
|
||||||
static unsigned char rx_buff[2];
|
|
||||||
|
|
||||||
extern TunerStudioOutputChannels tsOutputChannels;
|
|
||||||
|
|
||||||
EXTERN_ENGINE;
|
|
||||||
|
|
||||||
static SPIDriver *driver;
|
|
||||||
|
|
||||||
static OutputPin tle8888Cs;
|
|
||||||
|
|
||||||
static SPIConfig spiConfig = { /* end_cb */ NULL,
|
|
||||||
/* HW dependent part.*/
|
|
||||||
/* ssport */ NULL, /* sspad */ 0, /* cr1 */ SPI_CR1_MSTR | SPI_CR1_CPHA, /* cr2*/ 0 };
|
|
||||||
|
|
||||||
void initTle8888(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|
||||||
if (engineConfiguration->tle8888_cs == GPIO_UNASSIGNED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// SPI pins are enabled in initSpiModules()
|
|
||||||
tle8888Cs.initPin("tle8888 CS", engineConfiguration->tle8888_cs,
|
|
||||||
&engineConfiguration->tle8888_csPinMode);
|
|
||||||
|
|
||||||
spiConfig.cr1 += getSpiPrescaler(_150KHz, engineConfiguration->tle8888spiDevice);
|
|
||||||
|
|
||||||
driver = getSpiDevice(engineConfiguration->tle8888spiDevice);
|
|
||||||
if (driver == NULL) {
|
|
||||||
// error already reported
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// todo: reuse initSpiCs method?
|
|
||||||
spiConfig.ssport = getHwPort("tle8888", engineConfiguration->tle8888_cs);
|
|
||||||
spiConfig.sspad = getHwPin("tle8888", engineConfiguration->tle8888_cs);
|
|
||||||
|
|
||||||
spiStart(driver, &spiConfig);
|
|
||||||
|
|
||||||
tx_buff[0] = Cmd_write_access + CmdOE;
|
|
||||||
tx_buff[1] = DATA_OE_ENABLE;
|
|
||||||
// todo: extract 'sendSync' method?
|
|
||||||
spiSelect(driver);
|
|
||||||
spiSend(driver, 2, tx_buff);
|
|
||||||
if (engineConfiguration->debugMode == DBG_TLE8888) {
|
|
||||||
tsOutputChannels.debugIntField1 = 2;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 15.1 SPI Protocol
|
|
||||||
*
|
|
||||||
* after a read or write command: the address and content of the selected register
|
|
||||||
* is transmitted with the next SPI transmission (for not existing addresses or
|
|
||||||
* wrong access mode the data is always “0”)
|
|
||||||
*/
|
|
||||||
|
|
||||||
spiReceive(driver, 2, rx_buff);
|
|
||||||
|
|
||||||
if (engineConfiguration->debugMode == DBG_TLE8888) {
|
|
||||||
tsOutputChannels.debugIntField2 = (rx_buff[1] << 8) + rx_buff[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
spiUnselect(driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* EFI_TLE8888 */
|
|
|
@ -10,6 +10,49 @@
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
|
#include <hal.h>
|
||||||
|
|
||||||
|
#define TLE8888_OUTPUTS 20 /* ? */
|
||||||
|
/* 4 misc channels */
|
||||||
|
#define TLE8888_DIRECT_MISC 4
|
||||||
|
/* 4 IGN channels - INJ1..4 - IN1..4
|
||||||
|
* 4 INJ channels - OUT1..4 - IN5..8 */
|
||||||
|
#define TLE8888_DIRECT_OUTPUTS (4 + 4 + TLE8888_DIRECT_MISC)
|
||||||
|
|
||||||
|
/* DOTO: add irq support */
|
||||||
|
#define TLE8888_POLL_INTERVAL_MS 100
|
||||||
|
|
||||||
|
/* note that spi transfer should be LSB first */
|
||||||
|
struct tle8888_config {
|
||||||
|
SPIDriver *spi_bus;
|
||||||
|
const SPIConfig spi_config;
|
||||||
|
/* bidirectional, check DS */
|
||||||
|
struct {
|
||||||
|
ioportid_t port;
|
||||||
|
uint_fast8_t pad;
|
||||||
|
} reset;
|
||||||
|
/* currently not used.
|
||||||
|
* TODO: update as it is done in TLE6240 */
|
||||||
|
struct {
|
||||||
|
ioportid_t port;
|
||||||
|
uint_fast8_t pad;
|
||||||
|
} direct_io[TLE8888_DIRECT_MISC];
|
||||||
|
/* maping array for IN9..12, output numbers starts from 1, as in DS */
|
||||||
|
uint8_t direct_map[TLE8888_DIRECT_MISC];
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/* cleanup !!!! */
|
||||||
void initTle8888(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
void initTle8888(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
|
||||||
|
int tle8888_add(unsigned int index, const struct tle8888_config *cfg);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
#endif /* HW_LAYER_DRIVERS_GPIO_TLE8888_H_ */
|
#endif /* HW_LAYER_DRIVERS_GPIO_TLE8888_H_ */
|
||||||
|
|
Loading…
Reference in New Issue