36 #if (BOARD_TLE8888_COUNT > 0)
52 #define DRIVER_NAME "tle8888"
63 #define CMD_READ (0 << 0)
64 #define CMD_WRITE (1 << 0)
66 #define CMD_REG_ADDR(a) (((a) & 0x7f) << 1)
68 #define CMD_REG_DATA(d) (((d) & 0xff) << 8)
70 #define CMD_W(a, d) (static_cast<uint16_t>((CMD_WRITE | CMD_REG_ADDR(a) | CMD_REG_DATA(d))))
71 #define CMD_R(a) (static_cast<uint16_t>((CMD_READ | CMD_REG_ADDR(a))))
73 #define REG_INVALID 0x00
76 #define CMD_CMD0(d) CMD_W(0x01, d)
77 #define REG_CMD0_MRSE BIT(0)
78 #define REG_CMD0_MRON BIT(1)
80 #define CMD_WWDSERVICECMD CMD_W(0x15, 0x03)
81 #define CMD_FWDRESPCMD(d) CMD_W(0x16, d)
82 #define CMD_FWDRESPSYNCCMD(d) CMD_W(0x17, d)
84 #define CMD_SR_CODE 0x1a
85 #define CMD_SR CMD_W(CMD_SR_CODE, 0x03)
86 #define CMD_OE_SET CMD_W(0x1c, 0x02)
87 #define CMD_OE_CLR CMD_W(0x1c, 0x01)
88 #define CMD_CHIP_UNLOCK CMD_W(0x1e, 0x01)
92 #define REG_DIAG(n) (0x20 + ((n) & 0x01))
93 #define CMD_DIAG(n) CMD_R(REG_DIAG(n))
94 #define CMD_VRSDIAG(n) CMD_R(0x22 + ((n) & 0x01))
95 #define CMD_COMDIAG CMD_R(0x24)
96 #define CMD_OUTDIAG(n) CMD_R(0x25 + ((n) & 0x07))
97 #define CMD_PPOVDIAG CMD_R(0x2a)
98 #define CMD_BRIDIAG(n) CMD_R(0x2b + ((n) & 0x01))
99 #define CMD_IGNDIAG CMD_R(0x2d)
100 #define CMD_WDDIAG CMD_R(0x2e)
103 #define REG_OPSTAT(n) (0x34 + ((n) & 0x01))
104 #define CMD_OPSTAT(n) CMD_R(REG_OPSTAT(n))
105 #define REG_OPSTAT_MR BIT(3)
106 #define REG_OPSTAT_WAKE BIT(1)
107 #define REG_OPSTAT_KEY BIT(0)
108 #define REG_WWDSTAT 0x36
109 #define CMD_WWDSTAT CMD_R(REG_WWDSTAT)
110 #define REG_FWDSTAT(n) (0x37 + ((n) & 0x01))
111 #define CMD_FWDSTAT(n) CMD_R(REG_FWDSTAT(n))
112 #define REG_TECSTAT 0x39
113 #define CMD_TECSTAT CMD_R(REG_TECSTAT)
116 #define CMD_OUTCONFIG(n, d) CMD_W(0x40 + (n), d)
117 #define CMD_BRICONFIG(n, d) CMD_W(0x46 + ((n) & 0x01), d)
118 #define CMD_IGNCONFIG(d) CMD_W(0x48, d)
119 #define CMD_VRSCONFIG(n, d) CMD_W(0x49 + ((n) & 0x03), d)
120 #define CMD_OPCONFIG0(d) CMD_W(0x4e, d)
121 #define CMD_INCONFIG(n, d) CMD_W(0x53 + ((n) & 0x03), d)
122 #define CMD_DDCONFIG(n, d) CMD_W(0x57 + ((n) & 0x03), d)
123 #define CMD_OECONFIG(n, d) CMD_W(0x5b + ((n) & 0x03), d)
126 #define CMD_CONT(n, d) CMD_W(0x7b + ((n) & 0x03), d)
129 #define FWD_PERIOD_MS (20)
133 #define WWD_PERIOD_MS (100.8 + (12.8 / 2))
136 #define DIAG_PERIOD_MS (7)
141 {0xFF, 0x0F, 0xF0, 0x00},
142 {0xB0, 0x40, 0xBF, 0x4F},
143 {0xE9, 0x19, 0xE6, 0x16},
144 {0xA6, 0x56, 0xA9, 0x59},
145 {0x75, 0x85, 0x7A, 0x8A},
146 {0x3A, 0xCA, 0x35, 0xC5},
147 {0x63, 0x93, 0x6C, 0x9C},
148 {0x2C, 0xDC, 0x23, 0xD3},
149 {0xD2, 0x22, 0xDD, 0x2D},
150 {0x9D, 0x6D, 0x92, 0x62},
151 {0xC4, 0x34, 0xCB, 0x3B},
152 {0x8B, 0x7B, 0x84, 0x74},
153 {0x58, 0xA8, 0x57, 0xA7},
154 {0x17, 0xE7, 0x18, 0xE8},
155 {0x4E, 0xBE, 0x41, 0xB1},
156 {0x01, 0xF1, 0x0E, 0xFE}
173 int writePad(
size_t pin,
int value)
override;
174 int readPad(
size_t pin)
override;
178 void read_reg(uint16_t reg, uint16_t* val);
179 int spi_rw(uint16_t tx, uint16_t *rx_ptr);
180 int spi_validate(uint16_t rx);
181 int spi_rw_array(
const uint16_t *tx, uint16_t *rx,
int n);
182 int update_status_and_diag();
185 int update_direct_output(
size_t pin,
int value);
196 int calc_sleep_interval();
201 int chip_init_data();
213 uint32_t o_direct_mask;
221 uint32_t o_data_cached;
226 uint8_t InConfig[TLE8888_DIRECT_MISC];
264 static Tle8888
chips[BOARD_TLE8888_COUNT];
267 "TLE8888.INJ1",
"TLE8888.INJ2",
"TLE8888.INJ3",
"TLE8888.INJ4",
268 "TLE8888.OUT5",
"TLE8888.OUT6",
"TLE8888.OUT7",
"TLE8888.OUT8",
269 "TLE8888.OUT9",
"TLE8888.OUT10",
"TLE8888.OUT11",
"TLE8888.OUT12",
270 "TLE8888.OUT13",
"TLE8888.OUT14",
"TLE8888.OUT15",
"TLE8888.OUT16",
271 "TLE8888.OUT17",
"TLE8888.OUT18",
"TLE8888.OUT19",
"TLE8888.OUT20",
272 "TLE8888.OUT21",
"TLE8888.OUT22",
"TLE8888.OUT23",
"TLE8888.OUT24",
273 "TLE8888.IGN1",
"TLE8888.IGN2",
"TLE8888.IGN3",
"TLE8888.IGN4",
274 "TLE8888.MR",
"TLE8888.KEY",
"TLE8888.WAKE"
280 Tle8888 *chip = &
chips[0];
301 int Tle8888::spi_validate(uint16_t rx)
303 uint8_t reg = getRegisterFromResponse(rx);
305 if ((last_reg != REG_INVALID) && (last_reg != reg)) {
307 if (reg == REG_OPSTAT(0)) {
312 }
else if (reg == REG_FWDSTAT(1)) {
317 }
else if (reg == REG_DIAG(0)) {
339 int Tle8888::spi_rw(uint16_t tx, uint16_t *rx_ptr)
343 SPIDriver *
spi = cfg->spi_bus;
356 spiStart(
spi, &cfg->spi_config);
360 rx = spiPolledExchange(
spi, tx);
375 ret = spi_validate(rx);
376 last_reg = getRegisterFromResponse(tx);
385 int Tle8888::spi_rw_array(
const uint16_t *tx, uint16_t *rx,
int n)
388 SPIDriver *
spi = cfg->spi_bus;
405 spiStart(
spi, &cfg->spi_config);
407 for (
int i = 0; i < n; i++) {
411 uint16_t rxdata = spiPolledExchange(
spi, tx[i]);
424 ret = spi_validate(rxdata);
425 last_reg = getRegisterFromResponse(tx[i]);
442 int Tle8888::update_output()
447 uint8_t briconfig0 = 0;
450 for (i = 20; i < 24; i++) {
451 if (o_pp_mask & BIT(i)) {
452 if (o_state & BIT(i)) {
456 briconfig0 |= BIT((i - 20) * 2);
464 uint32_t o_data = o_state & ~o_direct_mask;
470 uint16_t updateTx[] = {
472 CMD_BRICONFIG(0, briconfig0),
474 CMD_CONT(0, o_data >> 0),
475 CMD_CONT(1, o_data >> 8),
476 CMD_CONT(2, o_data >> 16),
477 CMD_CONT(3, o_data >> 24),
479 CMD_CMD0((mr_manual ? REG_CMD0_MRSE : 0x0) |
480 ((o_data & BIT(TLE8888_OUTPUT_MR)) ? REG_CMD0_MRON : 0x0))
482 ret = spi_rw_array(updateTx, NULL,
efi::size(updateTx));
486 o_data_cached = o_data;
496 int Tle8888::update_status_and_diag()
499 const uint16_t diagTx[] = {
515 ret = spi_rw_array(diagTx, rx,
efi::size(diagTx));
520 OutDiag[0] = getDataFromResponse(rx[0 + 1]);
521 OutDiag[1] = getDataFromResponse(rx[1 + 1]);
522 OutDiag[2] = getDataFromResponse(rx[2 + 1]);
523 OutDiag[3] = getDataFromResponse(rx[3 + 1]);
524 OutDiag[4] = getDataFromResponse(rx[4 + 1]);
525 PPOVDiag = getDataFromResponse(rx[5 + 1]);
526 BriDiag[0] = getDataFromResponse(rx[6 + 1]);
527 BriDiag[1] = getDataFromResponse(rx[7 + 1]);
528 IgnDiag = getDataFromResponse(rx[8 + 1]);
529 OpStat[0] = getDataFromResponse(rx[9 + 1]);
530 OpStat[1] = getDataFromResponse(rx[10 + 1]);
541 int Tle8888::update_direct_output(
size_t pin,
int value)
548 }
else if (pin >= 24) {
550 index = (pin - 24) + 4;
553 for (
int i = 0; i < TLE8888_DIRECT_MISC; i++) {
555 if (cfg->direct_maps[i].output == pin + 1) {
567 palSetPort(cfg->direct_gpio[index].port,
568 PAL_PORT_BIT(cfg->direct_gpio[index].pad));
570 palClearPort(cfg->direct_gpio[index].port,
571 PAL_PORT_BIT(cfg->direct_gpio[index].pad));
580 int Tle8888::wake_driver()
583 chibios_rt::CriticalSectionLocker csl;
585 if (!port_is_isr_context()) {
599 return PIN_SHORT_TO_BAT;
603 return PIN_SHORT_TO_GND;
611 if (diag == PIN_SHORT_TO_BAT)
612 diag |= PIN_DRIVER_OVERTEMP;
617 int Tle8888::chip_reset() {
618 int ret = spi_rw(CMD_SR, NULL);
622 chThdSleepMilliseconds(3);
624 last_reg = REG_INVALID;
629 int Tle8888::chip_init()
636 uint16_t initTx[] = {
640 CMD_INCONFIG(0, InConfig[0]),
641 CMD_INCONFIG(1, InConfig[1]),
642 CMD_INCONFIG(2, InConfig[2]),
643 CMD_INCONFIG(3, InConfig[3]),
647 CMD_OUTCONFIG(0, BIT(7) | BIT(5) | BIT(3) | BIT(1)),
650 CMD_OUTCONFIG(1, BIT(5) | BIT(3) | BIT(1)),
657 CMD_OUTCONFIG(2, (0x0 << 6) | 0x00),
661 CMD_OUTCONFIG(2, (0x0 << 6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)),
667 CMD_OUTCONFIG(3, BIT(5) | (0x0 << 2) | (0x0 << 0)),
671 CMD_OUTCONFIG(4, BIT(5) | BIT(3) | BIT(1)),
674 CMD_OUTCONFIG(5, BIT(5) | BIT(3) | BIT(1)),
676 CMD_OECONFIG(0, o_oe_mask >> 0),
677 CMD_DDCONFIG(0, o_direct_mask >> 0),
678 CMD_OECONFIG(1, o_oe_mask >> 8),
679 CMD_DDCONFIG(1, o_direct_mask >> 8),
680 CMD_OECONFIG(2, o_oe_mask >> 16),
681 CMD_DDCONFIG(2, o_direct_mask >> 16),
682 CMD_OECONFIG(3, o_oe_mask >> 24),
683 CMD_DDCONFIG(3, o_direct_mask >> 24),
685 CMD_VRSCONFIG(1, (0 << 4) |
692 ret = spi_rw_array(initTx, NULL,
efi::size(initTx));
696 if (cfg->ign_en.port)
697 palSetPort(cfg->ign_en.port, PAL_PORT_BIT(cfg->ign_en.pad));
698 if (cfg->inj_en.port)
699 palSetPort(cfg->inj_en.port, PAL_PORT_BIT(cfg->inj_en.pad));
709 int Tle8888::wwd_feed() {
710 spi_rw(CMD_WWDSERVICECMD, NULL);
715 int Tle8888::fwd_feed() {
718 spi_rw(CMD_FWDSTAT(1), NULL);
720 spi_rw(CMD_WDDIAG, ®);
722 uint8_t data = getDataFromResponse(reg);
723 uint8_t fwdquest = data & 0xF;
724 uint8_t fwdrespc = (data >> 4) & 3;
728 spi_rw(CMD_FWDRESPCMD(response), NULL);
731 spi_rw(CMD_FWDRESPSYNCCMD(response), NULL);
737 int Tle8888::wd_get_status() {
740 spi_rw(CMD_WDDIAG, NULL);
741 spi_rw(CMD_WDDIAG, ®);
743 wd_diag = getDataFromResponse(reg);
745 if (wd_diag & 0x70) {
751 if (wd_diag & 0x0f) {
759 int Tle8888::wd_feed() {
760 bool update_status =
false;
762 if (wwd_ts <= chVTGetSystemTimeX()) {
763 update_status =
true;
764 if (wwd_feed() == 0) {
765 wwd_ts = chTimeAddX(chVTGetSystemTimeX(), TIME_MS2I(WWD_PERIOD_MS));
769 if (fwd_ts <= chVTGetSystemTimeX()) {
770 update_status =
true;
771 if (fwd_feed() == 0) {
772 fwd_ts = chTimeAddX(chVTGetSystemTimeX(), TIME_MS2I(FWD_PERIOD_MS));
777 uint16_t wwd_reg, fwd_reg, tec_reg;
779 spi_rw(CMD_WWDSTAT, NULL);
780 spi_rw(CMD_FWDSTAT(0), &wwd_reg);
781 spi_rw(CMD_TECSTAT, &fwd_reg);
782 spi_rw(CMD_TECSTAT, &tec_reg);
784 wwd_err_cnt = getDataFromResponse(wwd_reg) & 0x7f;
785 fwd_err_cnt = getDataFromResponse(fwd_reg) & 0x7f;
786 tot_err_cnt = getDataFromResponse(tec_reg) & 0x7f;
788 wd_happy = ((wwd_err_cnt == 0) &&
791 return wd_get_status();
797 int Tle8888::calc_sleep_interval() {
798 systime_t now = chVTGetSystemTimeX();
800 sysinterval_t wwd_delay = chTimeDiffX(now, wwd_ts);
801 sysinterval_t fwd_delay = chTimeDiffX(now, fwd_ts);
802 sysinterval_t diag_delay = chTimeDiffX(now, diag_ts);
804 if ((diag_delay <= wwd_delay) && (diag_delay <= fwd_delay))
806 if (fwd_delay <= wwd_delay)
816 Tle8888 *chip =
reinterpret_cast<Tle8888*
>(p);
817 sysinterval_t poll_interval = 0;
819 chRegSetThreadName(DRIVER_NAME);
823 msg_t msg = chSemWaitTimeout(&chip->wake, poll_interval);
829 poll_interval = TIME_MS2I(DIAG_PERIOD_MS);
831 if ((chip->cfg == NULL) ||
836 bool wd_happy = chip->wd_happy;
839 if ((wd_happy) || (1)) {
840 ret = chip->update_output();
846 ret = chip->wd_feed();
852 if ((chip->wd_happy != wd_happy) && (chip->wd_happy)) {
853 chip->need_init =
true;
856 if (chip->need_init) {
858 chip->need_init =
false;
862 chip->update_output();
865 if (chip->diag_ts <= chVTGetSystemTimeX()) {
867 ret = chip->update_status_and_diag();
882 chip->diag_ts = chTimeAddX(chVTGetSystemTimeX(), TIME_MS2I(DIAG_PERIOD_MS));
885 poll_interval = chip->calc_sleep_interval();
897 int Tle8888::setPadMode(
unsigned int pin,
iomode_t mode) {
898 if (pin >= TLE8888_SIGNALS)
902 if (pin == TLE8888_OUTPUT_MR) {
909 if ((pin < 20) || (pin > 23))
915 if ((mode & PAL_STM32_OTYPE_MASK) == PAL_STM32_OTYPE_OPENDRAIN) {
916 o_pp_mask &= ~BIT(pin);
918 o_pp_mask |= BIT(pin);
929 if (pin >= TLE8888_OUTPUTS)
933 chibios_rt::CriticalSectionLocker csl;
938 o_state &= ~BIT(pin);
943 if (o_direct_mask & BIT(pin)) {
944 return update_direct_output(pin, value);
946 return wake_driver();
951 int Tle8888::readPad(
size_t pin) {
952 if (pin >= TLE8888_OUTPUTS)
955 if (pin < TLE8888_OUTPUTS_REGULAR) {
958 return !!(o_data_cached & BIT(pin));
959 }
else if (pin == TLE8888_OUTPUT_MR) {
961 return !!(OpStat[0] & REG_OPSTAT_MR);
962 }
else if (pin == TLE8888_INPUT_KEY) {
963 return !!(OpStat[0] & REG_OPSTAT_KEY);
964 }
if (pin == TLE8888_INPUT_WAKE) {
965 return !!(OpStat[0] & REG_OPSTAT_WAKE);
975 return PIN_DRIVER_OFF;
999 if (PPOVDiag & BIT(pin - 7))
1000 ret |= PIN_SHORT_TO_BAT;
1016 if (((pin == 22) || (pin == 23)) &&
1017 (BriDiag[1] & BIT(5)))
1018 diag |= PIN_DRIVER_OVERTEMP;
1019 if (((pin == 20) || (pin == 21)) &&
1020 (BriDiag[1] & BIT(4)))
1021 diag |= PIN_DRIVER_OVERTEMP;
1022 if (BriDiag[1] & BIT(pin - 20))
1023 diag |= PIN_OVERLOAD;
1042 if (pin >= TLE8888_SIGNALS)
1045 if (pin < TLE8888_OUTPUTS)
1046 return getOutputDiag(pin);
1048 return getInputDiag(pin);
1051 int Tle8888::chip_init_data() {
1059 if (cfg->reset.port != NULL) {
1061 palSetPadMode(cfg->reset.port, cfg->reset.pad, PAL_MODE_OUTPUT_PUSHPULL);
1062 palSetPort(cfg->reset.port, PAL_PORT_BIT(cfg->reset.pad));
1064 if (cfg->ign_en.port != NULL) {
1065 ret |=
gpio_pin_markUsed(cfg->ign_en.port, cfg->ign_en.pad, DRIVER_NAME
" IGN EN");
1066 palSetPadMode(cfg->ign_en.port, cfg->ign_en.pad, PAL_MODE_OUTPUT_PUSHPULL);
1067 palClearPort(cfg->ign_en.port, PAL_PORT_BIT(cfg->ign_en.pad));
1069 if (cfg->inj_en.port != NULL) {
1070 ret |=
gpio_pin_markUsed(cfg->inj_en.port, cfg->inj_en.pad, DRIVER_NAME
" INJ EN");
1071 palSetPadMode(cfg->inj_en.port, cfg->inj_en.pad, PAL_MODE_OUTPUT_PUSHPULL);
1072 palClearPort(cfg->inj_en.port, PAL_PORT_BIT(cfg->inj_en.pad));
1075 for (
int i = 0; i < TLE8888_DIRECT_MISC; i++) {
1083 InConfig[i] = 25 - 1 - 4;
1086 for (
int i = 0; i < TLE8888_DIRECT_OUTPUTS; i++) {
1099 out = cfg->direct_maps[i - 8].output - 1;
1102 if ((out < 0) || (cfg->direct_gpio[i].port == NULL)) {
1108 if ((cfg->stepper) && (out >= 20) && (out <= 23)) {
1117 if (o_direct_mask & mask) {
1124 ret =
gpio_pin_markUsed(cfg->direct_gpio[i].port, cfg->direct_gpio[i].pad, DRIVER_NAME
" DIRECT IO");
1129 palSetPadMode(cfg->direct_gpio[i].port, cfg->direct_gpio[i].pad, PAL_MODE_OUTPUT_PUSHPULL);
1130 palClearPort(cfg->direct_gpio[i].port, PAL_PORT_BIT(cfg->direct_gpio[i].pad));
1133 o_direct_mask |= mask;
1137 if ((out < 4) || (out >= 24)) {
1141 InConfig[i - 8] = out - 4;
1147 o_pp_mask |= BIT(20) | BIT(21) | BIT(22) | BIT(23);
1151 o_oe_mask |= o_direct_mask;
1155 o_oe_mask |= 0x0ffffff0;
1161 if (cfg->inj_en.port != NULL)
1163 if (cfg->ign_en.port != NULL)
1165 if (cfg->reset.port != NULL)
1167 for (
int i = 0; i < TLE8888_DIRECT_OUTPUTS; i++) {
1168 if (cfg->direct_gpio[i].port) {
1188 ret = chip_init_data();
1199 chSemObjectInit(&
wake, 10);
1202 thread = chThdCreateStatic(thread_wa,
sizeof(thread_wa),
1203 PRIO_GPIOCHIP, tle8888_driver_thread,
this);
1208 int Tle8888::deinit()
1211 if (cfg->ign_en.port)
1212 palClearPort(cfg->ign_en.port, PAL_PORT_BIT(cfg->ign_en.pad));
1213 if (cfg->inj_en.port)
1214 palClearPort(cfg->inj_en.port, PAL_PORT_BIT(cfg->inj_en.pad));
1217 chThdTerminate(thread);
1233 if ((!cfg) || (!cfg->
spi_bus) || (index >= BOARD_TLE8888_COUNT))
1241 Tle8888* chip = &
chips[index];
1249 chip->o_direct_mask = 0;
1250 chip->o_data_cached = 0;
1267 void Tle8888::read_reg(uint16_t reg, uint16_t *val)
1269 spi_rw(CMD_R(reg), val);
1273 auto& tle =
chips[0];
1275 tle.need_init =
true;
1280 auto& chip =
chips[0];
1283 chip.read_reg(0, NULL);
1285 efiPrintf(
"register: data");
1286 for (
int request = 0; request <= 0x7e + 1; request++) {
1288 chip.read_reg(request < (0x7e + 1) ? request : 0x7e, &tmp);
1289 uint8_t reg = getRegisterFromResponse(tmp);
1290 uint8_t data = getDataFromResponse(tmp);
1292 efiPrintf(
"%02x: %02x", reg, data);
1300 (void)base; (void)index; (void)cfg;
TunerStudioOutputChannels outputChannels
int gpiochip_register(brain_pin_e base, const char *name, GpioChip &gpioChip, size_t size)
Register gpiochip.
int gpiochips_setPinNames(brain_pin_e base, const char **names)
Set pins names for registered gpiochip.
static THD_WORKING_AREA(flashWriteStack, 3 *UTILITY_THREAD_STACK_SIZE)
uint32_t iomode_t
Digital I/O modes.
void writePad(const char *msg, brain_pin_e pin, int bit)
@ OBD_PCM_Processor_Fault
engine_configuration_s * engineConfiguration
void gpio_pin_markUnused(ioportid_t port, ioportmask_t pin)
bool gpio_pin_markUsed(ioportid_t port, ioportmask_t pin, const char *msg)
virtual brain_pin_diag_e getDiag(size_t)
virtual int writePad(size_t, int)
virtual int readPad(size_t)
virtual int setPadMode(size_t, iomode_t)
const uint8_t tle8888_fwd_responses[16][4]
static const char * tle8888_pin_names[TLE8888_SIGNALS]
static brain_pin_diag_e tle8888_2b_to_diag_with_temp(unsigned int bits)
static THD_FUNCTION(tle8888_driver_thread, p)
int tle8888_add(brain_pin_e base, unsigned int index, const tle8888_config *cfg)
TLE8888 driver add.
static Tle8888 chips[BOARD_TLE8888_COUNT]
static Timer diagResponse
static brain_pin_diag_e tle8888_2b_to_diag_no_temp(unsigned int bits)