convert gpiochips to c++ (#2761)

* core

* basic header

* tests are happy

* tle6240

* tle8888

* 33972

* 33810

* tle8888_req_init

* unused warning

* warning

* unsigned

* 8888 debug

* fix

* don't qualify

Co-authored-by: Matthew Kennedy <makenne@microsoft.com>
This commit is contained in:
Matthew Kennedy 2021-06-10 01:11:01 -07:00 committed by GitHub
parent e82e5bcb84
commit a54a5e7f90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 591 additions and 745 deletions

View File

@ -32,12 +32,10 @@
struct gpiochip { struct gpiochip {
brain_pin_e base; brain_pin_e base;
size_t size; size_t size;
gpiochip_ops *ops; GpioChip *chip;
const char *name; const char *name;
/* optional names of each gpio */ /* optional names of each gpio */
const char **gpio_names; const char **gpio_names;
/* private driver data passed to ops */
void *priv;
}; };
static gpiochip chips[BOARD_EXT_GPIOCHIPS]; static gpiochip chips[BOARD_EXT_GPIOCHIPS];
@ -58,7 +56,7 @@ static gpiochip *gpiochip_find(brain_pin_e pin)
return chip; return chip;
} }
return NULL; return nullptr;
} }
/*==========================================================================*/ /*==========================================================================*/
@ -92,7 +90,7 @@ const char *gpiochips_getChipName(brain_pin_e pin) {
if (chip) if (chip)
return chip->name; return chip->name;
return NULL; return nullptr;
} }
/** /**
@ -111,7 +109,7 @@ const char *gpiochips_getPinName(brain_pin_e pin)
return chip->gpio_names[offset]; return chip->gpio_names[offset];
} }
return NULL; return nullptr;
} }
/** /**
@ -123,24 +121,18 @@ const char *gpiochips_getPinName(brain_pin_e pin)
* else returns chip base * else returns chip base
*/ */
int gpiochip_register(brain_pin_e base, const char *name, gpiochip_ops *ops, size_t size, void *priv) int gpiochip_register(brain_pin_e base, const char *name, GpioChip& gpioChip, size_t size)
{ {
int i; /* zero size? */
if (!size)
/* no ops provided, zero size? */
if ((!ops) || (!size))
return -1; return -1;
/* outside? */ /* outside? */
if (((size_t)base + size - 1 > BRAIN_PIN_LAST) || (base <= BRAIN_PIN_ONCHIP_LAST)) if (((size_t)base + size - 1 > BRAIN_PIN_LAST) || (base <= BRAIN_PIN_ONCHIP_LAST))
return -1; return -1;
/* no 'writePad' and no 'readPad' implementation? return error code */
if ((!ops->writePad) && (!ops->readPad))
return -1;
/* check for overlap with other chips */ /* check for overlap with other chips */
for (i = 0; i < BOARD_EXT_GPIOCHIPS; i++) { for (int i = 0; i < BOARD_EXT_GPIOCHIPS; i++) {
if (chips[i].base != 0) { if (chips[i].base != 0) {
#define in_range(a, b, c) (((a) > (b)) && ((a) < (c))) #define in_range(a, b, c) (((a) > (b)) && ((a) < (c)))
if (in_range(base, chips[i].base, chips[i].base + chips[i].size)) if (in_range(base, chips[i].base, chips[i].base + chips[i].size))
@ -150,9 +142,10 @@ int gpiochip_register(brain_pin_e base, const char *name, gpiochip_ops *ops, siz
} }
} }
gpiochip *chip = NULL; gpiochip *chip = nullptr;
/* find free gpiochip struct */ /* find free gpiochip struct */
for (i = 0; i < BOARD_EXT_GPIOCHIPS; i++) { for (int i = 0; i < BOARD_EXT_GPIOCHIPS; i++) {
if (chips[i].base == 0) { if (chips[i].base == 0) {
chip = &chips[i]; chip = &chips[i];
break; break;
@ -166,13 +159,12 @@ int gpiochip_register(brain_pin_e base, const char *name, gpiochip_ops *ops, siz
/* register chip */ /* register chip */
chip->name = name; chip->name = name;
chip->ops = ops; chip->chip = &gpioChip;
chip->base = base; chip->base = base;
chip->size = size; chip->size = size;
chip->gpio_names = NULL; chip->gpio_names = nullptr;
chip->priv = priv;
return (chip->base); return base;
} }
@ -194,12 +186,11 @@ int gpiochip_unregister(brain_pin_e base)
return -1; return -1;
/* unregister chip */ /* unregister chip */
chip->name = NULL; chip->name = nullptr;
chip->ops = NULL; chip->chip = nullptr;
chip->base = GPIO_UNASSIGNED; chip->base = GPIO_UNASSIGNED;
chip->size = 0; chip->size = 0;
chip->gpio_names = NULL; chip->gpio_names = nullptr;
chip->priv = NULL;
return 0; return 0;
} }
@ -230,20 +221,15 @@ int gpiochips_setPinNames(brain_pin_e base, const char **names)
int gpiochips_init(void) int gpiochips_init(void)
{ {
int i;
int ret = -1;
int pins_added = 0; int pins_added = 0;
for (i = 0; i < BOARD_EXT_GPIOCHIPS; i++) { for (int i = 0; i < BOARD_EXT_GPIOCHIPS; i++) {
gpiochip *chip = &chips[i]; gpiochip *chip = &chips[i];
if (!chip->base) if (!chip->base)
continue; continue;
if (chip->ops->init) if (chip->chip->init() < 0) {
ret = chip->ops->init(chip->priv);
if (ret < 0) {
/* remove chip if it fails to init */ /* remove chip if it fails to init */
/* TODO: we will have a gap, is it ok? */ /* TODO: we will have a gap, is it ok? */
chip->base = GPIO_UNASSIGNED; chip->base = GPIO_UNASSIGNED;
@ -270,10 +256,7 @@ int gpiochips_setPadMode(brain_pin_e pin, iomode_t mode)
if (!chip) if (!chip)
return -1; return -1;
if ((chip->ops->setPadMode)) return chip->chip->setPadMode(pin - chip->base, mode);
return chip->ops->setPadMode(chip->priv, pin - chip->base, mode);
return -1;
} }
/** /**
@ -292,10 +275,7 @@ int gpiochips_writePad(brain_pin_e pin, int value)
if (!chip) if (!chip)
return -1; return -1;
if (chip->ops->writePad) return chip->chip->writePad(pin - chip->base, value);
return chip->ops->writePad(chip->priv, pin - chip->base, value);
return -1;
} }
/** /**
@ -313,10 +293,7 @@ int gpiochips_readPad(brain_pin_e pin)
if (!chip) if (!chip)
return -1; return -1;
if (chip->ops->readPad) return chip->chip->readPad(pin - chip->base);
return chip->ops->readPad(chip->priv, pin - chip->base);
return -1;
} }
/** /**
@ -334,10 +311,7 @@ brain_pin_diag_e gpiochips_getDiag(brain_pin_e pin)
if (!chip) if (!chip)
return PIN_INVALID; return PIN_INVALID;
if (chip->ops->getDiag) return chip->chip->getDiag(pin - chip->base);
return chip->ops->getDiag(chip->priv, pin - chip->base);
return PIN_OK;
} }
/** /**
@ -374,18 +348,18 @@ int gpiochips_getPinOffset(brain_pin_e pin) {
const char *gpiochips_getChipName(brain_pin_e pin) { const char *gpiochips_getChipName(brain_pin_e pin) {
(void)pin; (void)pin;
return NULL; return nullptr;
} }
const char *gpiochips_getPinName(brain_pin_e pin) { const char *gpiochips_getPinName(brain_pin_e pin) {
(void)pin; (void)pin;
return NULL; return nullptr;
} }
int gpiochip_register(brain_pin_e base, const char *name, gpiochip_ops *ops, size_t size, void *priv) int gpiochip_register(brain_pin_e base, const char *name, GpioChip&, size_t size)
{ {
(void)base; (void)name; (void)ops; (void)size; (void)priv; (void)base; (void)name; (void)size;
return 0; return 0;
} }

View File

@ -49,7 +49,20 @@ SEMAPHORE_DECL(drv8860_wake, 10 /* or BOARD_DRV8860_COUNT ? */);
static THD_WORKING_AREA(drv8860_thread_1_wa, 256); static THD_WORKING_AREA(drv8860_thread_1_wa, 256);
/* Driver */ /* Driver */
struct drv8860_priv { struct Drv8860 : public GpioChip {
int init() override;
int writePad(size_t pin, int value) override;
brain_pin_diag_e getDiag(size_t pin) override;
// Internal helpers
int chip_init();
void spi_send(uint16_t tx);
void update_outputs();
int wake_driver();
const drv8860_config *cfg; const drv8860_config *cfg;
/* cached output state - state last send to chip */ /* cached output state - state last send to chip */
uint16_t o_state_cached; uint16_t o_state_cached;
@ -59,7 +72,7 @@ struct drv8860_priv {
drv8860_drv_state drv_state; drv8860_drv_state drv_state;
}; };
static drv8860_priv chips[BOARD_DRV8860_COUNT]; static Drv8860 chips[BOARD_DRV8860_COUNT];
static const char* drv8860_pin_names[DRV8860_OUTPUTS] = { static const char* drv8860_pin_names[DRV8860_OUTPUTS] = {
"drv8860.OUT1", "drv8860.OUT2", "drv8860.OUT3", "drv8860.OUT4", "drv8860.OUT1", "drv8860.OUT2", "drv8860.OUT3", "drv8860.OUT4",
@ -72,23 +85,18 @@ static const char* drv8860_pin_names[DRV8860_OUTPUTS] = {
/* Driver local functions. */ /* Driver local functions. */
/*==========================================================================*/ /*==========================================================================*/
static SPIDriver *get_bus(drv8860_priv *chip) {
/* return non-const SPIDriver* from const struct cfg */
return chip->cfg->spi_bus;
}
/** /**
* @brief DRV8860 send routine. * @brief DRV8860 send routine.
* @details Sends 8/16 bits. CS asserted before and released after transaction. * @details Sends 8/16 bits. CS asserted before and released after transaction.
*/ */
static void drv8860_spi_send(drv8860_priv *chip, uint16_t tx) { void Drv8860::spi_send(uint16_t tx) {
SPIDriver *spi = get_bus(chip); SPIDriver *spi = cfg->spi_bus;
/* Acquire ownership of the bus. */ /* Acquire ownership of the bus. */
spiAcquireBus(spi); spiAcquireBus(spi);
/* Setup transfer parameters. */ /* Setup transfer parameters. */
spiStart(spi, &chip->cfg->spi_config); spiStart(spi, &cfg->spi_config);
/* Slave Select assertion. */ /* Slave Select assertion. */
spiSelect(spi); spiSelect(spi);
/* Atomic transfer operations. */ /* Atomic transfer operations. */
@ -103,16 +111,16 @@ static void drv8860_spi_send(drv8860_priv *chip, uint16_t tx) {
* @brief DRV8860 send output data. * @brief DRV8860 send output data.
*/ */
static void drv8860_update_outputs(drv8860_priv *chip) { void Drv8860::update_outputs() {
/* TODO: lock? */ /* TODO: lock? */
/* atomic */ /* atomic */
/* set value only for non-direct driven pins */ /* set value only for non-direct driven pins */
drv8860_spi_send(chip, chip->o_state & 0xffff); spi_send(o_state & 0xffff);
/* atomic */ /* atomic */
chip->o_state_cached = chip->o_state; o_state_cached = o_state;
/* TODO: unlock? */ /* TODO: unlock? */
} }
@ -122,9 +130,9 @@ static void drv8860_update_outputs(drv8860_priv *chip) {
* @todo: Checks direct io signals integrity, read initial diagnostic state. * @todo: Checks direct io signals integrity, read initial diagnostic state.
*/ */
static int drv8860_chip_init(drv8860_priv *chip) { int Drv8860::chip_init() {
/* upload pin states */ /* upload pin states */
drv8860_update_outputs(chip); update_outputs();
return 0; return 0;
} }
@ -134,14 +142,11 @@ static int drv8860_chip_init(drv8860_priv *chip) {
* @details Wake up driver. Will cause output register update. * @details Wake up driver. Will cause output register update.
*/ */
static int drv8860_wake_driver(drv8860_priv *chip) { int Drv8860::wake_driver() {
(void)chip; /* Entering a reentrant critical zone.*/
chibios_rt::CriticalSectionLocker csl;
/* Entering a reentrant critical zone.*/
syssts_t sts = chSysGetStatusAndLockX();
chSemSignalI(&drv8860_wake); chSemSignalI(&drv8860_wake);
/* Leaving the critical zone.*/
chSysRestoreStatusX(sts);
return 0; return 0;
} }
@ -165,15 +170,13 @@ static THD_FUNCTION(drv8860_driver_thread, p) {
(void)msg; (void)msg;
for (i = 0; i < BOARD_DRV8860_COUNT; i++) { for (i = 0; i < BOARD_DRV8860_COUNT; i++) {
drv8860_priv *chip; auto chip = &chips[i];
chip = &chips[i];
if ((chip->cfg == NULL) || if ((chip->cfg == NULL) ||
(chip->drv_state == DRV8860_DISABLED) || (chip->drv_state == DRV8860_DISABLED) ||
(chip->drv_state == DRV8860_FAILED)) (chip->drv_state == DRV8860_FAILED))
continue; continue;
drv8860_update_outputs(chip); chip->update_outputs();
} }
} }
} }
@ -188,41 +191,34 @@ static THD_FUNCTION(drv8860_driver_thread, p) {
/* Driver exported functions. */ /* Driver exported functions. */
/*==========================================================================*/ /*==========================================================================*/
int drv8860_writePad(void *data, unsigned int pin, int value) { int Drv8860::writePad(size_t pin, int value) {
drv8860_priv *chip; if (pin >= DRV8860_OUTPUTS)
if ((pin >= DRV8860_OUTPUTS) || (data == NULL))
return -1; return -1;
chip = (drv8860_priv *)data;
/* TODO: lock */ /* TODO: lock */
if (value) if (value)
chip->o_state |= (1 << pin); o_state |= (1 << pin);
else else
chip->o_state &= ~(1 << pin); o_state &= ~(1 << pin);
/* TODO: unlock */ /* TODO: unlock */
drv8860_wake_driver(chip); wake_driver();
return 0; return 0;
} }
brain_pin_diag_e drv8860_getDiag(void* /*data*/, unsigned int /*pin*/) { brain_pin_diag_e Drv8860::getDiag(size_t /*pin*/) {
// todo: implement diag // todo: implement diag
return PIN_OK; return PIN_OK;
} }
int drv8860_init(void * data) { int Drv8860::init() {
int ret; int ret;
drv8860_priv *chip;
chip = (drv8860_priv *)data; ret = chip_init();
ret = drv8860_chip_init(chip);
if (ret) if (ret)
return ret; return ret;
chip->drv_state = DRV8860_READY; drv_state = DRV8860_READY;
if (!drv_task_ready) { if (!drv_task_ready) {
chThdCreateStatic(drv8860_thread_1_wa, sizeof(drv8860_thread_1_wa), chThdCreateStatic(drv8860_thread_1_wa, sizeof(drv8860_thread_1_wa),
@ -233,22 +229,6 @@ int drv8860_init(void * data) {
return 0; return 0;
} }
int drv8860_deinit(void *data) {
(void)data;
/* TODO: set all pins to inactive state, stop task? */
return 0;
}
struct gpiochip_ops drv8860_ops = {
.setPadMode = nullptr,
.writePad = drv8860_writePad,
.readPad = NULL, /* chip outputs only */
.getDiag = drv8860_getDiag,
.init = drv8860_init,
.deinit = drv8860_deinit,
};
/** /**
* @brief DRV8860 driver add. * @brief DRV8860 driver add.
* @details Checks for valid config * @details Checks for valid config
@ -256,7 +236,6 @@ struct gpiochip_ops drv8860_ops = {
int drv8860_add(brain_pin_e base, unsigned int index, const drv8860_config *cfg) { int drv8860_add(brain_pin_e base, unsigned int index, const drv8860_config *cfg) {
int ret; int ret;
drv8860_priv *chip;
/* no config or no such chip */ /* no config or no such chip */
if ((!cfg) || (!cfg->spi_bus) || (index >= BOARD_DRV8860_COUNT)) if ((!cfg) || (!cfg->spi_bus) || (index >= BOARD_DRV8860_COUNT))
@ -267,19 +246,19 @@ int drv8860_add(brain_pin_e base, unsigned int index, const drv8860_config *cfg)
//if (cfg->spi_config.ssport == NULL) //if (cfg->spi_config.ssport == NULL)
// return -1; // return -1;
chip = &chips[index]; auto& chip = chips[index];
/* already initted? */ /* already initted? */
if (chip->cfg != NULL) if (!chip.cfg)
return -1; return -1;
chip->cfg = cfg; chip.cfg = cfg;
chip->o_state = 0; chip.o_state = 0;
chip->o_state_cached = 0; chip.o_state_cached = 0;
chip->drv_state = DRV8860_WAIT_INIT; chip.drv_state = DRV8860_WAIT_INIT;
/* register, return gpio chip base */ /* register, return gpio chip base */
ret = gpiochip_register(base, DRIVER_NAME, &drv8860_ops, DRV8860_OUTPUTS, chip); ret = gpiochip_register(base, DRIVER_NAME, chip, DRV8860_OUTPUTS);
if (ret < 0) if (ret < 0)
return ret; return ret;

View File

@ -19,14 +19,16 @@
/* Checks */ /* Checks */
/*==========================================================================*/ /*==========================================================================*/
struct gpiochip_ops { struct GpioChip {
virtual int init() = 0;
// These functions need not be implemented if not supported by the particular chip.
/* pin argument is pin number within gpio chip, not a global number */ /* pin argument is pin number within gpio chip, not a global number */
int (*setPadMode)(void *data, unsigned int pin, iomode_t mode); virtual int setPadMode(size_t /*pin*/, iomode_t /*mode*/) { return -1; }
int (*writePad)(void *data, unsigned int pin, int value); virtual int writePad(size_t /*pin*/, int /*value*/) { return -1; }
int (*readPad)(void *data, unsigned int pin); virtual int readPad(size_t /*pin*/) { return -1; }
brain_pin_diag_e (*getDiag)(void *data, unsigned int pin); virtual brain_pin_diag_e getDiag(size_t /*pin*/) { return PIN_OK; }
int (*init)(void *data); virtual int deinit() { return 0; }
int (*deinit)(void *data);
}; };
int gpiochips_getPinOffset(brain_pin_e pin); int gpiochips_getPinOffset(brain_pin_e pin);
@ -34,7 +36,7 @@ const char *gpiochips_getChipName(brain_pin_e pin);
const char *gpiochips_getPinName(brain_pin_e pin); const char *gpiochips_getPinName(brain_pin_e pin);
/* register/unregister GPIO chip */ /* register/unregister GPIO chip */
int gpiochip_register(brain_pin_e base, const char *name, gpiochip_ops *ops, size_t size, void *priv); int gpiochip_register(brain_pin_e base, const char *name, GpioChip& chip, size_t size);
int gpiochip_unregister(brain_pin_e base); int gpiochip_unregister(brain_pin_e base);
/* Set individual names for pins */ /* Set individual names for pins */

View File

@ -90,7 +90,22 @@ SEMAPHORE_DECL(mc33810_wake, 10 /* or BOARD_MC33810_COUNT ? */);
static THD_WORKING_AREA(mc33810_thread_1_wa, 256); static THD_WORKING_AREA(mc33810_thread_1_wa, 256);
/* Driver */ /* Driver */
struct mc33810_priv { struct Mc33810 : public GpioChip {
int init() override;
int writePad(size_t pin, int value) override;
brain_pin_diag_e getDiag(size_t pin) override;
// internal functions
int spi_rw(uint16_t tx, uint16_t* rx);
int update_output_and_diag();
int chip_init();
void wake_driver();
const mc33810_config *cfg; const mc33810_config *cfg;
/* cached output state - state last send to chip */ /* cached output state - state last send to chip */
uint8_t o_state_cached; uint8_t o_state_cached;
@ -114,7 +129,7 @@ struct mc33810_priv {
mc33810_drv_state drv_state; mc33810_drv_state drv_state;
}; };
static mc33810_priv chips[BOARD_MC33810_COUNT]; static Mc33810 chips[BOARD_MC33810_COUNT];
static const char* mc33810_pin_names[MC33810_OUTPUTS] = { static const char* mc33810_pin_names[MC33810_OUTPUTS] = {
"mc33810.OUT1", "mc33810.OUT2", "mc33810.OUT3", "mc33810.OUT4", "mc33810.OUT1", "mc33810.OUT2", "mc33810.OUT3", "mc33810.OUT4",
@ -125,27 +140,21 @@ static const char* mc33810_pin_names[MC33810_OUTPUTS] = {
/* Driver local functions. */ /* Driver local functions. */
/*==========================================================================*/ /*==========================================================================*/
static SPIDriver *get_bus(mc33810_priv *chip)
{
/* return non-const SPIDriver* from const struct cfg */
return chip->cfg->spi_bus;
}
/** /**
* @brief MC33810 send and receive routine. * @brief MC33810 send and receive routine.
* @details Sends and receives 16 bits. CS asserted before and released * @details Sends and receives 16 bits. CS asserted before and released
* after transaction. * after transaction.
*/ */
static int mc33810_spi_rw(mc33810_priv *chip, uint16_t tx, uint16_t *rx) int Mc33810::spi_rw(uint16_t tx, uint16_t *rx)
{ {
uint16_t rxb; uint16_t rxb;
SPIDriver *spi = get_bus(chip); SPIDriver *spi = cfg->spi_bus;
/* Acquire ownership of the bus. */ /* Acquire ownership of the bus. */
spiAcquireBus(spi); spiAcquireBus(spi);
/* Setup transfer parameters. */ /* Setup transfer parameters. */
spiStart(spi, &chip->cfg->spi_config); spiStart(spi, &cfg->spi_config);
/* Slave Select assertion. */ /* Slave Select assertion. */
spiSelect(spi); spiSelect(spi);
/* Atomic transfer operations. */ /* Atomic transfer operations. */
@ -161,13 +170,13 @@ static int mc33810_spi_rw(mc33810_priv *chip, uint16_t tx, uint16_t *rx)
*rx = rxb; *rx = rxb;
/* if reply on previous command is ALL STATUS RESPONSE */ /* if reply on previous command is ALL STATUS RESPONSE */
if (chip->all_status_requested) { if (all_status_requested) {
chip->all_status_value = rxb; all_status_value = rxb;
chip->all_status_updated = true; all_status_updated = true;
} }
/* if next reply will be ALL STATUS RESPONSE */ /* if next reply will be ALL STATUS RESPONSE */
chip->all_status_requested = all_status_requested =
(((TX_GET_CMD(tx) >= 0x1) && (TX_GET_CMD(tx) <= 0xa)) || (((TX_GET_CMD(tx) >= 0x1) && (TX_GET_CMD(tx) <= 0xa)) ||
(tx == MC_CMD_READ_REG(REG_ALL_STAT))); (tx == MC_CMD_READ_REG(REG_ALL_STAT)));
@ -180,74 +189,74 @@ static int mc33810_spi_rw(mc33810_priv *chip, uint16_t tx, uint16_t *rx)
* @details Sends ORed data to register, also receive diagnostic. * @details Sends ORed data to register, also receive diagnostic.
*/ */
static int mc33810_update_output_and_diag(mc33810_priv *chip) int Mc33810::update_output_and_diag()
{ {
int ret = 0; int ret = 0;
/* TODO: lock? */ /* TODO: lock? */
/* we need to get updates status */ /* we need to get updates status */
chip->all_status_updated = false; all_status_updated = false;
/* if any pin is driven over SPI */ /* if any pin is driven over SPI */
if (chip->o_direct_mask != 0xff) { if (o_direct_mask != 0xff) {
uint16_t out_data; uint16_t out_data;
out_data = chip->o_state & (~chip->o_direct_mask); out_data = o_state & (~o_direct_mask);
ret = mc33810_spi_rw(chip, MC_CMD_DRIVER_EN(out_data), NULL); ret = spi_rw(MC_CMD_DRIVER_EN(out_data), NULL);
if (ret) if (ret)
return ret; return ret;
chip->o_state_cached = chip->o_state; o_state_cached = o_state;
} }
/* this comlicated logic to save few spi transfers in case we will receive status as reply on other command */ /* this comlicated logic to save few spi transfers in case we will receive status as reply on other command */
if (!chip->all_status_requested) { if (!all_status_requested) {
ret = mc33810_spi_rw(chip, MC_CMD_READ_REG(REG_ALL_STAT), NULL); ret = spi_rw(MC_CMD_READ_REG(REG_ALL_STAT), NULL);
if (ret) if (ret)
return ret; return ret;
} }
/* get reply */ /* get reply */
if (!chip->all_status_updated) { if (!all_status_updated) {
ret = mc33810_spi_rw(chip, MC_CMD_READ_REG(REG_ALL_STAT), NULL); ret = spi_rw(MC_CMD_READ_REG(REG_ALL_STAT), NULL);
if (ret) if (ret)
return ret; return ret;
} }
/* now we have updated ALL STATUS register in chip data */ /* now we have updated ALL STATUS register in chip data */
/* check OUT (injectors) first */ /* check OUT (injectors) first */
if (chip->all_status_value & 0x000f) { if (all_status_value & 0x000f) {
/* request diagnostic of OUT0 and OUT1 */ /* request diagnostic of OUT0 and OUT1 */
ret = mc33810_spi_rw(chip, MC_CMD_READ_REG(REG_OUT10_FAULT), NULL); ret = spi_rw(MC_CMD_READ_REG(REG_OUT10_FAULT), NULL);
if (ret) if (ret)
return ret; return ret;
/* get diagnostic for OUT0 and OUT1 and request diagnostic for OUT2 and OUT3 */ /* get diagnostic for OUT0 and OUT1 and request diagnostic for OUT2 and OUT3 */
ret = mc33810_spi_rw(chip, MC_CMD_READ_REG(REG_OUT32_FAULT), &chip->out_fault[0]); ret = spi_rw(MC_CMD_READ_REG(REG_OUT32_FAULT), &out_fault[0]);
if (ret) if (ret)
return ret; return ret;
/* get diagnostic for OUT2 and OUT2 and requset ALL STATUS */ /* get diagnostic for OUT2 and OUT2 and requset ALL STATUS */
ret = mc33810_spi_rw(chip, MC_CMD_READ_REG(REG_ALL_STAT), &chip->out_fault[1]); ret = spi_rw(MC_CMD_READ_REG(REG_ALL_STAT), &out_fault[1]);
if (ret) if (ret)
return ret; return ret;
} }
/* check GPGD - mode not supported yet */ /* check GPGD - mode not supported yet */
if (chip->all_status_value & 0x00f0) { if (all_status_value & 0x00f0) {
/* request diagnostic of GPGD */ /* request diagnostic of GPGD */
ret = mc33810_spi_rw(chip, MC_CMD_READ_REG(REG_GPGD_FAULT), NULL); ret = spi_rw(MC_CMD_READ_REG(REG_GPGD_FAULT), NULL);
if (ret) if (ret)
return ret; return ret;
/* get diagnostic for GPGD and requset ALL STATUS */ /* get diagnostic for GPGD and requset ALL STATUS */
ret = mc33810_spi_rw(chip, MC_CMD_READ_REG(REG_ALL_STAT), &chip->gpgd_fault); ret = spi_rw(MC_CMD_READ_REG(REG_ALL_STAT), &gpgd_fault);
if (ret) if (ret)
return ret; return ret;
} }
/* check IGN */ /* check IGN */
if (chip->all_status_value & 0x0f00) { if (all_status_value & 0x0f00) {
/* request diagnostic of IGN */ /* request diagnostic of IGN */
ret = mc33810_spi_rw(chip, MC_CMD_READ_REG(REG_IGN_FAULT), NULL); ret = spi_rw(MC_CMD_READ_REG(REG_IGN_FAULT), NULL);
if (ret) if (ret)
return ret; return ret;
/* get diagnostic for IGN and requset ALL STATUS */ /* get diagnostic for IGN and requset ALL STATUS */
ret = mc33810_spi_rw(chip, MC_CMD_READ_REG(REG_ALL_STAT), &chip->ign_fault); ret = spi_rw(MC_CMD_READ_REG(REG_ALL_STAT), &ign_fault);
if (ret) if (ret)
return ret; return ret;
} }
@ -262,12 +271,11 @@ static int mc33810_update_output_and_diag(mc33810_priv *chip)
* @details Checks communication. Check chip presense. * @details Checks communication. Check chip presense.
*/ */
static int mc33810_chip_init(mc33810_priv *chip) int Mc33810::chip_init()
{ {
int n; int n;
int ret; int ret;
uint16_t rx; uint16_t rx;
const mc33810_config *cfg = chip->cfg;
/* mark pins used */ /* mark pins used */
//ret = gpio_pin_markUsed(cfg->spi_config.ssport, cfg->spi_config.sspad, DRIVER_NAME " CS"); //ret = gpio_pin_markUsed(cfg->spi_config.ssport, cfg->spi_config.sspad, DRIVER_NAME " CS");
@ -289,9 +297,9 @@ static int mc33810_chip_init(mc33810_priv *chip)
/* check SPI communication */ /* check SPI communication */
/* 0. set echo mode, chip number - don't care */ /* 0. set echo mode, chip number - don't care */
ret = mc33810_spi_rw(chip, MC_CMD_SPI_CHECK, NULL); ret = spi_rw(MC_CMD_SPI_CHECK, NULL);
/* 1. check loopback */ /* 1. check loopback */
ret |= mc33810_spi_rw(chip, MC_CMD_READ_REG(REG_REV), &rx); ret |= spi_rw(MC_CMD_READ_REG(REG_REV), &rx);
if (ret) { if (ret) {
ret = -1; ret = -1;
goto err_gpios; goto err_gpios;
@ -303,7 +311,7 @@ static int mc33810_chip_init(mc33810_priv *chip)
} }
/* 2. read revision */ /* 2. read revision */
ret = mc33810_spi_rw(chip, MC_CMD_READ_REG(REG_ALL_STAT), &rx); ret = spi_rw(MC_CMD_READ_REG(REG_ALL_STAT), &rx);
if (ret) { if (ret) {
ret = -1; ret = -1;
goto err_gpios; goto err_gpios;
@ -328,12 +336,12 @@ static int mc33810_chip_init(mc33810_priv *chip)
(3 << 2) | /* Open Secondary OSFLT = 100 uS, default */ (3 << 2) | /* Open Secondary OSFLT = 100 uS, default */
(1 << 0) | /* End Spark THreshold: VPWR +5.5V, defaul */ (1 << 0) | /* End Spark THreshold: VPWR +5.5V, defaul */
0; 0;
ret = mc33810_spi_rw(chip, MC_CMD_SPARK(spark_settings), NULL); ret = spi_rw(MC_CMD_SPARK(spark_settings), NULL);
if (ret) { if (ret) {
goto err_gpios; goto err_gpios;
} }
ret = mc33810_spi_rw(chip, MC_CMD_MODE_SELECT(0xf << 8), NULL); ret = spi_rw(MC_CMD_MODE_SELECT(0xf << 8), NULL);
if (ret) { if (ret) {
goto err_gpios; goto err_gpios;
} }
@ -372,10 +380,8 @@ err_gpios:
* diagnostic update. * diagnostic update.
*/ */
static int mc33810_wake_driver(mc33810_priv *chip) void Mc33810::wake_driver()
{ {
(void)chip;
/* Entering a reentrant critical zone.*/ /* Entering a reentrant critical zone.*/
chibios_rt::CriticalSectionLocker csl; chibios_rt::CriticalSectionLocker csl;
chSemSignalI(&mc33810_wake); chSemSignalI(&mc33810_wake);
@ -386,8 +392,6 @@ static int mc33810_wake_driver(mc33810_priv *chip)
*/ */
chSchRescheduleS(); chSchRescheduleS();
} }
return 0;
} }
/*==========================================================================*/ /*==========================================================================*/
@ -410,17 +414,15 @@ static THD_FUNCTION(mc33810_driver_thread, p)
(void)msg; (void)msg;
for (i = 0; i < BOARD_MC33810_COUNT; i++) { for (i = 0; i < BOARD_MC33810_COUNT; i++) {
int ret; auto chip = &chips[i];
mc33810_priv *chip;
chip = &chips[i];
if ((chip->cfg == NULL) || if ((chip->cfg == NULL) ||
(chip->drv_state == MC33810_DISABLED) || (chip->drv_state == MC33810_DISABLED) ||
(chip->drv_state == MC33810_FAILED)) (chip->drv_state == MC33810_FAILED))
continue; continue;
/* TODO: implemet indirect driven gpios */ /* TODO: implemet indirect driven gpios */
ret = mc33810_update_output_and_diag(chip); int ret = chip->update_output_and_diag();
if (ret) { if (ret) {
/* set state to MC33810_FAILED? */ /* set state to MC33810_FAILED? */
} }
@ -438,54 +440,49 @@ static THD_FUNCTION(mc33810_driver_thread, p)
/* Driver exported functions. */ /* Driver exported functions. */
/*==========================================================================*/ /*==========================================================================*/
int mc33810_writePad(void *data, unsigned int pin, int value) int Mc33810::writePad(size_t pin, int value)
{ {
if ((pin >= MC33810_OUTPUTS) || !data) { if (pin >= MC33810_OUTPUTS){
return -1; return -1;
} }
auto chip = (mc33810_priv*)data;
{ {
// mutate driver state under lock // mutate driver state under lock
chibios_rt::CriticalSectionLocker csl; chibios_rt::CriticalSectionLocker csl;
if (value) if (value)
chip->o_state |= BIT(pin); o_state |= BIT(pin);
else else
chip->o_state &= ~BIT(pin); o_state &= ~BIT(pin);
} }
/* direct driven? */ /* direct driven? */
if (chip->o_direct_mask & BIT(pin)) { if (o_direct_mask & BIT(pin)) {
/* TODO: ensure that output driver enabled */ /* TODO: ensure that output driver enabled */
if (value) if (value)
palSetPort(chip->cfg->direct_io[pin].port, palSetPort(cfg->direct_io[pin].port,
PAL_PORT_BIT(chip->cfg->direct_io[pin].pad)); PAL_PORT_BIT(cfg->direct_io[pin].pad));
else else
palClearPort(chip->cfg->direct_io[pin].port, palClearPort(cfg->direct_io[pin].port,
PAL_PORT_BIT(chip->cfg->direct_io[pin].pad)); PAL_PORT_BIT(cfg->direct_io[pin].pad));
} else { } else {
mc33810_wake_driver(chip); wake_driver();
} }
return 0; return 0;
} }
brain_pin_diag_e mc33810_getDiag(void *data, unsigned int pin) brain_pin_diag_e Mc33810::getDiag(size_t pin)
{ {
int val; int val;
mc33810_priv *chip;
int diag = PIN_OK; int diag = PIN_OK;
if ((pin >= MC33810_DIRECT_OUTPUTS) || (data == NULL)) if (pin >= MC33810_DIRECT_OUTPUTS)
return PIN_INVALID; return PIN_INVALID;
chip = (mc33810_priv *)data;
if (pin < 4) { if (pin < 4) {
/* OUT drivers */ /* OUT drivers */
val = chip->out_fault[pin < 2 ? 0 : 1] >> (4 * (pin & 0x01)); val = out_fault[pin < 2 ? 0 : 1] >> (4 * (pin & 0x01));
/* ON open fault */ /* ON open fault */
if (val & BIT(0)) if (val & BIT(0))
@ -499,7 +496,7 @@ brain_pin_diag_e mc33810_getDiag(void *data, unsigned int pin)
diag |= PIN_DRIVER_OVERTEMP; diag |= PIN_DRIVER_OVERTEMP;
} else { } else {
/* INJ drivers, GPGD mode is not supported */ /* INJ drivers, GPGD mode is not supported */
val = chip->ign_fault >> (3 * (pin - 4)); val = ign_fault >> (3 * (pin - 4));
/* open load */ /* open load */
if (val & BIT(0)) if (val & BIT(0))
@ -515,45 +512,25 @@ brain_pin_diag_e mc33810_getDiag(void *data, unsigned int pin)
return static_cast<brain_pin_diag_e>(diag); return static_cast<brain_pin_diag_e>(diag);
} }
int mc33810_init(void * data) int Mc33810::init()
{ {
int ret; int ret;
mc33810_priv *chip;
chip = (mc33810_priv *)data; ret = chip_init();
ret = mc33810_chip_init(chip);
if (ret) if (ret)
return ret; return ret;
chip->drv_state = MC33810_READY; drv_state = MC33810_READY;
if (!drv_task_ready) { if (!drv_task_ready) {
chThdCreateStatic(mc33810_thread_1_wa, sizeof(mc33810_thread_1_wa), chThdCreateStatic(mc33810_thread_1_wa, sizeof(mc33810_thread_1_wa),
PRIO_GPIOCHIP, mc33810_driver_thread, NULL); PRIO_GPIOCHIP, mc33810_driver_thread, nullptr);
drv_task_ready = true; drv_task_ready = true;
} }
return 0; return 0;
} }
int mc33810_deinit(void *data)
{
(void)data;
/* TODO: set all pins to inactive state, stop task? */
return 0;
}
struct gpiochip_ops mc33810_ops = {
.setPadMode = nullptr,
.writePad = mc33810_writePad,
.readPad = NULL, /* chip outputs only */
.getDiag = mc33810_getDiag,
.init = mc33810_init,
.deinit = mc33810_deinit,
};
/** /**
* @brief MC33810 driver add. * @brief MC33810 driver add.
* @details Checks for valid config * @details Checks for valid config
@ -563,7 +540,6 @@ int mc33810_add(brain_pin_e base, unsigned int index, const mc33810_config *cfg)
{ {
int i; int i;
int ret; int ret;
mc33810_priv *chip;
/* no config or no such chip */ /* no config or no such chip */
if ((!cfg) || (!cfg->spi_bus) || (index >= BOARD_MC33810_COUNT)) if ((!cfg) || (!cfg->spi_bus) || (index >= BOARD_MC33810_COUNT))
@ -574,36 +550,36 @@ int mc33810_add(brain_pin_e base, unsigned int index, const mc33810_config *cfg)
//if (cfg->spi_config.ssport == NULL) //if (cfg->spi_config.ssport == NULL)
// return -1; // return -1;
chip = &chips[index]; Mc33810& chip = chips[index];
/* already initted? */ /* already initted? */
if (chip->cfg != NULL) if (chip.cfg != NULL)
return -1; return -1;
chip->cfg = cfg; chip.cfg = cfg;
chip->o_state = 0; chip.o_state = 0;
chip->o_state_cached = 0; chip.o_state_cached = 0;
chip->o_direct_mask = 0; chip.o_direct_mask = 0;
chip->drv_state = MC33810_WAIT_INIT; chip.drv_state = MC33810_WAIT_INIT;
for (i = 0; i < MC33810_DIRECT_OUTPUTS; i++) { for (i = 0; i < MC33810_DIRECT_OUTPUTS; i++) {
if (cfg->direct_io[i].port != 0) if (cfg->direct_io[i].port != 0)
chip->o_direct_mask |= BIT(i); chip.o_direct_mask |= BIT(i);
} }
/* GPGD mode is not supported yet, ignition mode does not support spi on/off commands /* GPGD mode is not supported yet, ignition mode does not support spi on/off commands
* so ignition signals should be directly driven */ * so ignition signals should be directly driven */
if ((chip->o_direct_mask & 0xf0) != 0xf0) if ((chip.o_direct_mask & 0xf0) != 0xf0)
return -1; return -1;
/* register, return gpio chip base */ /* register, return gpio chip base */
ret = gpiochip_register(base, DRIVER_NAME, &mc33810_ops, MC33810_OUTPUTS, chip); ret = gpiochip_register(base, DRIVER_NAME, chip, MC33810_OUTPUTS);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* set default pin names, board init code can rewrite */ /* set default pin names, board init code can rewrite */
gpiochips_setPinNames(static_cast<brain_pin_e>(ret), mc33810_pin_names); gpiochips_setPinNames(static_cast<brain_pin_e>(ret), mc33810_pin_names);
chip->drv_state = MC33810_WAIT_INIT; chip.drv_state = MC33810_WAIT_INIT;
return ret; return ret;
} }

View File

@ -79,7 +79,30 @@ typedef enum {
/*==========================================================================*/ /*==========================================================================*/
/* Driver */ /* Driver */
struct mc33972_priv { struct Mc33972 : public GpioChip {
int init() override;
int deinit() override;
// These functions need not be implemented if not supported by the particular chip.
/* pin argument is pin number within gpio chip, not a global number */
int setPadMode(size_t pin, iomode_t mode) override;
int readPad(size_t pin) override;
brain_pin_diag_e getDiag(size_t pin) override;
// internal functions
int chip_init();
int update_pullups();
int update_status();
void wake_driver();
int spi_w(uint32_t tx);
int comm_test();
const struct mc33972_config *cfg; const struct mc33972_config *cfg;
/* thread stuff */ /* thread stuff */
@ -97,18 +120,12 @@ struct mc33972_priv {
mc33972_drv_state drv_state; mc33972_drv_state drv_state;
}; };
static mc33972_priv chips[BOARD_MC33972_COUNT]; static Mc33972 chips[BOARD_MC33972_COUNT];
/*==========================================================================*/ /*==========================================================================*/
/* Driver local functions. */ /* Driver local functions. */
/*==========================================================================*/ /*==========================================================================*/
static SPIDriver *get_bus(mc33972_priv *chip)
{
/* return non-const SPIDriver* from const struct cfg */
return chip->cfg->spi_bus;
}
/** /**
* @brief MC33972 send cmd routine. * @brief MC33972 send cmd routine.
* @details Sends 24 bits of data. CS asserted before and released * @details Sends 24 bits of data. CS asserted before and released
@ -116,12 +133,12 @@ static SPIDriver *get_bus(mc33972_priv *chip)
* of diagnostic. This routine save it to chip->i_state * of diagnostic. This routine save it to chip->i_state
*/ */
static int mc33972_spi_w(mc33972_priv *chip, uint32_t tx) int Mc33972::spi_w(uint32_t tx)
{ {
int i; int i;
uint8_t rxb[3]; uint8_t rxb[3];
uint8_t txb[3]; uint8_t txb[3];
SPIDriver *spi = get_bus(chip); SPIDriver *spi = cfg->spi_bus;
txb[0] = (tx >> 16) & 0xff; txb[0] = (tx >> 16) & 0xff;
txb[1] = (tx >> 8) & 0xff; txb[1] = (tx >> 8) & 0xff;
@ -129,7 +146,7 @@ static int mc33972_spi_w(mc33972_priv *chip, uint32_t tx)
/* Acquire ownership of the bus. */ /* Acquire ownership of the bus. */
spiAcquireBus(spi); spiAcquireBus(spi);
/* Setup transfer parameters. */ /* Setup transfer parameters. */
spiStart(spi, &chip->cfg->spi_config); spiStart(spi, &cfg->spi_config);
/* Slave Select assertion. */ /* Slave Select assertion. */
spiSelect(spi); spiSelect(spi);
/* Atomic transfer operations. */ /* Atomic transfer operations. */
@ -141,7 +158,7 @@ static int mc33972_spi_w(mc33972_priv *chip, uint32_t tx)
spiReleaseBus(spi); spiReleaseBus(spi);
/* save received data */ /* save received data */
chip->i_state = (rxb[0] << 16) | (rxb[1] << 8) | (rxb[2] << 0); i_state = (rxb[0] << 16) | (rxb[1] << 8) | (rxb[2] << 0);
/* no errors for now */ /* no errors for now */
return 0; return 0;
@ -152,25 +169,25 @@ static int mc33972_spi_w(mc33972_priv *chip, uint32_t tx)
* @details Chip reply with input data and two bits of diag * @details Chip reply with input data and two bits of diag
*/ */
static int mc33972_update_status(mc33972_priv *chip) int Mc33972::update_status()
{ {
return mc33972_spi_w(chip, CMD_STATUS); return spi_w(CMD_STATUS);
} }
static int mc33972_update_pullups(mc33972_priv *chip) int Mc33972::update_pullups()
{ {
int ret; int ret;
/* enable tri-state for all unused pins */ /* enable tri-state for all unused pins */
ret = mc33972_spi_w(chip, CMD_TRI_STATE(SP_BANK, SP_PINS_EXTRACT(~chip->en_pins))); ret = spi_w(CMD_TRI_STATE(SP_BANK, SP_PINS_EXTRACT(~en_pins)));
if (ret) if (ret)
return ret; return ret;
ret = mc33972_spi_w(chip, CMD_TRI_STATE(SG_BANK, SG_PINS_EXTRACT(~chip->en_pins))); ret = spi_w(CMD_TRI_STATE(SG_BANK, SG_PINS_EXTRACT(~en_pins)));
return ret; return ret;
} }
static int mc33972_comm_test(mc33972_priv *chip) int Mc33972::comm_test()
{ {
int ret; int ret;
@ -182,14 +199,14 @@ static int mc33972_comm_test(mc33972_priv *chip)
* check that muxed input bit is zero */ * check that muxed input bit is zero */
for (int i = 0; i < MC33972_INPUTS; i++) { for (int i = 0; i < MC33972_INPUTS; i++) {
/* indexed starting from 1 */ /* indexed starting from 1 */
ret = mc33972_spi_w(chip, CMD_ANALOG(0, i + 1)); ret = spi_w(CMD_ANALOG(0, i + 1));
if (ret) if (ret)
return ret; return ret;
ret = mc33972_update_status(chip); ret = update_status();
if (ret) if (ret)
return ret; return ret;
if (chip->i_state & PIN_MASK(i)) if (i_state & PIN_MASK(i))
return -1; return -1;
} }
@ -202,12 +219,12 @@ static int mc33972_comm_test(mc33972_priv *chip)
* Performs reset. * Performs reset.
*/ */
static int mc33972_chip_init(mc33972_priv *chip) int Mc33972::chip_init()
{ {
int ret; int ret;
/* reset first */ /* reset first */
ret = mc33972_spi_w(chip, CMD_RST); ret = spi_w(CMD_RST);
if (ret) if (ret)
return ret; return ret;
@ -226,20 +243,20 @@ static int mc33972_chip_init(mc33972_priv *chip)
*/ */
/* check communication */ /* check communication */
ret = mc33972_comm_test(chip); ret = comm_test();
if (ret) if (ret)
return ret; return ret;
/* disable tri-state for used pins only */ /* disable tri-state for used pins only */
ret = mc33972_update_pullups(chip); ret = update_pullups();
if (ret) if (ret)
return ret; return ret;
/* Set wetting current to 2 mA */ /* Set wetting current to 2 mA */
ret = mc33972_spi_w(chip, CMD_METALLIC(SP_BANK, 0)); ret = spi_w(CMD_METALLIC(SP_BANK, 0));
if (ret) if (ret)
return ret; return ret;
ret = mc33972_spi_w(chip, CMD_METALLIC(SG_BANK, 0)); ret = spi_w(CMD_METALLIC(SG_BANK, 0));
if (ret) if (ret)
return ret; return ret;
@ -251,11 +268,12 @@ static int mc33972_chip_init(mc33972_priv *chip)
* @details Wake up driver. Will cause input and diagnostic * @details Wake up driver. Will cause input and diagnostic
* update * update
*/ */
static int mc33972_wake_driver(mc33972_priv *chip) void Mc33972::wake_driver()
{ {
/* Entering a reentrant critical zone.*/ /* Entering a reentrant critical zone */
syssts_t sts = chSysGetStatusAndLockX(); chibios_rt::CriticalSectionLocker csl;
chSemSignalI(&chip->wake);
chSemSignalI(&wake);
if (!port_is_isr_context()) { if (!port_is_isr_context()) {
/** /**
* chSemSignalI above requires rescheduling * chSemSignalI above requires rescheduling
@ -263,10 +281,6 @@ static int mc33972_wake_driver(mc33972_priv *chip)
*/ */
chSchRescheduleS(); chSchRescheduleS();
} }
/* Leaving the critical zone.*/
chSysRestoreStatusX(sts);
return 0;
} }
/*==========================================================================*/ /*==========================================================================*/
@ -276,13 +290,13 @@ static int mc33972_wake_driver(mc33972_priv *chip)
static THD_FUNCTION(mc33972_driver_thread, p) static THD_FUNCTION(mc33972_driver_thread, p)
{ {
int ret; int ret;
mc33972_priv *chip = reinterpret_cast<mc33972_priv*>(p); Mc33972 *chip = reinterpret_cast<Mc33972*>(p);
chRegSetThreadName(DRIVER_NAME); chRegSetThreadName(DRIVER_NAME);
/* repeat init until success */ /* repeat init until success */
do { do {
ret = mc33972_chip_init(chip); ret = chip->chip_init();
if (ret) { if (ret) {
chThdSleepMilliseconds(1000); chThdSleepMilliseconds(1000);
continue; continue;
@ -301,11 +315,11 @@ static THD_FUNCTION(mc33972_driver_thread, p)
if (msg == MSG_TIMEOUT) { if (msg == MSG_TIMEOUT) {
/* only input state update */ /* only input state update */
ret = mc33972_update_status(chip); ret = chip->update_status();
} else { } else {
/* someone waked thread and asks us to update pin config */ /* someone waked thread and asks us to update pin config */
/* inputs state is also readed */ /* inputs state is also read */
ret = mc33972_update_pullups(chip); ret = chip->update_pullups();
} }
if (ret) { if (ret) {
@ -324,14 +338,10 @@ static THD_FUNCTION(mc33972_driver_thread, p)
/* Driver exported functions. */ /* Driver exported functions. */
/*==========================================================================*/ /*==========================================================================*/
static int mc33972_setPadMode(void *data, unsigned int pin, iomode_t mode) { int Mc33972::setPadMode(size_t pin, iomode_t mode) {
mc33972_priv *chip; if (pin >= MC33972_INPUTS)
if ((pin >= MC33972_INPUTS) || (data == NULL))
return -1; return -1;
chip = (mc33972_priv *)data;
/* currently driver doesn't know how to hanlde different modes */ /* currently driver doesn't know how to hanlde different modes */
(void)mode; (void)mode;
@ -341,84 +351,60 @@ static int mc33972_setPadMode(void *data, unsigned int pin, iomode_t mode) {
* if this function is called for pin, that means someone * if this function is called for pin, that means someone
* wants to read this pin and we can enable pull-up * wants to read this pin and we can enable pull-up
* Also pull down is not supported yet */ * Also pull down is not supported yet */
chip->en_pins |= PIN_MASK(pin); en_pins |= PIN_MASK(pin);
/* ask for reinit */ /* ask for reinit */
mc33972_wake_driver(chip); wake_driver();
return 0; return 0;
} }
static int mc33972_readPad(void *data, unsigned int pin) { int Mc33972::readPad(size_t pin) {
mc33972_priv *chip; if (pin >= MC33972_INPUTS)
if ((pin >= MC33972_INPUTS) || (data == NULL))
return -1; return -1;
chip = (mc33972_priv *)data;
/* convert to some common enum? */ /* convert to some common enum? */
return !!(chip->i_state & PIN_MASK(pin)); return !!(i_state & PIN_MASK(pin));
} }
static brain_pin_diag_e mc33972_getDiag(void *data, unsigned int pin) { brain_pin_diag_e Mc33972::getDiag(size_t pin) {
brain_pin_diag_e diag = PIN_OK; brain_pin_diag_e diag = PIN_OK;
mc33972_priv *chip;
if ((pin >= MC33972_INPUTS) || (data == NULL)) if (pin >= MC33972_INPUTS)
return PIN_INVALID; return PIN_INVALID;
chip = (mc33972_priv *)data;
/* one diag bit for all pins */ /* one diag bit for all pins */
if (chip->i_state & FLAG_THERM) if (i_state & FLAG_THERM)
diag = PIN_DRIVER_OVERTEMP; diag = PIN_DRIVER_OVERTEMP;
return diag; return diag;
} }
static int mc33972_init(void * data) int Mc33972::init()
{ {
mc33972_priv *chip;
chip = (mc33972_priv *)data;
/* no pins enabled yet */ /* no pins enabled yet */
chip->en_pins = 0x0000; en_pins = 0x0000;
/* init semaphore */ /* init semaphore */
chSemObjectInit(&chip->wake, 0); chSemObjectInit(&wake, 0);
/* start thread */ /* start thread */
chip->thread = chThdCreateStatic(chip->thread_wa, sizeof(chip->thread_wa), thread = chThdCreateStatic(thread_wa, sizeof(thread_wa),
PRIO_GPIOCHIP, mc33972_driver_thread, chip); PRIO_GPIOCHIP, mc33972_driver_thread, this);
return 0; return 0;
} }
static int mc33972_deinit(void *data) int Mc33972::deinit()
{ {
mc33972_priv *chip;
chip = (mc33972_priv *)data;
/* TODO: disable pulls for all pins? */ /* TODO: disable pulls for all pins? */
/* stop thread */ /* stop thread */
chThdTerminate(chip->thread); chThdTerminate(thread);
return 0; return 0;
} }
struct gpiochip_ops mc33972_ops = {
.setPadMode = mc33972_setPadMode,
.writePad = NULL, /* chip input only */
.readPad = mc33972_readPad,
.getDiag = mc33972_getDiag,
.init = mc33972_init,
.deinit = mc33972_deinit,
};
/** /**
* @brief MC33972 driver add. * @brief MC33972 driver add.
* @details Checks for valid config * @details Checks for valid config
@ -426,8 +412,6 @@ struct gpiochip_ops mc33972_ops = {
int mc33972_add(brain_pin_e base, unsigned int index, const struct mc33972_config *cfg) int mc33972_add(brain_pin_e base, unsigned int index, const struct mc33972_config *cfg)
{ {
mc33972_priv *chip;
/* no config or no such chip */ /* no config or no such chip */
if ((!cfg) || (!cfg->spi_bus) || (index >= BOARD_MC33972_COUNT)) if ((!cfg) || (!cfg->spi_bus) || (index >= BOARD_MC33972_COUNT))
return -1; return -1;
@ -438,18 +422,18 @@ int mc33972_add(brain_pin_e base, unsigned int index, const struct mc33972_confi
return -1; return -1;
} }
chip = &chips[index]; Mc33972& chip = chips[index];
/* already initted? */ /* already initted? */
if (chip->cfg != NULL) if (chip.cfg != NULL)
return -1; return -1;
chip->cfg = cfg; chip.cfg = cfg;
chip->i_state = 0; chip.i_state = 0;
chip->drv_state = MC33972_WAIT_INIT; chip.drv_state = MC33972_WAIT_INIT;
/* register, return gpio chip base */ /* register, return gpio chip base */
return gpiochip_register(base, DRIVER_NAME, &mc33972_ops, MC33972_INPUTS, chip); return gpiochip_register(base, DRIVER_NAME, chip, MC33972_INPUTS);
} }
#else /* BOARD_MC33972_COUNT > 0 */ #else /* BOARD_MC33972_COUNT > 0 */

View File

@ -83,7 +83,19 @@ SEMAPHORE_DECL(tle6240_wake, 10 /* or BOARD_TLE6240_COUNT ? */);
static THD_WORKING_AREA(tle6240_thread_1_wa, 256); static THD_WORKING_AREA(tle6240_thread_1_wa, 256);
/* Driver */ /* Driver */
struct tle6240_priv { struct Tle6240 : public GpioChip {
int init() override;
int writePad(size_t pin, int value) override;
brain_pin_diag_e getDiag(size_t pin) override;
// internal functions
int spi_rw(uint16_t tx, uint16_t *rx);
int update_output_and_diag();
int chip_init();
const tle6240_config *cfg; const tle6240_config *cfg;
/* cached output state - state last send to chip */ /* cached output state - state last send to chip */
uint16_t o_state_cached; uint16_t o_state_cached;
@ -100,7 +112,7 @@ struct tle6240_priv {
tle6240_drv_state drv_state; tle6240_drv_state drv_state;
}; };
static tle6240_priv chips[BOARD_TLE6240_COUNT]; static Tle6240 chips[BOARD_TLE6240_COUNT];
static const char* tle6240_pin_names[TLE6240_OUTPUTS] = { static const char* tle6240_pin_names[TLE6240_OUTPUTS] = {
"tle6240.OUT1", "tle6240.OUT2", "tle6240.OUT3", "tle6240.OUT4", "tle6240.OUT1", "tle6240.OUT2", "tle6240.OUT3", "tle6240.OUT4",
@ -113,27 +125,21 @@ static const char* tle6240_pin_names[TLE6240_OUTPUTS] = {
/* Driver local functions. */ /* Driver local functions. */
/*==========================================================================*/ /*==========================================================================*/
static SPIDriver *get_bus(tle6240_priv *chip)
{
/* return non-const SPIDriver* from const struct cfg */
return chip->cfg->spi_bus;
}
/** /**
* @brief TLE6240 send and receive routine. * @brief TLE6240 send and receive routine.
* @details Sends and receives 16 bits. CS asserted before and released * @details Sends and receives 16 bits. CS asserted before and released
* after transaction. * after transaction.
*/ */
static int tle6240_spi_rw(tle6240_priv *chip, uint16_t tx, uint16_t *rx) int Tle6240::spi_rw(uint16_t tx, uint16_t *rx)
{ {
uint16_t rxb; uint16_t rxb;
SPIDriver *spi = get_bus(chip); SPIDriver *spi = cfg->spi_bus;
/* Acquire ownership of the bus. */ /* Acquire ownership of the bus. */
spiAcquireBus(spi); spiAcquireBus(spi);
/* Setup transfer parameters. */ /* Setup transfer parameters. */
spiStart(spi, &chip->cfg->spi_config); spiStart(spi, &cfg->spi_config);
/* Slave Select assertion. */ /* Slave Select assertion. */
spiSelect(spi); spiSelect(spi);
/* Atomic transfer operations. */ /* Atomic transfer operations. */
@ -155,30 +161,30 @@ static int tle6240_spi_rw(tle6240_priv *chip, uint16_t tx, uint16_t *rx)
* @details Sends ORed data to register, also receive 2-bit diagnostic. * @details Sends ORed data to register, also receive 2-bit diagnostic.
*/ */
static int tle6240_update_output_and_diag(tle6240_priv *chip) int Tle6240::update_output_and_diag()
{ {
int ret; int ret;
uint16_t out_data; uint16_t out_data;
/* atomic */ /* atomic */
/* set value only for non-direct driven pins */ /* set value only for non-direct driven pins */
out_data = chip->o_state & (~chip->o_direct_mask); out_data = o_state & (~o_direct_mask);
if (chip->diag_8_reguested) { if (diag_8_reguested) {
/* diagnostic for OUT8..15 was requested on prev access */ /* diagnostic for OUT8..15 was requested on prev access */
ret = tle6240_spi_rw(chip, CMD_OR_DIAG(0, (out_data >> 0) & 0xff), &chip->diag[1]); ret = spi_rw(CMD_OR_DIAG(0, (out_data >> 0) & 0xff), &diag[1]);
ret |= tle6240_spi_rw(chip, CMD_OR_DIAG(8, (out_data >> 8) & 0xff), &chip->diag[0]); ret |= spi_rw(CMD_OR_DIAG(8, (out_data >> 8) & 0xff), &diag[0]);
} else { } else {
ret = tle6240_spi_rw(chip, CMD_OR_DIAG(0, (out_data >> 0) & 0xff), NULL); ret = spi_rw(CMD_OR_DIAG(0, (out_data >> 0) & 0xff), NULL);
ret |= tle6240_spi_rw(chip, CMD_OR_DIAG(8, (out_data >> 8) & 0xff), &chip->diag[0]); ret |= spi_rw(CMD_OR_DIAG(8, (out_data >> 8) & 0xff), &diag[0]);
/* send same one more time to receive OUT8..15 diagnostic */ /* send same one more time to receive OUT8..15 diagnostic */
ret |= tle6240_spi_rw(chip, CMD_OR_DIAG(8, (out_data >> 8) & 0xff), &chip->diag[1]); ret |= spi_rw(CMD_OR_DIAG(8, (out_data >> 8) & 0xff), &diag[1]);
} }
chip->diag_8_reguested = false; diag_8_reguested = false;
if (ret == 0) { if (ret == 0) {
/* atomic */ /* atomic */
chip->o_state_cached = out_data; o_state_cached = out_data;
chip->diag_8_reguested = true; diag_8_reguested = true;
} }
return ret; return ret;
@ -191,12 +197,11 @@ static int tle6240_update_output_and_diag(tle6240_priv *chip)
* Reads initial diagnostic state. * Reads initial diagnostic state.
*/ */
static int tle6240_chip_init(tle6240_priv *chip) int Tle6240::chip_init()
{ {
int n; int n;
int ret; int ret;
uint16_t rx; uint16_t rx;
const tle6240_config *cfg = chip->cfg;
/* mark pins used */ /* mark pins used */
//ret = gpio_pin_markUsed(cfg->spi_config.ssport, cfg->spi_config.sspad, DRIVER_NAME " CS"); //ret = gpio_pin_markUsed(cfg->spi_config.ssport, cfg->spi_config.sspad, DRIVER_NAME " CS");
@ -213,7 +218,7 @@ static int tle6240_chip_init(tle6240_priv *chip)
} }
/* release reset */ /* release reset */
if (cfg->reset.port != NULL) { if (!cfg->reset.port) {
palClearPort(cfg->reset.port, palClearPort(cfg->reset.port,
PAL_PORT_BIT(cfg->reset.pad)); PAL_PORT_BIT(cfg->reset.pad));
chThdSleepMilliseconds(1); chThdSleepMilliseconds(1);
@ -224,9 +229,9 @@ static int tle6240_chip_init(tle6240_priv *chip)
/* check SPI communication */ /* check SPI communication */
/* 0. set echo mode, chip number - don't care */ /* 0. set echo mode, chip number - don't care */
ret = tle6240_spi_rw(chip, CMD_ECHO(0), NULL); ret = spi_rw(CMD_ECHO(0), nullptr);
/* 1. check loopback */ /* 1. check loopback */
ret |= tle6240_spi_rw(chip, 0x5555, &rx); ret |= spi_rw(0x5555, &rx);
if (ret || (rx != 0x5555)) { if (ret || (rx != 0x5555)) {
//print(DRIVER_NAME " spi loopback test failed\n"); //print(DRIVER_NAME " spi loopback test failed\n");
ret = -2; ret = -2;
@ -237,23 +242,23 @@ static int tle6240_chip_init(tle6240_priv *chip)
/* 0. set all direct out to 0 */ /* 0. set all direct out to 0 */
for (n = 0; n < TLE6240_DIRECT_OUTPUTS; n++) { for (n = 0; n < TLE6240_DIRECT_OUTPUTS; n++) {
int i = (n < 4) ? n : (n + 4); int i = (n < 4) ? n : (n + 4);
if (chip->o_direct_mask & (1 << i)) { if (o_direct_mask & (1 << i)) {
palClearPort(cfg->direct_io[n].port, palClearPort(cfg->direct_io[n].port,
PAL_PORT_BIT(cfg->direct_io[n].pad)); PAL_PORT_BIT(cfg->direct_io[n].pad));
} }
} }
/* 1. disable IN0..7 outputs first (ADNed with 0x00) /* 1. disable IN0..7 outputs first (ADNed with 0x00)
* also will get full diag on next access */ * also will get full diag on next access */
ret = tle6240_spi_rw(chip, CMD_AND_DIAG(0, 0x00), NULL); ret = spi_rw(CMD_AND_DIAG(0, 0x00), NULL);
/* 2. get diag for OUT0..7 and send disable OUT8..15 */ /* 2. get diag for OUT0..7 and send disable OUT8..15 */
ret |= tle6240_spi_rw(chip, CMD_AND_DIAG(8, 0x00), &chip->diag[0]); ret |= spi_rw(CMD_AND_DIAG(8, 0x00), &diag[0]);
/* 3. get diag for OUT8..15 and readback input status */ /* 3. get diag for OUT8..15 and readback input status */
ret |= tle6240_spi_rw(chip, CMD_IO_SHORTDIAG(0), &chip->diag[1]); ret |= spi_rw(CMD_IO_SHORTDIAG(0), &diag[1]);
/* 4. send dummy short diag command and get 8 bit of input data and /* 4. send dummy short diag command and get 8 bit of input data and
* 8 bit of short diag */ * 8 bit of short diag */
ret |= tle6240_spi_rw(chip, CMD_IO_SHORTDIAG(0), &rx); ret |= spi_rw(CMD_IO_SHORTDIAG(0), &rx);
rx = ((rx >> 4) & 0x0f00) | ((rx >> 8) & 0x000f); rx = ((rx >> 4) & 0x0f00) | ((rx >> 8) & 0x000f);
if (ret || (rx & chip->o_direct_mask)) { if (ret || (rx & o_direct_mask)) {
//print(DRIVER_NAME " direct io test #1 failed (invalid io mask %04x)\n", (rx & chip->o_direct_mask)); //print(DRIVER_NAME " direct io test #1 failed (invalid io mask %04x)\n", (rx & chip->o_direct_mask));
ret = -3; ret = -3;
goto err_gpios; goto err_gpios;
@ -262,23 +267,23 @@ static int tle6240_chip_init(tle6240_priv *chip)
/* 5. set all direct io to 1 */ /* 5. set all direct io to 1 */
for (n = 0; n < TLE6240_DIRECT_OUTPUTS; n++) { for (n = 0; n < TLE6240_DIRECT_OUTPUTS; n++) {
int i = (n < 4) ? n : (n + 4); int i = (n < 4) ? n : (n + 4);
if (chip->o_direct_mask & (1 << i)) { if (o_direct_mask & (1 << i)) {
palSetPort(cfg->direct_io[n].port, palSetPort(cfg->direct_io[n].port,
PAL_PORT_BIT(cfg->direct_io[n].pad)); PAL_PORT_BIT(cfg->direct_io[n].pad));
} }
} }
/* 6. read chort diagnostic again */ /* 6. read chort diagnostic again */
ret |= tle6240_spi_rw(chip, CMD_IO_SHORTDIAG(0), &rx); ret |= spi_rw(CMD_IO_SHORTDIAG(0), &rx);
rx = ((rx >> 4) & 0x0f00) | ((rx >> 8) & 0x000f); rx = ((rx >> 4) & 0x0f00) | ((rx >> 8) & 0x000f);
rx &= chip->o_direct_mask; rx &= o_direct_mask;
if (ret || (rx != chip->o_direct_mask)) { if (ret || (rx != o_direct_mask)) {
//print(DRIVER_NAME " direct io test #2 failed (invalid io mask %04x)\n", (rx ^ (~chip->o_direct_mask))); //print(DRIVER_NAME " direct io test #2 failed (invalid io mask %04x)\n", (rx ^ (~chip->o_direct_mask)));
ret = -4; ret = -4;
goto err_gpios; goto err_gpios;
} }
/* 7. set all all pins to OR mode, and upload pin states */ /* 7. set all all pins to OR mode, and upload pin states */
ret = tle6240_update_output_and_diag(chip); ret = update_output_and_diag();
if (ret) { if (ret) {
//print(DRIVER_NAME " final setup error\n"); //print(DRIVER_NAME " final setup error\n");
ret = -5; ret = -5;
@ -305,12 +310,11 @@ err_gpios:
* diagnostic update. * diagnostic update.
*/ */
static int tle6240_wake_driver(tle6240_priv *chip) static int tle6240_wake_driver()
{ {
(void)chip;
/* Entering a reentrant critical zone.*/ /* Entering a reentrant critical zone.*/
syssts_t sts = chSysGetStatusAndLockX(); chibios_rt::CriticalSectionLocker csl;
chSemSignalI(&tle6240_wake); chSemSignalI(&tle6240_wake);
if (!port_is_isr_context()) { if (!port_is_isr_context()) {
/** /**
@ -319,8 +323,6 @@ static int tle6240_wake_driver(tle6240_priv *chip)
*/ */
chSchRescheduleS(); chSchRescheduleS();
} }
/* Leaving the critical zone.*/
chSysRestoreStatusX(sts);
return 0; return 0;
} }
@ -346,15 +348,14 @@ static THD_FUNCTION(tle6240_driver_thread, p)
for (i = 0; i < BOARD_TLE6240_COUNT; i++) { for (i = 0; i < BOARD_TLE6240_COUNT; i++) {
int ret; int ret;
tle6240_priv *chip; Tle6240& chip = chips[i];
chip = &chips[i]; if (!chip.cfg ||
if ((chip->cfg == NULL) || (chip.drv_state == TLE6240_DISABLED) ||
(chip->drv_state == TLE6240_DISABLED) || (chip.drv_state == TLE6240_FAILED))
(chip->drv_state == TLE6240_FAILED))
continue; continue;
ret = tle6240_update_output_and_diag(chip); ret = chip.update_output_and_diag();
if (ret) { if (ret) {
/* set state to TLE6240_FAILED? */ /* set state to TLE6240_FAILED? */
} }
@ -372,106 +373,77 @@ static THD_FUNCTION(tle6240_driver_thread, p)
/* Driver exported functions. */ /* Driver exported functions. */
/*==========================================================================*/ /*==========================================================================*/
static int tle6240_writePad(void *data, unsigned int pin, int value) int Tle6240::writePad(unsigned int pin, int value)
{ {
tle6240_priv *chip; if (pin >= TLE6240_OUTPUTS)
if ((pin >= TLE6240_OUTPUTS) || (data == NULL))
return -1; return -1;
chip = (tle6240_priv *)data;
{ {
chibios_rt::CriticalSectionLocker csl; chibios_rt::CriticalSectionLocker csl;
if (value) if (value)
chip->o_state |= (1 << pin); o_state |= (1 << pin);
else else
chip->o_state &= ~(1 << pin); o_state &= ~(1 << pin);
} }
/* direct driven? */ /* direct driven? */
if (chip->o_direct_mask & (1 << pin)) { if (o_direct_mask & (1 << pin)) {
int n = (pin < 8) ? pin : (pin - 4); int n = (pin < 8) ? pin : (pin - 4);
/* TODO: ensure that TLE6240 configured in active high mode */ /* TODO: ensure that TLE6240 configured in active high mode */
if (value) if (value)
palSetPort(chip->cfg->direct_io[n].port, palSetPort(cfg->direct_io[n].port,
PAL_PORT_BIT(chip->cfg->direct_io[n].pad)); PAL_PORT_BIT(cfg->direct_io[n].pad));
else else
palClearPort(chip->cfg->direct_io[n].port, palClearPort(cfg->direct_io[n].port,
PAL_PORT_BIT(chip->cfg->direct_io[n].pad)); PAL_PORT_BIT(cfg->direct_io[n].pad));
} else { } else {
tle6240_wake_driver(chip); tle6240_wake_driver();
} }
return 0; return 0;
} }
static brain_pin_diag_e tle6240_getDiag(void *data, unsigned int pin) brain_pin_diag_e Tle6240::getDiag(size_t pin)
{ {
int val; int val;
int diag; int diagVal;
tle6240_priv *chip;
if ((pin >= TLE6240_OUTPUTS) || (data == NULL)) if (pin >= TLE6240_OUTPUTS)
return PIN_INVALID; return PIN_INVALID;
chip = (tle6240_priv *)data; val = (diag[(pin > 7) ? 1 : 0] >> ((pin % 8) * 2)) & 0x03;
val = (chip->diag[(pin > 7) ? 1 : 0] >> ((pin % 8) * 2)) & 0x03;
if (val == 0x3) if (val == 0x3)
diag = PIN_OK; diagVal = PIN_OK;
else if (val == 0x2) else if (val == 0x2)
/* Overload, shorted load or overtemperature */ /* Overload, shorted load or overtemperature */
diag = PIN_OVERLOAD | PIN_DRIVER_OVERTEMP; diagVal = PIN_OVERLOAD | PIN_DRIVER_OVERTEMP;
else if (val == 0x1) else if (val == 0x1)
diag = PIN_OPEN; diagVal = PIN_OPEN;
else if (val == 0x0) else if (val == 0x0)
diag = PIN_SHORT_TO_GND; diagVal = PIN_SHORT_TO_GND;
return static_cast<brain_pin_diag_e>(diag); return static_cast<brain_pin_diag_e>(diagVal);
} }
static int tle6240_init(void * data) int Tle6240::init()
{ {
int ret; int ret = chip_init();
tle6240_priv *chip;
chip = (tle6240_priv *)data;
ret = tle6240_chip_init(chip);
if (ret) if (ret)
return ret; return ret;
chip->drv_state = TLE6240_READY; drv_state = TLE6240_READY;
if (!drv_task_ready) { if (!drv_task_ready) {
chThdCreateStatic(tle6240_thread_1_wa, sizeof(tle6240_thread_1_wa), chThdCreateStatic(tle6240_thread_1_wa, sizeof(tle6240_thread_1_wa),
PRIO_GPIOCHIP, tle6240_driver_thread, NULL); PRIO_GPIOCHIP, tle6240_driver_thread, nullptr);
drv_task_ready = true; drv_task_ready = true;
} }
return 0; return 0;
} }
static int tle6240_deinit(void *data)
{
(void)data;
/* TODO: set all pins to inactive state, stop task? */
return 0;
}
struct gpiochip_ops tle6240_ops = {
.setPadMode = nullptr,
.writePad = tle6240_writePad,
.readPad = NULL, /* chip outputs only */
.getDiag = tle6240_getDiag,
.init = tle6240_init,
.deinit = tle6240_deinit,
};
/** /**
* @brief TLE6240 driver add. * @brief TLE6240 driver add.
* @details Checks for valid config * @details Checks for valid config
@ -481,7 +453,7 @@ int tle6240_add(brain_pin_e base, unsigned int index, const tle6240_config *cfg)
{ {
int i; int i;
int ret; int ret;
tle6240_priv *chip; Tle6240 *chip;
/* no config or no such chip */ /* no config or no such chip */
if ((!cfg) || (!cfg->spi_bus) || (index >= BOARD_TLE6240_COUNT)) if ((!cfg) || (!cfg->spi_bus) || (index >= BOARD_TLE6240_COUNT))
@ -511,7 +483,7 @@ int tle6240_add(brain_pin_e base, unsigned int index, const tle6240_config *cfg)
chip->drv_state = TLE6240_WAIT_INIT; chip->drv_state = TLE6240_WAIT_INIT;
/* register, return gpio chip base */ /* register, return gpio chip base */
ret = gpiochip_register(base, DRIVER_NAME, &tle6240_ops, TLE6240_OUTPUTS, chip); ret = gpiochip_register(base, DRIVER_NAME, *chip, TLE6240_OUTPUTS);
if (ret < 0) if (ret < 0)
return ret; return ret;

View File

@ -175,7 +175,41 @@ static int lowVoltageResetCounter = 0;
float vBattForTle8888 = 0; float vBattForTle8888 = 0;
/* Driver private data */ /* Driver private data */
struct tle8888_priv { struct Tle8888 : 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;
// internal functions
void read_reg(uint16_t reg, uint16_t* val);
int spi_rw(uint16_t tx, uint16_t *rx_ptr);
int spi_validate(uint16_t rx);
int spi_rw_array(const uint16_t *tx, uint16_t *rx, int n);
int update_status_and_diag();
int update_output();
int update_direct_output(size_t pin, int value);
int wake_driver();
int chip_reset();
int chip_init();
int wwd_feed();
int fwd_feed();
int wd_get_status();
int wd_feed();
int calc_sleep_interval();
brain_pin_diag_e getOutputDiag(size_t pin);
brain_pin_diag_e getInputDiag(size_t pin);
int chip_init_data();
const tle8888_config *cfg; const tle8888_config *cfg;
/* thread stuff */ /* thread stuff */
@ -241,7 +275,7 @@ struct tle8888_priv {
uint16_t rx; uint16_t rx;
}; };
static tle8888_priv chips[BOARD_TLE8888_COUNT]; static Tle8888 chips[BOARD_TLE8888_COUNT];
static const char* tle8888_pin_names[TLE8888_SIGNALS] = { static const char* tle8888_pin_names[TLE8888_SIGNALS] = {
"TLE8888.INJ1", "TLE8888.INJ2", "TLE8888.INJ3", "TLE8888.INJ4", "TLE8888.INJ1", "TLE8888.INJ2", "TLE8888.INJ3", "TLE8888.INJ4",
@ -257,7 +291,7 @@ static const char* tle8888_pin_names[TLE8888_SIGNALS] = {
#if EFI_TUNER_STUDIO #if EFI_TUNER_STUDIO
// set debug_mode 31 // set debug_mode 31
void tle8888PostState(TsDebugChannels *debugChannels) { void tle8888PostState(TsDebugChannels *debugChannels) {
tle8888_priv *chip = &chips[0]; Tle8888 *chip = &chips[0];
debugChannels->debugIntField1 = chip->wwd_err_cnt; debugChannels->debugIntField1 = chip->wwd_err_cnt;
debugChannels->debugIntField2 = chip->fwd_err_cnt; debugChannels->debugIntField2 = chip->fwd_err_cnt;
@ -278,40 +312,34 @@ void tle8888PostState(TsDebugChannels *debugChannels) {
/* Driver local functions. */ /* Driver local functions. */
/*==========================================================================*/ /*==========================================================================*/
static SPIDriver *get_bus(tle8888_priv *chip) int Tle8888::spi_validate(uint16_t rx)
{
/* return non-const SPIDriver* from const struct cfg */
return chip->cfg->spi_bus;
}
static int tle8888_spi_validate(tle8888_priv *chip, uint16_t rx)
{ {
uint8_t reg = getRegisterFromResponse(rx); uint8_t reg = getRegisterFromResponse(rx);
if ((chip->last_reg != REG_INVALID) && (chip->last_reg != reg)) { if ((last_reg != REG_INVALID) && (last_reg != reg)) {
/* unexpected SPI answers */ /* unexpected SPI answers */
if (reg == REG_OPSTAT(0)) { if (reg == REG_OPSTAT(0)) {
/* after power on reset: the address and the content of the /* after power on reset: the address and the content of the
* status register OpStat0 is transmitted with the next SPI * status register OpStat0 is transmitted with the next SPI
* transmission */ * transmission */
chip->por_cnt++; por_cnt++;
} else if (reg == REG_FWDSTAT(1)) { } else if (reg == REG_FWDSTAT(1)) {
/* after watchdog reset: the address and the content of the /* after watchdog reset: the address and the content of the
* diagnosis register FWDStat1 is transmitted with the first * diagnosis register FWDStat1 is transmitted with the first
* SPI transmission after the low to high transition of RST */ * SPI transmission after the low to high transition of RST */
chip->wdr_cnt++; wdr_cnt++;
} else if (reg == REG_DIAG(0)) { } else if (reg == REG_DIAG(0)) {
/* after an invalid communication frame: the address and the /* after an invalid communication frame: the address and the
* content of the diagnosis register Diag0 is transmitted * content of the diagnosis register Diag0 is transmitted
* with the next SPI transmission and the bit COMFE in * with the next SPI transmission and the bit COMFE in
* diagnosis register ComDiag is set to "1" */ * diagnosis register ComDiag is set to "1" */
chip->comfe_cnt++; comfe_cnt++;
} }
/* during power on reset: SPI commands are ignored, SDO is always /* during power on reset: SPI commands are ignored, SDO is always
* tristate */ * tristate */
/* during watchdog reset: SPI commands are ignored, SDO has the /* during watchdog reset: SPI commands are ignored, SDO has the
* value of the status flag */ * value of the status flag */
chip->need_init = true; need_init = true;
return -1; return -1;
} }
@ -322,11 +350,11 @@ static int tle8888_spi_validate(tle8888_priv *chip, uint16_t rx)
/** /**
* @returns -1 in case of communication error * @returns -1 in case of communication error
*/ */
static int tle8888_spi_rw(tle8888_priv *chip, uint16_t tx, uint16_t *rx_ptr) int Tle8888::spi_rw(uint16_t tx, uint16_t *rx_ptr)
{ {
int ret; int ret;
uint16_t rx; uint16_t rx;
SPIDriver *spi = get_bus(chip); SPIDriver *spi = cfg->spi_bus;
/** /**
* 15.1 SPI Protocol * 15.1 SPI Protocol
@ -339,7 +367,7 @@ static int tle8888_spi_rw(tle8888_priv *chip, uint16_t tx, uint16_t *rx_ptr)
/* Acquire ownership of the bus. */ /* Acquire ownership of the bus. */
spiAcquireBus(spi); spiAcquireBus(spi);
/* Setup transfer parameters. */ /* Setup transfer parameters. */
spiStart(spi, &chip->cfg->spi_config); spiStart(spi, &cfg->spi_config);
/* Slave Select assertion. */ /* Slave Select assertion. */
spiSelect(spi); spiSelect(spi);
/* Atomic transfer operations. */ /* Atomic transfer operations. */
@ -350,16 +378,16 @@ static int tle8888_spi_rw(tle8888_priv *chip, uint16_t tx, uint16_t *rx_ptr)
spiReleaseBus(spi); spiReleaseBus(spi);
/* statisctic and debug */ /* statisctic and debug */
chip->tx = tx; this->tx = tx;
chip->rx = rx; this->rx = rx;
chip->spi_cnt++; this->spi_cnt++;
if (rx_ptr) if (rx_ptr)
*rx_ptr = rx; *rx_ptr = rx;
/* validate reply and save last accessed register */ /* validate reply and save last accessed register */
ret = tle8888_spi_validate(chip, rx); ret = spi_validate(rx);
chip->last_reg = getRegisterFromResponse(tx); last_reg = getRegisterFromResponse(tx);
/* no errors for now */ /* no errors for now */
return ret; return ret;
@ -368,11 +396,11 @@ static int tle8888_spi_rw(tle8888_priv *chip, uint16_t tx, uint16_t *rx_ptr)
/** /**
* @return -1 in case of communication error * @return -1 in case of communication error
*/ */
static int tle8888_spi_rw_array(tle8888_priv *chip, const uint16_t *tx, uint16_t *rx, int n) int Tle8888::spi_rw_array(const uint16_t *tx, uint16_t *rx, int n)
{ {
int ret; int ret;
uint16_t rxdata; uint16_t rxdata;
SPIDriver *spi = get_bus(chip); SPIDriver *spi = cfg->spi_bus;
/** /**
* 15.1 SPI Protocol * 15.1 SPI Protocol
@ -385,7 +413,7 @@ static int tle8888_spi_rw_array(tle8888_priv *chip, const uint16_t *tx, uint16_t
/* Acquire ownership of the bus. */ /* Acquire ownership of the bus. */
spiAcquireBus(spi); spiAcquireBus(spi);
/* Setup transfer parameters. */ /* Setup transfer parameters. */
spiStart(spi, &chip->cfg->spi_config); spiStart(spi, &cfg->spi_config);
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
/* Slave Select assertion. */ /* Slave Select assertion. */
@ -399,13 +427,13 @@ static int tle8888_spi_rw_array(tle8888_priv *chip, const uint16_t *tx, uint16_t
spiUnselect(spi); spiUnselect(spi);
/* statistic and debug */ /* statistic and debug */
chip->tx = tx[i]; this->tx = tx[i];
chip->rx = rxdata; this->rx = rxdata;
chip->spi_cnt++; this->spi_cnt++;
/* validate reply and save last accessed register */ /* validate reply and save last accessed register */
ret = tle8888_spi_validate(chip, rxdata); ret = spi_validate(rxdata);
chip->last_reg = getRegisterFromResponse(tx[i]); last_reg = getRegisterFromResponse(tx[i]);
if (ret < 0) if (ret < 0)
break; break;
@ -422,7 +450,7 @@ static int tle8888_spi_rw_array(tle8888_priv *chip, const uint16_t *tx, uint16_t
* @details Sends ORed data to register. * @details Sends ORed data to register.
*/ */
static int tle8888_update_output(tle8888_priv *chip) int Tle8888::update_output()
{ {
int i; int i;
int ret; int ret;
@ -431,8 +459,8 @@ static int tle8888_update_output(tle8888_priv *chip)
/* calculate briconfig0 */ /* calculate briconfig0 */
for (i = 20; i < 24; i++) { for (i = 20; i < 24; i++) {
if (chip->o_pp_mask & BIT(i)) { if (o_pp_mask & BIT(i)) {
if (chip->o_state & BIT(i)) { if (o_state & BIT(i)) {
/* low-side switch mode */ /* low-side switch mode */
} else { } else {
/* else enable high-side switch mode */ /* else enable high-side switch mode */
@ -444,11 +472,11 @@ static int tle8888_update_output(tle8888_priv *chip)
/* TODO: apply hi-Z mask when support will be added */ /* TODO: apply hi-Z mask when support will be added */
/* set value only for non-direct driven pins */ /* set value only for non-direct driven pins */
uint32_t o_data = chip->o_state & ~chip->o_direct_mask; uint32_t o_data = o_state & ~o_direct_mask;
/* output for push-pull pins is allways enabled /* output for push-pull pins is allways enabled
* (at least until we start supporting hi-Z state) */ * (at least until we start supporting hi-Z state) */
o_data |= chip->o_pp_mask; o_data |= o_pp_mask;
uint16_t tx[] = { uint16_t tx[] = {
/* bridge config */ /* bridge config */
@ -459,14 +487,14 @@ static int tle8888_update_output(tle8888_priv *chip)
CMD_CONT(2, o_data >> 16), CMD_CONT(2, o_data >> 16),
CMD_CONT(3, o_data >> 24), CMD_CONT(3, o_data >> 24),
/* Main Relay output: manual vs auto-mode */ /* Main Relay output: manual vs auto-mode */
CMD_CMD0((chip->mr_manual ? REG_CMD0_MRSE : 0x0) | CMD_CMD0((mr_manual ? REG_CMD0_MRSE : 0x0) |
((o_data & BIT(TLE8888_OUTPUT_MR)) ? REG_CMD0_MRON : 0x0)) ((o_data & BIT(TLE8888_OUTPUT_MR)) ? REG_CMD0_MRON : 0x0))
}; };
ret = tle8888_spi_rw_array(chip, tx, NULL, ARRAY_SIZE(tx)); ret = spi_rw_array(tx, NULL, ARRAY_SIZE(tx));
if (ret == 0) { if (ret == 0) {
/* atomic */ /* atomic */
chip->o_data_cached = o_data; o_data_cached = o_data;
} }
return ret; return ret;
@ -476,7 +504,7 @@ static int tle8888_update_output(tle8888_priv *chip)
* @brief read TLE8888 diagnostic registers data. * @brief read TLE8888 diagnostic registers data.
* @details Chained read of several registers * @details Chained read of several registers
*/ */
static int tle8888_update_status_and_diag(tle8888_priv *chip) int Tle8888::update_status_and_diag()
{ {
int ret = 0; int ret = 0;
const uint16_t tx[] = { const uint16_t tx[] = {
@ -495,22 +523,22 @@ static int tle8888_update_status_and_diag(tle8888_priv *chip)
}; };
uint16_t rx[ARRAY_SIZE(tx)]; uint16_t rx[ARRAY_SIZE(tx)];
ret = tle8888_spi_rw_array(chip, tx, rx, ARRAY_SIZE(tx)); ret = spi_rw_array(tx, rx, ARRAY_SIZE(tx));
if (ret == 0) { if (ret == 0) {
/* the address and content of the selected register is transmitted with the /* the address and content of the selected register is transmitted with the
* next SPI transmission */ * next SPI transmission */
chip->OutDiag[0] = getDataFromResponse(rx[0 + 1]); OutDiag[0] = getDataFromResponse(rx[0 + 1]);
chip->OutDiag[1] = getDataFromResponse(rx[1 + 1]); OutDiag[1] = getDataFromResponse(rx[1 + 1]);
chip->OutDiag[2] = getDataFromResponse(rx[2 + 1]); OutDiag[2] = getDataFromResponse(rx[2 + 1]);
chip->OutDiag[3] = getDataFromResponse(rx[3 + 1]); OutDiag[3] = getDataFromResponse(rx[3 + 1]);
chip->OutDiag[4] = getDataFromResponse(rx[4 + 1]); OutDiag[4] = getDataFromResponse(rx[4 + 1]);
chip->PPOVDiag = getDataFromResponse(rx[5 + 1]); PPOVDiag = getDataFromResponse(rx[5 + 1]);
chip->BriDiag[0] = getDataFromResponse(rx[6 + 1]); BriDiag[0] = getDataFromResponse(rx[6 + 1]);
chip->BriDiag[1] = getDataFromResponse(rx[7 + 1]); BriDiag[1] = getDataFromResponse(rx[7 + 1]);
chip->IgnDiag = getDataFromResponse(rx[8 + 1]); IgnDiag = getDataFromResponse(rx[8 + 1]);
chip->OpStat[0] = getDataFromResponse(rx[9 + 1]); OpStat[0] = getDataFromResponse(rx[9 + 1]);
chip->OpStat[1] = getDataFromResponse(rx[10 + 1]); OpStat[1] = getDataFromResponse(rx[10 + 1]);
} }
return ret; return ret;
@ -521,10 +549,9 @@ static int tle8888_update_status_and_diag(tle8888_priv *chip)
* @details This is faster than updating Cont registers over SPI * @details This is faster than updating Cont registers over SPI
*/ */
static int tle8888_update_direct_output(tle8888_priv *chip, int pin, int value) int Tle8888::update_direct_output(size_t pin, int value)
{ {
int index = -1; int index = -1;
const tle8888_config *cfg = chip->cfg;
if (pin < 4) { if (pin < 4) {
/* OUT1..4 */ /* OUT1..4 */
@ -561,11 +588,11 @@ static int tle8888_update_direct_output(tle8888_priv *chip, int pin, int value)
* @details Wake up driver. Will cause output register update * @details Wake up driver. Will cause output register update
*/ */
static int tle8888_wake_driver(tle8888_priv *chip) int Tle8888::wake_driver()
{ {
/* Entering a reentrant critical zone.*/ /* Entering a reentrant critical zone.*/
chibios_rt::CriticalSectionLocker csl; chibios_rt::CriticalSectionLocker csl;
chSemSignalI(&chip->wake); chSemSignalI(&wake);
if (!port_is_isr_context()) { if (!port_is_isr_context()) {
/** /**
* chSemSignalI above requires rescheduling * chSemSignalI above requires rescheduling
@ -598,35 +625,35 @@ static brain_pin_diag_e tle8888_2b_to_diag_with_temp(unsigned int bits)
return static_cast<brain_pin_diag_e>(diag); return static_cast<brain_pin_diag_e>(diag);
} }
static int tle8888_chip_reset(tle8888_priv *chip) { int Tle8888::chip_reset() {
int ret; int ret;
ret = tle8888_spi_rw(chip, CMD_SR, NULL); ret = spi_rw(CMD_SR, NULL);
/** /**
* Table 8. Reset Times. All reset times not more than 20uS * Table 8. Reset Times. All reset times not more than 20uS
*/ */
chThdSleepMilliseconds(3); chThdSleepMilliseconds(3);
chip->last_reg = REG_INVALID; last_reg = REG_INVALID;
return ret; return ret;
} }
static int tle8888_chip_init(tle8888_priv *chip) int Tle8888::chip_init()
{ {
int ret; int ret;
/* statistic */ /* statistic */
chip->init_cnt++; init_cnt++;
uint16_t tx[] = { uint16_t tx[] = {
/* unlock */ /* unlock */
CMD_UNLOCK, CMD_UNLOCK,
/* set INCONFIG - aux input mapping */ /* set INCONFIG - aux input mapping */
CMD_INCONFIG(0, chip->InConfig[0]), CMD_INCONFIG(0, InConfig[0]),
CMD_INCONFIG(1, chip->InConfig[1]), CMD_INCONFIG(1, InConfig[1]),
CMD_INCONFIG(2, chip->InConfig[2]), CMD_INCONFIG(2, InConfig[2]),
CMD_INCONFIG(3, chip->InConfig[3]), CMD_INCONFIG(3, InConfig[3]),
/* Diagnnostic settings */ /* Diagnnostic settings */
/* Enable open load detection and disable switch off /* Enable open load detection and disable switch off
* in case of overcurrent for OUTPUT1..4 */ * in case of overcurrent for OUTPUT1..4 */
@ -659,27 +686,25 @@ static int tle8888_chip_init(tle8888_priv *chip)
* in case of overcurrent for OUTPUT18..20 */ * in case of overcurrent for OUTPUT18..20 */
CMD_OUTCONFIG(5, BIT(5) | BIT(3) | BIT(1)), CMD_OUTCONFIG(5, BIT(5) | BIT(3) | BIT(1)),
/* set OE and DD registers */ /* set OE and DD registers */
CMD_OECONFIG(0, chip->o_oe_mask >> 0), CMD_OECONFIG(0, o_oe_mask >> 0),
CMD_DDCONFIG(0, chip->o_direct_mask >> 0), CMD_DDCONFIG(0, o_direct_mask >> 0),
CMD_OECONFIG(1, chip->o_oe_mask >> 8), CMD_OECONFIG(1, o_oe_mask >> 8),
CMD_DDCONFIG(1, chip->o_direct_mask >> 8), CMD_DDCONFIG(1, o_direct_mask >> 8),
CMD_OECONFIG(2, chip->o_oe_mask >> 16), CMD_OECONFIG(2, o_oe_mask >> 16),
CMD_DDCONFIG(2, chip->o_direct_mask >> 16), CMD_DDCONFIG(2, o_direct_mask >> 16),
CMD_OECONFIG(3, chip->o_oe_mask >> 24), CMD_OECONFIG(3, o_oe_mask >> 24),
CMD_DDCONFIG(3, chip->o_direct_mask >> 24), CMD_DDCONFIG(3, o_direct_mask >> 24),
/* set VR mode: VRS/Hall */ /* set VR mode: VRS/Hall */
CMD_VRSCONFIG(1, (0 << 4) | CMD_VRSCONFIG(1, (0 << 4) |
(chip->cfg->mode << 2) | (cfg->mode << 2) |
(0 << 0)), (0 << 0)),
/* enable outputs */ /* enable outputs */
CMD_OE_SET CMD_OE_SET
}; };
ret = tle8888_spi_rw_array(chip, tx, NULL, ARRAY_SIZE(tx)); ret = spi_rw_array(tx, NULL, ARRAY_SIZE(tx));
if (ret == 0) { if (ret == 0) {
const tle8888_config *cfg = chip->cfg;
/* enable pins */ /* enable pins */
if (cfg->ign_en.port) if (cfg->ign_en.port)
palSetPort(cfg->ign_en.port, PAL_PORT_BIT(cfg->ign_en.pad)); palSetPort(cfg->ign_en.port, PAL_PORT_BIT(cfg->ign_en.pad));
@ -694,18 +719,18 @@ static int tle8888_chip_init(tle8888_priv *chip)
return ret; return ret;
} }
static int tle8888_wwd_feed(tle8888_priv *chip) { int Tle8888::wwd_feed() {
tle8888_spi_rw(chip, CMD_WWDSERVICECMD, NULL); spi_rw(CMD_WWDSERVICECMD, NULL);
return 0; return 0;
} }
static int tle8888_fwd_feed(tle8888_priv *chip) { int Tle8888::fwd_feed() {
uint16_t reg; uint16_t reg;
tle8888_spi_rw(chip, CMD_FWDSTAT(1), NULL); spi_rw(CMD_FWDSTAT(1), NULL);
/* here we get response of the 'FWDStat1' above */ /* here we get response of the 'FWDStat1' above */
tle8888_spi_rw(chip, CMD_WDDIAG, &reg); spi_rw(CMD_WDDIAG, &reg);
uint8_t data = getDataFromResponse(reg); uint8_t data = getDataFromResponse(reg);
uint8_t fwdquest = data & 0xF; uint8_t fwdquest = data & 0xF;
@ -713,30 +738,30 @@ static int tle8888_fwd_feed(tle8888_priv *chip) {
/* Table lines are filled in reverse order (like in DS) */ /* Table lines are filled in reverse order (like in DS) */
uint8_t response = tle8888_fwd_responses[fwdquest][3 - fwdrespc]; uint8_t response = tle8888_fwd_responses[fwdquest][3 - fwdrespc];
if (fwdrespc != 0) { if (fwdrespc != 0) {
tle8888_spi_rw(chip, CMD_FWDRESPCMD(response), NULL); spi_rw(CMD_FWDRESPCMD(response), NULL);
} else { } else {
/* to restart heartbeat timer, sync command should be used for response 0 */ /* to restart heartbeat timer, sync command should be used for response 0 */
tle8888_spi_rw(chip, CMD_FWDRESPSYNCCMD(response), NULL); spi_rw(CMD_FWDRESPSYNCCMD(response), NULL);
} }
return 0; return 0;
} }
static int tle8888_wd_get_status(tle8888_priv *chip) { int Tle8888::wd_get_status() {
uint16_t reg; uint16_t reg;
tle8888_spi_rw(chip, CMD_WDDIAG, NULL); spi_rw(CMD_WDDIAG, NULL);
tle8888_spi_rw(chip, CMD_WDDIAG, &reg); spi_rw(CMD_WDDIAG, &reg);
chip->wd_diag = getDataFromResponse(reg); wd_diag = getDataFromResponse(reg);
if (chip->wd_diag & 0x70) { if (wd_diag & 0x70) {
/* Reset caused by TEC /* Reset caused by TEC
* Reset caused by FWD * Reset caused by FWD
* Reset caused by WWD */ * Reset caused by WWD */
return -1; return -1;
} }
if (chip->wd_diag & 0x0f) { if (wd_diag & 0x0f) {
/* Some error in WD handling */ /* Some error in WD handling */
return 1; return 1;
} }
@ -744,50 +769,50 @@ static int tle8888_wd_get_status(tle8888_priv *chip) {
return 0; return 0;
} }
static int tle8888_wd_feed(tle8888_priv *chip) { int Tle8888::wd_feed() {
bool update_status; bool update_status;
if (chip->wwd_ts <= chVTGetSystemTimeX()) { if (wwd_ts <= chVTGetSystemTimeX()) {
update_status = true; update_status = true;
if (tle8888_wwd_feed(chip) == 0) { if (wwd_feed() == 0) {
chip->wwd_ts = chTimeAddX(chVTGetSystemTimeX(), TIME_MS2I(WWD_PERIOD_MS)); wwd_ts = chTimeAddX(chVTGetSystemTimeX(), TIME_MS2I(WWD_PERIOD_MS));
} }
} }
if (chip->fwd_ts <= chVTGetSystemTimeX()) { if (fwd_ts <= chVTGetSystemTimeX()) {
update_status = true; update_status = true;
if (tle8888_fwd_feed(chip) == 0) { if (fwd_feed() == 0) {
chip->fwd_ts = chTimeAddX(chVTGetSystemTimeX(), TIME_MS2I(FWD_PERIOD_MS)); fwd_ts = chTimeAddX(chVTGetSystemTimeX(), TIME_MS2I(FWD_PERIOD_MS));
} }
} }
if (update_status) { if (update_status) {
uint16_t wwd_reg, fwd_reg, tec_reg; uint16_t wwd_reg, fwd_reg, tec_reg;
tle8888_spi_rw(chip, CMD_WWDSTAT, NULL); spi_rw(CMD_WWDSTAT, NULL);
tle8888_spi_rw(chip, CMD_FWDSTAT(0), &wwd_reg); spi_rw(CMD_FWDSTAT(0), &wwd_reg);
tle8888_spi_rw(chip, CMD_TECSTAT, &fwd_reg); spi_rw(CMD_TECSTAT, &fwd_reg);
tle8888_spi_rw(chip, CMD_TECSTAT, &tec_reg); spi_rw(CMD_TECSTAT, &tec_reg);
chip->wwd_err_cnt = getDataFromResponse(wwd_reg) & 0x7f; wwd_err_cnt = getDataFromResponse(wwd_reg) & 0x7f;
chip->fwd_err_cnt = getDataFromResponse(fwd_reg) & 0x7f; fwd_err_cnt = getDataFromResponse(fwd_reg) & 0x7f;
chip->tot_err_cnt = getDataFromResponse(tec_reg) & 0x7f; tot_err_cnt = getDataFromResponse(tec_reg) & 0x7f;
chip->wd_happy = ((chip->wwd_err_cnt == 0) && wd_happy = ((wwd_err_cnt == 0) &&
(chip->fwd_err_cnt == 0)); (fwd_err_cnt == 0));
return tle8888_wd_get_status(chip); return wd_get_status();
} else { } else {
return 0; return 0;
} }
} }
static int tle8888_calc_sleep_interval(tle8888_priv *chip) { int Tle8888::calc_sleep_interval() {
systime_t now = chVTGetSystemTimeX(); systime_t now = chVTGetSystemTimeX();
sysinterval_t wwd_delay = chTimeDiffX(now, chip->wwd_ts); sysinterval_t wwd_delay = chTimeDiffX(now, wwd_ts);
sysinterval_t fwd_delay = chTimeDiffX(now, chip->fwd_ts); sysinterval_t fwd_delay = chTimeDiffX(now, fwd_ts);
sysinterval_t diag_delay = chTimeDiffX(now, chip->diag_ts); sysinterval_t diag_delay = chTimeDiffX(now, diag_ts);
if ((diag_delay <= wwd_delay) && (diag_delay <= fwd_delay)) if ((diag_delay <= wwd_delay) && (diag_delay <= fwd_delay))
return diag_delay; return diag_delay;
@ -801,7 +826,7 @@ static int tle8888_calc_sleep_interval(tle8888_priv *chip) {
/*==========================================================================*/ /*==========================================================================*/
static THD_FUNCTION(tle8888_driver_thread, p) { static THD_FUNCTION(tle8888_driver_thread, p) {
tle8888_priv *chip = reinterpret_cast<tle8888_priv*>(p); Tle8888 *chip = reinterpret_cast<Tle8888*>(p);
sysinterval_t poll_interval = 0; sysinterval_t poll_interval = 0;
chRegSetThreadName(DRIVER_NAME); chRegSetThreadName(DRIVER_NAME);
@ -838,13 +863,13 @@ static THD_FUNCTION(tle8888_driver_thread, p) {
/* update outputs only if WD is happy */ /* update outputs only if WD is happy */
if ((wd_happy) || (1)) { if ((wd_happy) || (1)) {
ret = tle8888_update_output(chip); ret = chip->update_output();
if (ret) { if (ret) {
/* set state to TLE8888_FAILED? */ /* set state to TLE8888_FAILED? */
} }
} }
ret = tle8888_wd_feed(chip); ret = chip->wd_feed();
if (ret < 0) { if (ret < 0) {
/* WD is not happy */ /* WD is not happy */
continue; continue;
@ -858,14 +883,14 @@ static THD_FUNCTION(tle8888_driver_thread, p) {
/* clear first, as flag can be raised again during init */ /* clear first, as flag can be raised again during init */
chip->need_init = false; chip->need_init = false;
/* re-init chip! */ /* re-init chip! */
tle8888_chip_init(chip); chip->chip_init();
/* sync pins state */ /* sync pins state */
tle8888_update_output(chip); chip->update_output();
} }
if (chip->diag_ts <= chVTGetSystemTimeX()) { if (chip->diag_ts <= chVTGetSystemTimeX()) {
/* this is expensive call, will do a lot of spi transfers... */ /* this is expensive call, will do a lot of spi transfers... */
ret = tle8888_update_status_and_diag(chip); ret = chip->update_status_and_diag();
if (ret) { if (ret) {
/* set state to TLE8888_FAILED or force reinit? */ /* set state to TLE8888_FAILED or force reinit? */
} }
@ -881,7 +906,7 @@ static THD_FUNCTION(tle8888_driver_thread, p) {
chip->diag_ts = chTimeAddX(chVTGetSystemTimeX(), TIME_MS2I(DIAG_PERIOD_MS)); chip->diag_ts = chTimeAddX(chVTGetSystemTimeX(), TIME_MS2I(DIAG_PERIOD_MS));
} }
poll_interval = tle8888_calc_sleep_interval(chip); poll_interval = chip->calc_sleep_interval();
} }
} }
@ -893,16 +918,13 @@ static THD_FUNCTION(tle8888_driver_thread, p) {
/* Driver exported functions. */ /* Driver exported functions. */
/*==========================================================================*/ /*==========================================================================*/
static int tle8888_setPadMode(void *data, unsigned int pin, iomode_t mode) { int Tle8888::setPadMode(unsigned int pin, iomode_t mode) {
if (pin >= TLE8888_SIGNALS)
if ((pin >= TLE8888_SIGNALS) || (data == NULL))
return -1; return -1;
tle8888_priv *chip = (tle8888_priv *)data;
/* if someone has requested MR pin - switch it to manual mode */ /* if someone has requested MR pin - switch it to manual mode */
if (pin == TLE8888_OUTPUT_MR) { if (pin == TLE8888_OUTPUT_MR) {
chip->mr_manual = true; mr_manual = true;
} }
/* do not enalbe PP mode yet */ /* do not enalbe PP mode yet */
@ -915,9 +937,9 @@ static int tle8888_setPadMode(void *data, unsigned int pin, iomode_t mode) {
* values to tle8888 driver... But this is how gpios * values to tle8888 driver... But this is how gpios
* currently implemented */ * currently implemented */
if ((mode & PAL_STM32_OTYPE_MASK) == PAL_STM32_OTYPE_OPENDRAIN) { if ((mode & PAL_STM32_OTYPE_MASK) == PAL_STM32_OTYPE_OPENDRAIN) {
chip->o_pp_mask &= ~BIT(pin); o_pp_mask &= ~BIT(pin);
} else { } else {
chip->o_pp_mask |= BIT(pin); o_pp_mask |= BIT(pin);
} }
#else #else
(void)mode; (void)mode;
@ -926,63 +948,59 @@ static int tle8888_setPadMode(void *data, unsigned int pin, iomode_t mode) {
return 0; return 0;
} }
static int tle8888_writePad(void *data, unsigned int pin, int value) { int Tle8888::writePad(unsigned int pin, int value) {
if ((pin >= TLE8888_OUTPUTS) || (data == NULL)) if (pin >= TLE8888_OUTPUTS)
return -1; return -1;
tle8888_priv *chip = (tle8888_priv *)data;
{ {
chibios_rt::CriticalSectionLocker csl; chibios_rt::CriticalSectionLocker csl;
if (value) { if (value) {
chip->o_state |= (1 << pin); o_state |= (1 << pin);
} else { } else {
chip->o_state &= ~(1 << pin); o_state &= ~(1 << pin);
} }
} }
/* direct driven? */ /* direct driven? */
if (chip->o_direct_mask & (1 << pin)) { if (o_direct_mask & (1 << pin)) {
return tle8888_update_direct_output(chip, pin, value); return update_direct_output(pin, value);
} else { } else {
return tle8888_wake_driver(chip); return wake_driver();
} }
return 0; return 0;
} }
static int tle8888_readPad(void *data, unsigned int pin) { int Tle8888::readPad(size_t pin) {
if ((pin >= TLE8888_OUTPUTS) || (data == NULL)) if (pin >= TLE8888_OUTPUTS)
return -1; return -1;
tle8888_priv *chip = (tle8888_priv *)data;
if (pin < TLE8888_OUTPUTS_REGULAR) { if (pin < TLE8888_OUTPUTS_REGULAR) {
/* return output state */ /* return output state */
/* DOTO: check that pins is disabled by diagnostic? */ /* DOTO: check that pins is disabled by diagnostic? */
return !!(chip->o_data_cached & BIT(pin)); return !!(o_data_cached & BIT(pin));
} else if (pin == TLE8888_OUTPUT_MR) { } else if (pin == TLE8888_OUTPUT_MR) {
/* Main relay can be enabled by KEY input, so report real state */ /* Main relay can be enabled by KEY input, so report real state */
return !!(chip->OpStat[0] & REG_OPSTAT_MR); return !!(OpStat[0] & REG_OPSTAT_MR);
} else if (pin == TLE8888_INPUT_KEY) { } else if (pin == TLE8888_INPUT_KEY) {
return !!(chip->OpStat[0] & REG_OPSTAT_KEY); return !!(OpStat[0] & REG_OPSTAT_KEY);
} if (pin == TLE8888_INPUT_WAKE) { } if (pin == TLE8888_INPUT_WAKE) {
return !!(chip->OpStat[0] & REG_OPSTAT_WAKE); return !!(OpStat[0] & REG_OPSTAT_WAKE);
} }
/* unknown pin */ /* unknown pin */
return -1; return -1;
} }
static brain_pin_diag_e tle8888_getOutputDiag(tle8888_priv *chip, unsigned int pin) brain_pin_diag_e Tle8888::getOutputDiag(size_t pin)
{ {
/* OUT1..OUT4, indexes 0..3 */ /* OUT1..OUT4, indexes 0..3 */
if (pin < 4) if (pin < 4)
return tle8888_2b_to_diag_with_temp((chip->OutDiag[0] >> ((pin - 0) * 2)) & 0x03); return tle8888_2b_to_diag_with_temp((OutDiag[0] >> ((pin - 0) * 2)) & 0x03);
/* OUT5..OUT7, indexes 4..6 */ /* OUT5..OUT7, indexes 4..6 */
if (pin < 7) { if (pin < 7) {
return tle8888_2b_to_diag_with_temp((chip->OutDiag[1] >> ((pin - 4) * 2)) & 0x03); return tle8888_2b_to_diag_with_temp((OutDiag[1] >> ((pin - 4) * 2)) & 0x03);
} }
/* OUT8 to OUT13, indexes 7..12 */ /* OUT8 to OUT13, indexes 7..12 */
if (pin < 13) { if (pin < 13) {
@ -990,79 +1008,75 @@ static brain_pin_diag_e tle8888_getOutputDiag(tle8888_priv *chip, unsigned int p
/* OUT8 */ /* OUT8 */
if (pin == 7) if (pin == 7)
ret = tle8888_2b_to_diag_no_temp((chip->OutDiag[1] >> 6) & 0x03); ret = tle8888_2b_to_diag_no_temp((OutDiag[1] >> 6) & 0x03);
/* OUT9..OUT12 */ /* OUT9..OUT12 */
else if (pin < 12) else if (pin < 12)
ret = tle8888_2b_to_diag_no_temp((chip->OutDiag[2] >> ((pin - 8) * 2)) & 0x03); ret = tle8888_2b_to_diag_no_temp((OutDiag[2] >> ((pin - 8) * 2)) & 0x03);
/* OUT13 */ /* OUT13 */
else /* if (pin == 12) */ else /* if (pin == 12) */
ret = tle8888_2b_to_diag_no_temp((chip->OutDiag[3] >> 0) & 0x03); ret = tle8888_2b_to_diag_no_temp((OutDiag[3] >> 0) & 0x03);
/* overvoltage bit */ /* overvoltage bit */
if (chip->PPOVDiag & BIT(pin - 7)) if (PPOVDiag & BIT(pin - 7))
ret |= PIN_SHORT_TO_BAT; ret |= PIN_SHORT_TO_BAT;
return static_cast<brain_pin_diag_e>(ret); return static_cast<brain_pin_diag_e>(ret);
} }
/* OUT14 to OUT16, indexes 13..15 */ /* OUT14 to OUT16, indexes 13..15 */
if (pin < 16) if (pin < 16)
return tle8888_2b_to_diag_with_temp((chip->OutDiag[3] >> ((pin - 13 + 1) * 2)) & 0x03); return tle8888_2b_to_diag_with_temp((OutDiag[3] >> ((pin - 13 + 1) * 2)) & 0x03);
/* OUT17 to OUT20, indexes 16..19 */ /* OUT17 to OUT20, indexes 16..19 */
if (pin < 20) if (pin < 20)
return tle8888_2b_to_diag_with_temp((chip->OutDiag[4] >> ((pin - 16) * 2)) & 0x03); return tle8888_2b_to_diag_with_temp((OutDiag[4] >> ((pin - 16) * 2)) & 0x03);
/* OUT21..OUT24, indexes 20..23 */ /* OUT21..OUT24, indexes 20..23 */
if (pin < 24) { if (pin < 24) {
/* half bridges */ /* half bridges */
int diag; int diag;
diag = tle8888_2b_to_diag_no_temp((chip->BriDiag[0] >> ((pin - 20) * 2)) & 0x03); diag = tle8888_2b_to_diag_no_temp((BriDiag[0] >> ((pin - 20) * 2)) & 0x03);
if (((pin == 22) || (pin == 23)) && if (((pin == 22) || (pin == 23)) &&
(chip->BriDiag[1] & BIT(5))) (BriDiag[1] & BIT(5)))
diag |= PIN_DRIVER_OVERTEMP; diag |= PIN_DRIVER_OVERTEMP;
if (((pin == 20) || (pin == 21)) && if (((pin == 20) || (pin == 21)) &&
(chip->BriDiag[1] & BIT(4))) (BriDiag[1] & BIT(4)))
diag |= PIN_DRIVER_OVERTEMP; diag |= PIN_DRIVER_OVERTEMP;
if (chip->BriDiag[1] & BIT(pin - 20)) if (BriDiag[1] & BIT(pin - 20))
diag |= PIN_OVERLOAD; /* overcurrent */ diag |= PIN_OVERLOAD; /* overcurrent */
return static_cast<brain_pin_diag_e>(diag); return static_cast<brain_pin_diag_e>(diag);
} }
if (pin < 28) if (pin < 28)
return tle8888_2b_to_diag_with_temp((chip->IgnDiag >> ((pin - 24) * 2)) & 0x03); return tle8888_2b_to_diag_with_temp((IgnDiag >> ((pin - 24) * 2)) & 0x03);
return PIN_OK; return PIN_OK;
} }
static brain_pin_diag_e tle8888_getInputDiag(tle8888_priv *chip, unsigned int pin) brain_pin_diag_e Tle8888::getInputDiag(unsigned int pin)
{ {
(void)chip; (void)pin; (void)pin;
return PIN_OK; return PIN_OK;
} }
static brain_pin_diag_e tle8888_getDiag(void *data, unsigned int pin) brain_pin_diag_e Tle8888::getDiag(size_t pin)
{ {
if ((pin >= TLE8888_SIGNALS) || (data == NULL)) if (pin >= TLE8888_SIGNALS)
return PIN_INVALID; return PIN_INVALID;
tle8888_priv *chip = (tle8888_priv *)data;
if (pin < TLE8888_OUTPUTS) if (pin < TLE8888_OUTPUTS)
return tle8888_getOutputDiag(chip, pin); return getOutputDiag(pin);
else else
return tle8888_getInputDiag(chip, pin); return getInputDiag(pin);
} }
static int tle8888_chip_init_data(void * data) { int Tle8888::chip_init_data() {
int i; int i;
tle8888_priv *chip = (tle8888_priv *)data;
const tle8888_config *cfg = chip->cfg;
int ret = 0; int ret = 0;
chip->o_direct_mask = 0; o_direct_mask = 0;
chip->o_oe_mask = 0; o_oe_mask = 0;
chip->o_pp_mask = 0; o_pp_mask = 0;
/* mark pins used */ /* mark pins used */
if (cfg->reset.port != NULL) { if (cfg->reset.port != NULL) {
@ -1104,7 +1118,7 @@ static int tle8888_chip_init_data(void * data) {
mask = BIT(out); mask = BIT(out);
/* check if output already occupied */ /* check if output already occupied */
if (chip->o_direct_mask & mask) { if (o_direct_mask & mask) {
/* incorrect config? */ /* incorrect config? */
ret = -1; ret = -1;
goto err_gpios; goto err_gpios;
@ -1120,7 +1134,7 @@ static int tle8888_chip_init_data(void * data) {
palClearPort(cfg->direct_gpio[i].port, PAL_PORT_BIT(cfg->direct_gpio[i].pad)); palClearPort(cfg->direct_gpio[i].port, PAL_PORT_BIT(cfg->direct_gpio[i].pad));
/* enable direct drive */ /* enable direct drive */
chip->o_direct_mask |= mask; o_direct_mask |= mask;
/* calculate INCONFIG - aux input mapping for IN9..IN12 */ /* calculate INCONFIG - aux input mapping for IN9..IN12 */
if (i >= 8) { if (i >= 8) {
@ -1128,21 +1142,21 @@ static int tle8888_chip_init_data(void * data) {
ret = -1; ret = -1;
goto err_gpios; goto err_gpios;
} }
chip->InConfig[i - 8] = out - 4; InConfig[i - 8] = out - 4;
} }
} }
/* Enable Push-Pull mode for OUT21..OUT24 */ /* Enable Push-Pull mode for OUT21..OUT24 */
if (cfg->stepper) { if (cfg->stepper) {
chip->o_pp_mask |= BIT(20) | BIT(21) | BIT(22) | BIT(23); o_pp_mask |= BIT(20) | BIT(21) | BIT(22) | BIT(23);
} }
/* enable all direct driven */ /* enable all direct driven */
chip->o_oe_mask |= chip->o_direct_mask; o_oe_mask |= o_direct_mask;
/* enable all ouputs /* enable all ouputs
* TODO: add API to enable/disable? */ * TODO: add API to enable/disable? */
chip->o_oe_mask |= 0x0ffffff0; o_oe_mask |= 0x0ffffff0;
return 0; return 0;
@ -1163,46 +1177,40 @@ err_gpios:
return ret; return ret;
} }
static int tle8888_init(void * data) int Tle8888::init()
{ {
int ret; int ret;
tle8888_priv *chip;
chip = (tle8888_priv *)data;
/* check for multiple init */ /* check for multiple init */
if (chip->drv_state != TLE8888_WAIT_INIT) if (drv_state != TLE8888_WAIT_INIT)
return -1; return -1;
ret = tle8888_chip_reset(chip); ret = chip_reset();
if (ret) if (ret)
return ret; return ret;
ret = tle8888_chip_init_data(chip); ret = chip_init_data();
if (ret) if (ret)
return ret; return ret;
/* force init from driver thread */ /* force init from driver thread */
chip->need_init = true; need_init = true;
/* instance is ready */ /* instance is ready */
chip->drv_state = TLE8888_READY; drv_state = TLE8888_READY;
/* init semaphore */ /* init semaphore */
chSemObjectInit(&chip->wake, 10); chSemObjectInit(&wake, 10);
/* start thread */ /* start thread */
chip->thread = chThdCreateStatic(chip->thread_wa, sizeof(chip->thread_wa), thread = chThdCreateStatic(thread_wa, sizeof(thread_wa),
PRIO_GPIOCHIP, tle8888_driver_thread, chip); PRIO_GPIOCHIP, tle8888_driver_thread, this);
return 0; return 0;
} }
static int tle8888_deinit(void *data) int Tle8888::deinit()
{ {
tle8888_priv *chip = (tle8888_priv *)data;
const tle8888_config *cfg = chip->cfg;
/* disable pins */ /* disable pins */
if (cfg->ign_en.port) if (cfg->ign_en.port)
palClearPort(cfg->ign_en.port, PAL_PORT_BIT(cfg->ign_en.pad)); palClearPort(cfg->ign_en.port, PAL_PORT_BIT(cfg->ign_en.pad));
@ -1210,20 +1218,11 @@ static int tle8888_deinit(void *data)
palClearPort(cfg->inj_en.port, PAL_PORT_BIT(cfg->inj_en.pad)); palClearPort(cfg->inj_en.port, PAL_PORT_BIT(cfg->inj_en.pad));
/* stop thread */ /* stop thread */
chThdTerminate(chip->thread); chThdTerminate(thread);
return 0; return 0;
} }
struct gpiochip_ops tle8888_ops = {
.setPadMode = tle8888_setPadMode,
.writePad = tle8888_writePad,
.readPad = tle8888_readPad,
.getDiag = tle8888_getDiag,
.init = tle8888_init,
.deinit = tle8888_deinit,
};
/** /**
* @brief TLE8888 driver add. * @brief TLE8888 driver add.
* @details Checks for valid config * @details Checks for valid config
@ -1243,10 +1242,10 @@ int tle8888_add(brain_pin_e base, unsigned int index, const tle8888_config *cfg)
if (cfg->spi_config.ssport == NULL) if (cfg->spi_config.ssport == NULL)
return -1; return -1;
tle8888_priv *chip = &chips[index]; Tle8888* chip = &chips[index];
/* already initted? */ /* already initted? */
if (chip->cfg != NULL) if (chip->cfg)
return -1; return -1;
chip->cfg = cfg; chip->cfg = cfg;
@ -1256,7 +1255,7 @@ int tle8888_add(brain_pin_e base, unsigned int index, const tle8888_config *cfg)
chip->drv_state = TLE8888_WAIT_INIT; chip->drv_state = TLE8888_WAIT_INIT;
/* register */ /* register */
int ret = gpiochip_register(base, DRIVER_NAME, &tle8888_ops, TLE8888_OUTPUTS, chip); int ret = gpiochip_register(base, DRIVER_NAME, *chip, TLE8888_OUTPUTS);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -1269,19 +1268,33 @@ int tle8888_add(brain_pin_e base, unsigned int index, const tle8888_config *cfg)
/*==========================================================================*/ /*==========================================================================*/
/* Driver exported debug functions. */ /* Driver exported debug functions. */
/*==========================================================================*/ /*==========================================================================*/
void tle8888_read_reg(uint16_t reg, uint16_t *val) void Tle8888::read_reg(uint16_t reg, uint16_t *val)
{ {
tle8888_priv *chip = &chips[0]; spi_rw(CMD_R(reg), val);
tle8888_spi_rw(chip, CMD_R(reg), val);
} }
void tle8888_req_init(void) void tle8888_req_init() {
{ auto& tle = chips[0];
tle8888_priv *chip = &chips[0];
chip->need_init = true; tle.need_init = true;
chip->init_req_cnt++; tle.init_req_cnt++;
}
void tle8888_dump_regs() {
auto& chip = chips[0];
// since responses are always in the NEXT transmission we will have this one first
chip.read_reg(0, NULL);
efiPrintf("register: data");
for (int request = 0; request <= 0x7e + 1; request++) {
uint16_t tmp;
chip.read_reg(request < (0x7e + 1) ? request : 0x7e, &tmp);
uint8_t reg = getRegisterFromResponse(tmp);
uint8_t data = getDataFromResponse(tmp);
efiPrintf("%02x: %02x", reg, data);
}
} }
#else /* BOARD_TLE8888_COUNT > 0 */ #else /* BOARD_TLE8888_COUNT > 0 */

View File

@ -56,7 +56,7 @@ struct tle8888_config {
/* IN9..IN12 to output mapping */ /* IN9..IN12 to output mapping */
struct { struct {
/* ...used to drive output (starts from 1, as in DS, coders gonna hate) */ /* ...used to drive output (starts from 1, as in DS, coders gonna hate) */
int output; uint8_t output;
} direct_maps[TLE8888_DIRECT_MISC]; } direct_maps[TLE8888_DIRECT_MISC];
struct { struct {
ioportid_t port; ioportid_t port;
@ -78,8 +78,8 @@ struct tle8888_config {
int tle8888_add(brain_pin_e base, unsigned int index, const struct tle8888_config *cfg); int tle8888_add(brain_pin_e base, unsigned int index, const struct tle8888_config *cfg);
/* debug */ /* debug */
void tle8888_read_reg(uint16_t reg, uint16_t *val); void tle8888_req_init();
void tle8888_req_init(void); void tle8888_dump_regs();
#if EFI_TUNER_STUDIO #if EFI_TUNER_STUDIO
#include "tunerstudio_debug_struct.h" #include "tunerstudio_debug_struct.h"

View File

@ -69,24 +69,6 @@ PinRepository::PinRepository() {
initBrainUsedPins(); initBrainUsedPins();
} }
#if (BOARD_TLE8888_COUNT > 0)
void tle8888_dump_regs(void)
{
// since responses are always in the NEXT transmission we will have this one first
tle8888_read_reg(0, NULL);
efiPrintf("register: data");
for (int request = 0; request <= 0x7e + 1; request++) {
uint16_t tmp;
tle8888_read_reg(request < (0x7e + 1) ? request : 0x7e, &tmp);
uint8_t reg = getRegisterFromResponse(tmp);
uint8_t data = getDataFromResponse(tmp);
efiPrintf("%02x: %02x", reg, data);
}
}
#endif
static void reportPins(void) { static void reportPins(void) {
for (unsigned int i = 0; i < getBrainPinOnchipNum(); i++) { for (unsigned int i = 0; i < getBrainPinOnchipNum(); i++) {
const char *pin_user = getBrainUsedPin(i); const char *pin_user = getBrainUsedPin(i);

View File

@ -32,7 +32,6 @@ bool isBrainPinValid(brain_pin_e brainPin);
void initPinRepository(void); void initPinRepository(void);
EXTERNC bool brain_pin_is_onchip(brain_pin_e brainPin); EXTERNC bool brain_pin_is_onchip(brain_pin_e brainPin);
EXTERNC bool brain_pin_is_ext(brain_pin_e brainPin); EXTERNC bool brain_pin_is_ext(brain_pin_e brainPin);
EXTERNC void tle8888_dump_regs(void);
/** /**
* Usually high-level code would invoke efiSetPadMode, not this method directly * Usually high-level code would invoke efiSetPadMode, not this method directly

View File

@ -10,85 +10,53 @@
using ::testing::_; using ::testing::_;
static int testchip_readPad(void *data, unsigned int pin)
{
if (pin & 0x01)
return 1;
return 0;
}
static int io_state = 0; static int io_state = 0;
static int testchip_writePad(void *data, unsigned int pin, int value)
{
if (value)
io_state |= (1 << value);
else
io_state &= ~(1 << value);
return 0;
}
static int initcalls = 0; static int initcalls = 0;
struct GoodChip : public GpioChip {
int init() override {
initcalls++;
return 0;
}
};
static int testchip_init(void *data) class TestChip1 : public GoodChip {
{ int readPad(size_t pin) override {
initcalls++; if (pin & 0x01)
return 1;
return 0;
}
};
return 0; static TestChip1 testchip1;
}
class TestChip2 : public GoodChip {
int writePad(size_t pin, int value) override {
if (value)
io_state |= (1 << value);
else
io_state &= ~(1 << value);
return 0;
}
};
static TestChip2 testchip2;
static int calls_to_failed_chip = 0; static int calls_to_failed_chip = 0;
static int testchip_failed_writePad(void *data, unsigned int pin, int value) // This chip fails to start
{ class TestChip3 : public GpioChip {
calls_to_failed_chip++; int writePad(size_t pin, int value) override {
return 0; calls_to_failed_chip++;
} return 0;
}
static int testchip_failed_init(void *data) int init() override {
{ return -1;
return -1; }
}
/* invalid chip */
struct gpiochip_ops testchip0 = {
/*.setPadMode =*/ NULL,
/*.writePad =*/ NULL,
/*.readPad =*/ NULL,
/*.getDiag =*/ NULL,
/*.init =*/ testchip_init,
/*.deinit =*/ NULL,
}; };
/* Input only chip */ static TestChip3 testchip3;
struct gpiochip_ops testchip1 = {
/*.setPadMode =*/ NULL,
/*.writePad =*/ NULL,
/*.readPad =*/ testchip_readPad,
/*.getDiag =*/ NULL,
/*.init =*/ testchip_init,
/*.deinit =*/ NULL,
};
/* Input only chip */
struct gpiochip_ops testchip2 = {
/*.setPadMode =*/ NULL,
/*.writePad =*/ testchip_writePad,
/*.readPad =*/ NULL,
/*.getDiag =*/ NULL,
/*.init =*/ testchip_init,
/*.deinit =*/ NULL,
};
/* testchi[ failed to init */
struct gpiochip_ops testchip3 = {
/*.setPadMode =*/ NULL,
/*.writePad =*/ testchip_failed_writePad,
/*.readPad =*/ NULL,
/*.getDiag =*/ NULL,
/*.init =*/ testchip_failed_init,
/*.deinit =*/ NULL,
};
TEST(gpioext, testGpioExt) { TEST(gpioext, testGpioExt) {
int ret; int ret;
@ -96,28 +64,25 @@ TEST(gpioext, testGpioExt) {
printf("====================================================================================== testGpioExt\r\n"); printf("====================================================================================== testGpioExt\r\n");
/* should fail to register chip with no readPad and writePad */
EXPECT_FALSE(gpiochip_register((brain_pin_e)(BRAIN_PIN_ONCHIP_LAST + 1), "invalid", &testchip0, 16, NULL) > 0);
/* should fail to register chip with zero gpios */ /* should fail to register chip with zero gpios */
EXPECT_FALSE(gpiochip_register((brain_pin_e)(BRAIN_PIN_ONCHIP_LAST + 1), "invalid", &testchip1, 0, NULL) > 0); EXPECT_FALSE(gpiochip_register((brain_pin_e)(BRAIN_PIN_ONCHIP_LAST + 1), "invalid", testchip1, 0) > 0);
/* should fail to register chip with base overlapig on-chip gpios */ /* should fail to register chip with base overlapig on-chip gpios */
EXPECT_FALSE(gpiochip_register((brain_pin_e)(BRAIN_PIN_ONCHIP_LAST - 1), "invalid", &testchip1, 0, NULL) > 0); EXPECT_FALSE(gpiochip_register((brain_pin_e)(BRAIN_PIN_ONCHIP_LAST - 1), "invalid", testchip1, 0) > 0);
chip1_base = gpiochip_register((brain_pin_e)(BRAIN_PIN_ONCHIP_LAST + 1), "input only", &testchip1, 16, NULL); chip1_base = gpiochip_register((brain_pin_e)(BRAIN_PIN_ONCHIP_LAST + 1), "input only", testchip1, 16);
EXPECT_TRUE(chip1_base > 0); EXPECT_TRUE(chip1_base > 0);
EXPECT_EQ(16, gpiochips_get_total_pins()); EXPECT_EQ(16, gpiochips_get_total_pins());
/* should fail to register chip overlapping other one */ /* should fail to register chip overlapping other one */
EXPECT_FALSE(gpiochip_register((brain_pin_e)(BRAIN_PIN_ONCHIP_LAST + 1 + 15), "output only", &testchip2, 16, NULL) > 0); EXPECT_FALSE(gpiochip_register((brain_pin_e)(BRAIN_PIN_ONCHIP_LAST + 1 + 15), "output only", testchip2, 16) > 0);
chip2_base = gpiochip_register((brain_pin_e)(BRAIN_PIN_ONCHIP_LAST + 1 + 16), "output only", &testchip2, 16, NULL); chip2_base = gpiochip_register((brain_pin_e)(BRAIN_PIN_ONCHIP_LAST + 1 + 16), "output only", testchip2, 16);
EXPECT_TRUE(chip2_base > 0); EXPECT_TRUE(chip2_base > 0);
/* this chip will fail to init, but should be registered without errors */ /* this chip will fail to init, but should be registered without errors */
chip3_base = gpiochip_register((brain_pin_e)(BRAIN_PIN_ONCHIP_LAST + 1 + 16 + 16), "failed chip", &testchip3, 16, NULL); chip3_base = gpiochip_register((brain_pin_e)(BRAIN_PIN_ONCHIP_LAST + 1 + 16 + 16), "failed chip", testchip3, 16);
EXPECT_TRUE(chip2_base > 0); EXPECT_TRUE(chip2_base > 0);
EXPECT_EQ(48, gpiochips_get_total_pins()); EXPECT_EQ(48, gpiochips_get_total_pins());