rusEFI
The most advanced open source ECU
tle8888.cpp
Go to the documentation of this file.
1 /*
2  * tle8888.c
3  *
4  * TLE8888 Engine Machine System IC driver
5  *
6  * This has worked on a bench - see https://youtu.be/yjs5dh_NKo4
7  * All SPI and CS pin in OM_DEFAULT mode
8  *
9  * @date Mar 25, 2019
10  * @author Andrey Belomutskiy, (c) 2012-2020
11  *
12  * 3.2 Pin Definitions and Functions
13  *
14  * IN1-4 Parallel input; Input pin for direct control of power stage OUT1-4
15  *
16  * IN5-8 Parallel input; Input pin for direct control of push pull state IGN1-IGN4
17  *
18  * Table 24 Direct Drive Input Assignment to Output Stages
19  * IN9 to IN12 OUT5 to OUT24
20  *
21  * Masks/inputs bits:
22  * 0..3 - OUT1 .. 4 - INJ - OpenDrain: 2.2A - direct
23  * 4..6 - OUT5 .. 7 - OpenDrain: 4.5A
24  * 7..12 - OUT8 ..13 - Push/Pull: 20mA - quite weak
25  * 13..19 - OUT14..20 - OpenDrain: 0.6A
26  * 20..23 - OUT21..24 - Push/Pull: 0.6A - half bridge (GND or +12v)
27  * 24..27 - IGN1 .. 4 - Push/Pull: 20mA - direct
28  *
29  * Andrey Gusakov, (c) 2019
30  */
31 
32 #include "pch.h"
33 
34 #include "gpio/tle8888.h"
35 
36 #if (BOARD_TLE8888_COUNT > 0)
37 
39 #include "hardware.h"
40 #include "gpio/gpio_ext.h"
41 
42 static Timer diagResponse;
43 
44 /*
45  * TODO list:
46  */
47 
48 /*==========================================================================*/
49 /* Driver local definitions. */
50 /*==========================================================================*/
51 
52 #define DRIVER_NAME "tle8888"
53 
54 typedef enum {
60 
61 /* SPI communication helpers */
62 /* C0 */
63 #define CMD_READ (0 << 0)
64 #define CMD_WRITE (1 << 0)
65 /* C7:1 */
66 #define CMD_REG_ADDR(a) (((a) & 0x7f) << 1)
67 /* CD7:0 */
68 #define CMD_REG_DATA(d) (((d) & 0xff) << 8)
69 
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))))
72 
73 #define REG_INVALID 0x00
74 
75 /* Command registers */
76 #define CMD_CMD0(d) CMD_W(0x01, d)
77 #define REG_CMD0_MRSE BIT(0)
78 #define REG_CMD0_MRON BIT(1)
79 /* Window watchdog open WWDOWT window time = 12.8 mS - fixed value for TLE8888QK */
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)
83 
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)
89 //#define CMD_CHIP_LOCK CMD_W(0x1e, 0x02)
90 
91 /* Diagnostic registers */
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)
101 
102 /* Status registers */
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)
114 
115 /* Configuration registers */
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)
124 
125 /* Control registers */
126 #define CMD_CONT(n, d) CMD_W(0x7b + ((n) & 0x03), d)
127 
128 /* Looks like reset value is 113.6ms? 1.6ms * 0x47 */
129 #define FWD_PERIOD_MS (20)
130 
131 /* Default closed window time is 0b0011.1111 * 1.6 = 100.8mS
132  * Default open window time is 0b0011 * 3.2 = 12.8 mS */
133 #define WWD_PERIOD_MS (100.8 + (12.8 / 2))
134 
135 /* TODO: add irq support */
136 #define DIAG_PERIOD_MS (7)
137 
138 const uint8_t tle8888_fwd_responses[16][4] = {
139  /* Reverse order:
140  * RESP3,RESP2,RESP1,RESP0 */
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}
157 };
158 
159 /*==========================================================================*/
160 /* Driver exported variables. */
161 /*==========================================================================*/
162 
163 /*==========================================================================*/
164 /* Driver local variables and types. */
165 /*==========================================================================*/
166 
167 /* Driver private data */
168 struct Tle8888 : public GpioChip {
169  int init() override;
170  int deinit() override;
171 
172  int setPadMode(size_t pin, iomode_t mode) override;
173  int writePad(size_t pin, int value) override;
174  int readPad(size_t pin) override;
175  brain_pin_diag_e getDiag(size_t pin) override;
176 
177  // internal functions
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();
183 
184  int update_output();
185  int update_direct_output(size_t pin, int value);
186  int wake_driver();
187 
188  int chip_reset();
189 
190  int chip_init();
191 
192  int wwd_feed();
193  int fwd_feed();
194  int wd_get_status();
195  int wd_feed();
196  int calc_sleep_interval();
197 
198  brain_pin_diag_e getOutputDiag(size_t pin);
199  brain_pin_diag_e getInputDiag(size_t pin);
200 
201  int chip_init_data();
202 
203  const tle8888_config *cfg;
204 
205  /* thread stuff */
206  thread_t *thread;
207  THD_WORKING_AREA(thread_wa, 256);
208  semaphore_t wake;
209 
210  /* state to be sent to chip */
211  uint32_t o_state;
212  /* direct driven output mask */
213  uint32_t o_direct_mask;
214  /* output enabled mask */
215  uint32_t o_oe_mask;
216  /* push-pull enabled mask (for OUT21..OUT24 only) */
217  /* this is overhead to store 4 bits in uint32_t
218  * but I don't want any magic shift math */
219  uint32_t o_pp_mask;
220  /* cached output registers state - value last send to chip */
221  uint32_t o_data_cached;
222 
223  tle8888_drv_state drv_state;
224 
225  /* direct drive mapping registers */
226  uint8_t InConfig[TLE8888_DIRECT_MISC];
227 
228  /* last accessed register, for validation on next SPI access */
229  uint8_t last_reg;
230 
231  /* diagnostic registers */
232  uint8_t OutDiag[5];
233  uint8_t PPOVDiag;
234  uint8_t BriDiag[2];
235  uint8_t IgnDiag;
236  /* status registers */
237  uint8_t OpStat[2];
238 
239  /* last diagnostic was read */
240  systime_t diag_ts;
241 
242  /* WD stuff */
243  uint8_t wwd_err_cnt;
244  uint8_t fwd_err_cnt;
245  uint8_t tot_err_cnt;
246  uint8_t wd_diag;
247  bool wd_happy;
248  systime_t wwd_ts;
249  systime_t fwd_ts;
250 
251  /* main relay output */
252  bool mr_manual;
253 
254  /* statistic */
255  int por_cnt;
256  int wdr_cnt;
257  int comfe_cnt;
258  int init_req_cnt;
259  int spi_cnt;
260  uint16_t recentTx;
261  uint16_t recentRx;
262 };
263 
264 static Tle8888 chips[BOARD_TLE8888_COUNT];
265 
266 static const char* tle8888_pin_names[TLE8888_SIGNALS] = {
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"
275 };
276 
277 #if EFI_TUNER_STUDIO
278 // set debug_mode 31
280  Tle8888 *chip = &chips[0];
281 
282  engine->outputChannels.debugIntField1 = chip->wwd_err_cnt;
283  engine->outputChannels.debugIntField2 = chip->fwd_err_cnt;
284  engine->outputChannels.debugIntField3 = chip->tot_err_cnt;
285  //engine->outputChannels.debugIntField1 = chip->spi_cnt;
286  //engine->outputChannels.debugIntField2 = chip->tx;
287  //engine->outputChannels.debugIntField3 = chip->rx;
288  engine->outputChannels.debugIntField5 = chip->init_cnt;
289 
290  engine->outputChannels.debugFloatField3 = chip->OpStat[1];
291  engine->outputChannels.debugFloatField4 = chip->por_cnt * 1000000 + chip->init_req_cnt * 10000;
294 }
295 #endif /* EFI_TUNER_STUDIO */
296 
297 /*==========================================================================*/
298 /* Driver local functions. */
299 /*==========================================================================*/
300 
301 int Tle8888::spi_validate(uint16_t rx)
302 {
303  uint8_t reg = getRegisterFromResponse(rx);
304 
305  if ((last_reg != REG_INVALID) && (last_reg != reg)) {
306  /* unexpected SPI answers */
307  if (reg == REG_OPSTAT(0)) {
308  /* after power on reset: the address and the content of the
309  * status register OpStat0 is transmitted with the next SPI
310  * transmission */
311  por_cnt++;
312  } else if (reg == REG_FWDSTAT(1)) {
313  /* after watchdog reset: the address and the content of the
314  * diagnosis register FWDStat1 is transmitted with the first
315  * SPI transmission after the low to high transition of RST */
316  wdr_cnt++;
317  } else if (reg == REG_DIAG(0)) {
318  /* after an invalid communication frame: the address and the
319  * content of the diagnosis register Diag0 is transmitted
320  * with the next SPI transmission and the bit COMFE in
321  * diagnosis register ComDiag is set to "1" */
322  comfe_cnt++;
323  }
324  /* during power on reset: SPI commands are ignored, SDO is always
325  * tristate */
326  /* during watchdog reset: SPI commands are ignored, SDO has the
327  * value of the status flag */
328  need_init = true;
329 
330  return -1;
331  }
332 
333  return 0;
334 }
335 
336 /**
337  * @returns -1 in case of communication error
338  */
339 int Tle8888::spi_rw(uint16_t tx, uint16_t *rx_ptr)
340 {
341  int ret;
342  uint16_t rx;
343  SPIDriver *spi = cfg->spi_bus;
344 
345  /**
346  * 15.1 SPI Protocol
347  *
348  * after a read or write command: the address and content of the selected register
349  * is transmitted with the next SPI transmission (for not existing addresses or
350  * wrong access mode the data is always 0)
351  */
352 
353  /* Acquire ownership of the bus. */
354  spiAcquireBus(spi);
355  /* Setup transfer parameters. */
356  spiStart(spi, &cfg->spi_config);
357  /* Slave Select assertion. */
358  spiSelect(spi);
359  /* Atomic transfer operations. */
360  rx = spiPolledExchange(spi, tx);
361  /* Slave Select de-assertion. */
362  spiUnselect(spi);
363  /* Ownership release. */
364  spiReleaseBus(spi);
365 
366  /* statisctic and debug */
367  recentTx = tx;
368  recentRx = rx;
369  this->spi_cnt++;
370 
371  if (rx_ptr)
372  *rx_ptr = rx;
373 
374  /* validate reply and save last accessed register */
375  ret = spi_validate(rx);
376  last_reg = getRegisterFromResponse(tx);
377 
378  /* no errors for now */
379  return ret;
380 }
381 
382 /**
383  * @return -1 in case of communication error
384  */
385 int Tle8888::spi_rw_array(const uint16_t *tx, uint16_t *rx, int n)
386 {
387  int ret = 0;
388  SPIDriver *spi = cfg->spi_bus;
389 
390  if (n <= 0) {
391  return -2;
392  }
393 
394  /**
395  * 15.1 SPI Protocol
396  *
397  * after a read or write command: the address and content of the selected register
398  * is transmitted with the next SPI transmission (for not existing addresses or
399  * wrong access mode the data is always 0)
400  */
401 
402  /* Acquire ownership of the bus. */
403  spiAcquireBus(spi);
404  /* Setup transfer parameters. */
405  spiStart(spi, &cfg->spi_config);
406 
407  for (int i = 0; i < n; i++) {
408  /* Slave Select assertion. */
409  spiSelect(spi);
410  /* data transfer */
411  uint16_t rxdata = spiPolledExchange(spi, tx[i]);
412 
413  if (rx)
414  rx[i] = rxdata;
415  /* Slave Select de-assertion. */
416  spiUnselect(spi);
417 
418  /* statistic and debug */
419  recentTx = tx[i];
420  recentRx = rxdata;
421  this->spi_cnt++;
422 
423  /* validate reply and save last accessed register */
424  ret = spi_validate(rxdata);
425  last_reg = getRegisterFromResponse(tx[i]);
426 
427  if (ret < 0)
428  break;
429  }
430  /* Ownership release. */
431  spiReleaseBus(spi);
432 
433  /* no errors for now */
434  return ret;
435 }
436 
437 /**
438  * @brief TLE8888 send output registers data.
439  * @details Sends ORed data to register.
440  */
441 
442 int Tle8888::update_output()
443 {
444  int i;
445  int ret;
446 
447  uint8_t briconfig0 = 0;
448 
449  /* calculate briconfig0 */
450  for (i = 20; i < 24; i++) {
451  if (o_pp_mask & BIT(i)) {
452  if (o_state & BIT(i)) {
453  /* low-side switch mode */
454  } else {
455  /* else enable high-side switch mode */
456  briconfig0 |= BIT((i - 20) * 2);
457  }
458  }
459  }
460  /* TODO: set freewheeling bits in briconfig0? */
461  /* TODO: apply hi-Z mask when support will be added */
462 
463  /* set value only for non-direct driven pins */
464  uint32_t o_data = o_state & ~o_direct_mask;
465 
466  /* output for push-pull pins is allways enabled
467  * (at least until we start supporting hi-Z state) */
468  o_data |= o_pp_mask;
469 
470  uint16_t updateTx[] = {
471  /* bridge config */
472  CMD_BRICONFIG(0, briconfig0),
473  /* output enables */
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),
478  /* Main Relay output: manual vs auto-mode */
479  CMD_CMD0((mr_manual ? REG_CMD0_MRSE : 0x0) |
480  ((o_data & BIT(TLE8888_OUTPUT_MR)) ? REG_CMD0_MRON : 0x0))
481  };
482  ret = spi_rw_array(updateTx, NULL, efi::size(updateTx));
483 
484  if (ret == 0) {
485  /* atomic */
486  o_data_cached = o_data;
487  }
488 
489  return ret;
490 }
491 
492 /**
493  * @brief read TLE8888 diagnostic registers data.
494  * @details Chained read of several registers
495  */
496 int Tle8888::update_status_and_diag()
497 {
498  int ret = 0;
499  const uint16_t diagTx[] = {
500  CMD_OUTDIAG(0),
501  CMD_OUTDIAG(1),
502  CMD_OUTDIAG(2),
503  CMD_OUTDIAG(3),
504  CMD_OUTDIAG(4),
505  CMD_PPOVDIAG,
506  CMD_BRIDIAG(0),
507  CMD_BRIDIAG(1),
508  CMD_IGNDIAG,
509  CMD_OPSTAT(0),
510  CMD_OPSTAT(1),
511  CMD_OPSTAT(1)
512  };
513  uint16_t rx[efi::size(diagTx)];
514 
515  ret = spi_rw_array(diagTx, rx, efi::size(diagTx));
516 
517  if (ret == 0) {
518  /* the address and content of the selected register is transmitted with the
519  * next SPI transmission */
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]);
531  }
532 
533  return ret;
534 }
535 
536 /**
537  * @brief Drives natve MCU pins connected to TLE8888 inputs
538  * @details This is faster than updating Cont registers over SPI
539  */
540 
541 int Tle8888::update_direct_output(size_t pin, int value)
542 {
543  int index = -1;
544 
545  if (pin < 4) {
546  /* OUT1..4 */
547  index = pin;
548  } else if (pin >= 24) {
549  /* IGN1..4 */
550  index = (pin - 24) + 4;
551  } else {
552  /* find remapable direct drive gpio */
553  for (int i = 0; i < TLE8888_DIRECT_MISC; i++) {
554  /* again: outputs in cfg counted starting from 1 - hate this */
555  if (cfg->direct_maps[i].output == pin + 1) {
556  index = 8 + i;
557  break;
558  }
559  }
560  }
561 
562  /* direct gpio not found */
563  if (index < 0)
564  return -1;
565 
566  if (value)
567  palSetPort(cfg->direct_gpio[index].port,
568  PAL_PORT_BIT(cfg->direct_gpio[index].pad));
569  else
570  palClearPort(cfg->direct_gpio[index].port,
571  PAL_PORT_BIT(cfg->direct_gpio[index].pad));
572  return 0;
573 }
574 
575 /**
576  * @brief TLE8888 chip driver wakeup.
577  * @details Wake up driver. Will cause output register update
578  */
579 
580 int Tle8888::wake_driver()
581 {
582  /* Entering a reentrant critical zone.*/
583  chibios_rt::CriticalSectionLocker csl;
584  chSemSignalI(&wake);
585  if (!port_is_isr_context()) {
586  /**
587  * chSemSignalI above requires rescheduling
588  * interrupt handlers have implicit rescheduling
589  */
590  chSchRescheduleS();
591  }
592 
593  return 0;
594 }
595 
597 {
598  if (bits == 0x01)
599  return PIN_SHORT_TO_BAT;
600  if (bits == 0x02)
601  return PIN_OPEN;
602  if (bits == 0x03)
603  return PIN_SHORT_TO_GND;
604  return PIN_OK;
605 }
606 
608 {
609  int diag = tle8888_2b_to_diag_no_temp(bits);
610 
611  if (diag == PIN_SHORT_TO_BAT)
612  diag |= PIN_DRIVER_OVERTEMP;
613 
614  return static_cast<brain_pin_diag_e>(diag);
615 }
616 
617 int Tle8888::chip_reset() {
618  int ret = spi_rw(CMD_SR, NULL);
619  /**
620  * Table 8. Reset Times. All reset times not more than 20uS
621  */
622  chThdSleepMilliseconds(3);
623 
624  last_reg = REG_INVALID;
625 
626  return ret;
627 }
628 
629 int Tle8888::chip_init()
630 {
631  int ret;
632 
633  /* statistic */
634  init_cnt++;
635 
636  uint16_t initTx[] = {
637  /* unlock */
638  CMD_CHIP_UNLOCK,
639  /* set INCONFIG - aux input mapping */
640  CMD_INCONFIG(0, InConfig[0]),
641  CMD_INCONFIG(1, InConfig[1]),
642  CMD_INCONFIG(2, InConfig[2]),
643  CMD_INCONFIG(3, InConfig[3]),
644  /* Diagnnostic settings */
645  /* Enable open load detection and disable switch off
646  * in case of overcurrent for OUTPUT1..4 */
647  CMD_OUTCONFIG(0, BIT(7) | BIT(5) | BIT(3) | BIT(1)),
648  /* Enable open load detection and disable switch off
649  * in case of overcurrent for OUTPUT5..7 */
650  CMD_OUTCONFIG(1, BIT(5) | BIT(3) | BIT(1)),
651 #if 1
652  /* MRE 0.5.? share same outputs between OUTPUT8..13
653  * and analog inputs. Disable diagnostic pull-down
654  * not to affect analog inputs.
655  * Disable open load detection and set short to bat
656  * thresholt to 125 mV (default) for OUTPUT8..13 */
657  CMD_OUTCONFIG(2, (0x0 << 6) | 0x00),
658 #else
659  /* Enable open load detection and set short to bat
660  * thresholt to 125 mV (default) for OUTPUT8..13 */
661  CMD_OUTCONFIG(2, (0x0 << 6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)),
662 #endif
663  /* Enable open load detection and disable switch off
664  * in case of overcurrent for OUTPUT14
665  * Set short to bat threshold to 125mV (default) for
666  * OUTPUT12..13 and OUTPUT10..11 */
667  CMD_OUTCONFIG(3, BIT(5) | (0x0 << 2) | (0x0 << 0)),
668  /* No delayed off function for OUTPUT17
669  * Enable open load detection and disable switch off
670  * in case of overcurrent for OUTPUT15..17 */
671  CMD_OUTCONFIG(4, BIT(5) | BIT(3) | BIT(1)),
672  /* Enable open load detection and disable switch off
673  * in case of overcurrent for OUTPUT18..20 */
674  CMD_OUTCONFIG(5, BIT(5) | BIT(3) | BIT(1)),
675  /* set OE and DD registers */
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),
684  /* set VR mode: VRS/Hall */
685  CMD_VRSCONFIG(1, (0 << 4) |
686  (cfg->mode << 2) |
687  (0 << 0)),
688  /* enable outputs */
689  CMD_OE_SET
690  };
691 
692  ret = spi_rw_array(initTx, NULL, efi::size(initTx));
693 
694  if (ret == 0) {
695  /* enable pins */
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));
700  }
701 
704  }
705 
706  return ret;
707 }
708 
709 int Tle8888::wwd_feed() {
710  spi_rw(CMD_WWDSERVICECMD, NULL);
711 
712  return 0;
713 }
714 
715 int Tle8888::fwd_feed() {
716  uint16_t reg;
717 
718  spi_rw(CMD_FWDSTAT(1), NULL);
719  /* here we get response of the 'FWDStat1' above */
720  spi_rw(CMD_WDDIAG, &reg);
721 
722  uint8_t data = getDataFromResponse(reg);
723  uint8_t fwdquest = data & 0xF;
724  uint8_t fwdrespc = (data >> 4) & 3;
725  /* Table lines are filled in reverse order (like in DS) */
726  uint8_t response = tle8888_fwd_responses[fwdquest][3 - fwdrespc];
727  if (fwdrespc != 0) {
728  spi_rw(CMD_FWDRESPCMD(response), NULL);
729  } else {
730  /* to restart heartbeat timer, sync command should be used for response 0 */
731  spi_rw(CMD_FWDRESPSYNCCMD(response), NULL);
732  }
733 
734  return 0;
735 }
736 
737 int Tle8888::wd_get_status() {
738  uint16_t reg;
739 
740  spi_rw(CMD_WDDIAG, NULL);
741  spi_rw(CMD_WDDIAG, &reg);
742 
743  wd_diag = getDataFromResponse(reg);
744 
745  if (wd_diag & 0x70) {
746  /* Reset caused by TEC
747  * Reset caused by FWD
748  * Reset caused by WWD */
749  return -1;
750  }
751  if (wd_diag & 0x0f) {
752  /* Some error in WD handling */
753  return 1;
754  }
755 
756  return 0;
757 }
758 
759 int Tle8888::wd_feed() {
760  bool update_status = false;
761 
762  if (wwd_ts <= chVTGetSystemTimeX()) {
763  update_status = true;
764  if (wwd_feed() == 0) {
765  wwd_ts = chTimeAddX(chVTGetSystemTimeX(), TIME_MS2I(WWD_PERIOD_MS));
766  }
767  }
768 
769  if (fwd_ts <= chVTGetSystemTimeX()) {
770  update_status = true;
771  if (fwd_feed() == 0) {
772  fwd_ts = chTimeAddX(chVTGetSystemTimeX(), TIME_MS2I(FWD_PERIOD_MS));
773  }
774  }
775 
776  if (update_status) {
777  uint16_t wwd_reg, fwd_reg, tec_reg;
778 
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);
783 
784  wwd_err_cnt = getDataFromResponse(wwd_reg) & 0x7f;
785  fwd_err_cnt = getDataFromResponse(fwd_reg) & 0x7f;
786  tot_err_cnt = getDataFromResponse(tec_reg) & 0x7f;
787 
788  wd_happy = ((wwd_err_cnt == 0) &&
789  (fwd_err_cnt == 0));
790 
791  return wd_get_status();
792  } else {
793  return 0;
794  }
795 }
796 
797 int Tle8888::calc_sleep_interval() {
798  systime_t now = chVTGetSystemTimeX();
799 
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);
803 
804  if ((diag_delay <= wwd_delay) && (diag_delay <= fwd_delay))
805  return diag_delay;
806  if (fwd_delay <= wwd_delay)
807  return fwd_delay;
808  return wwd_delay;
809 }
810 
811 /*==========================================================================*/
812 /* Driver thread. */
813 /*==========================================================================*/
814 
815 static THD_FUNCTION(tle8888_driver_thread, p) {
816  Tle8888 *chip = reinterpret_cast<Tle8888*>(p);
817  sysinterval_t poll_interval = 0;
818 
819  chRegSetThreadName(DRIVER_NAME);
820 
821  while (1) {
822  int ret;
823  msg_t msg = chSemWaitTimeout(&chip->wake, poll_interval);
824 
825  /* should we care about msg == MSG_TIMEOUT? */
826  (void)msg;
827 
828  /* default polling interval */
829  poll_interval = TIME_MS2I(DIAG_PERIOD_MS);
830 
831  if ((chip->cfg == NULL) ||
832  (chip->drv_state == TLE8888_DISABLED) ||
833  (chip->drv_state == TLE8888_FAILED))
834  continue;
835 
836  bool wd_happy = chip->wd_happy;
837 
838  /* update outputs only if WD is happy */
839  if ((wd_happy) || (1)) {
840  ret = chip->update_output();
841  if (ret) {
842  /* set state to TLE8888_FAILED? */
843  }
844  }
845 
846  ret = chip->wd_feed();
847  if (ret < 0) {
848  /* WD is not happy */
849  continue;
850  }
851  /* happiness state has changed! */
852  if ((chip->wd_happy != wd_happy) && (chip->wd_happy)) {
853  chip->need_init = true;
854  }
855 
856  if (chip->need_init) {
857  /* clear first, as flag can be raised again during init */
858  chip->need_init = false;
859  /* re-init chip! */
860  chip->chip_init();
861  /* sync pins state */
862  chip->update_output();
863  }
864 
865  if (chip->diag_ts <= chVTGetSystemTimeX()) {
866  /* this is expensive call, will do a lot of spi transfers... */
867  ret = chip->update_status_and_diag();
868  if (ret) {
869  /* set state to TLE8888_FAILED or force reinit? */
870  } else {
871  diagResponse.reset();
872  }
873  /* TODO:
874  * Procedure to switch on after failure condition occurred:
875  * - Read out of diagnosis bits
876  * - Second read out to verify that the failure conditions are not
877  * remaining
878  * - Set of the dedicated output enable bit of the affected channel
879  * if the diagnosis bit is not active anymore
880  * - Switch on of the channel */
881 
882  chip->diag_ts = chTimeAddX(chVTGetSystemTimeX(), TIME_MS2I(DIAG_PERIOD_MS));
883  }
884 
885  poll_interval = chip->calc_sleep_interval();
886  }
887 }
888 
889 /*==========================================================================*/
890 /* Driver interrupt handlers. */
891 /*==========================================================================*/
892 
893 /*==========================================================================*/
894 /* Driver exported functions. */
895 /*==========================================================================*/
896 
897 int Tle8888::setPadMode(unsigned int pin, iomode_t mode) {
898  if (pin >= TLE8888_SIGNALS)
899  return -1;
900 
901  /* if someone has requested MR pin - switch it to manual mode */
902  if (pin == TLE8888_OUTPUT_MR) {
903  mr_manual = true;
904  }
905 
906  /* do not enalbe PP mode yet */
907 #if 0
908  /* only OUT21..OUT24 support mode change: PP vs OD */
909  if ((pin < 20) || (pin > 23))
910  return 0;
911 
912  /* this is absolutly confusing... we pass STM32 specific
913  * values to tle8888 driver... But this is how gpios
914  * currently implemented */
915  if ((mode & PAL_STM32_OTYPE_MASK) == PAL_STM32_OTYPE_OPENDRAIN) {
916  o_pp_mask &= ~BIT(pin);
917  } else {
918  o_pp_mask |= BIT(pin);
919  }
920 #else
921  (void)mode;
922 #endif
923 
924  return 0;
925 }
926 
927 int Tle8888::writePad(unsigned int pin, int value) {
928 
929  if (pin >= TLE8888_OUTPUTS)
930  return -1;
931 
932  {
933  chibios_rt::CriticalSectionLocker csl;
934 
935  if (value) {
936  o_state |= BIT(pin);
937  } else {
938  o_state &= ~BIT(pin);
939  }
940  }
941 
942  /* direct driven? */
943  if (o_direct_mask & BIT(pin)) {
944  return update_direct_output(pin, value);
945  } else {
946  return wake_driver();
947  }
948  return 0;
949 }
950 
951 int Tle8888::readPad(size_t pin) {
952  if (pin >= TLE8888_OUTPUTS)
953  return -1;
954 
955  if (pin < TLE8888_OUTPUTS_REGULAR) {
956  /* return output state */
957  /* TODO: check that pins is disabled by diagnostic? */
958  return !!(o_data_cached & BIT(pin));
959  } else if (pin == TLE8888_OUTPUT_MR) {
960  /* Main relay can be enabled by KEY input, so report real state */
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);
966  }
967 
968  /* unknown pin */
969  return -1;
970 }
971 
972 brain_pin_diag_e Tle8888::getOutputDiag(size_t pin) {
973  if (diagResponse.hasElapsedMs(500)) {
974  // has been too long since we've received diagnostics
975  return PIN_DRIVER_OFF;
976  }
977  /* OUT1..OUT4, indexes 0..3 */
978  if (pin < 4)
979  return tle8888_2b_to_diag_with_temp((OutDiag[0] >> ((pin - 0) * 2)) & 0x03);
980  /* OUT5..OUT7, indexes 4..6 */
981  if (pin < 7) {
982  return tle8888_2b_to_diag_with_temp((OutDiag[1] >> ((pin - 4) * 2)) & 0x03);
983  }
984  /* OUT8 to OUT13, indexes 7..12 */
985  if (pin < 13) {
986  int ret;
987 
988  /* OUT8 */
989  if (pin == 7)
990  ret = tle8888_2b_to_diag_no_temp((OutDiag[1] >> 6) & 0x03);
991  /* OUT9..OUT12 */
992  else if (pin < 12)
993  ret = tle8888_2b_to_diag_no_temp((OutDiag[2] >> ((pin - 8) * 2)) & 0x03);
994  /* OUT13 */
995  else /* if (pin == 12) */
996  ret = tle8888_2b_to_diag_no_temp((OutDiag[3] >> 0) & 0x03);
997 
998  /* overvoltage bit */
999  if (PPOVDiag & BIT(pin - 7))
1000  ret |= PIN_SHORT_TO_BAT;
1001 
1002  return static_cast<brain_pin_diag_e>(ret);
1003  }
1004  /* OUT14 to OUT16, indexes 13..15 */
1005  if (pin < 16)
1006  return tle8888_2b_to_diag_with_temp((OutDiag[3] >> ((pin - 13 + 1) * 2)) & 0x03);
1007  /* OUT17 to OUT20, indexes 16..19 */
1008  if (pin < 20)
1009  return tle8888_2b_to_diag_with_temp((OutDiag[4] >> ((pin - 16) * 2)) & 0x03);
1010  /* OUT21..OUT24, indexes 20..23 */
1011  if (pin < 24) {
1012  /* half bridges */
1013  int diag;
1014 
1015  diag = tle8888_2b_to_diag_no_temp((BriDiag[0] >> ((pin - 20) * 2)) & 0x03);
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; /* overcurrent */
1024 
1025  return static_cast<brain_pin_diag_e>(diag);
1026  }
1027  if (pin < 28)
1028  return tle8888_2b_to_diag_with_temp((IgnDiag >> ((pin - 24) * 2)) & 0x03);
1029 
1030  return PIN_OK;
1031 }
1032 
1033 brain_pin_diag_e Tle8888::getInputDiag(unsigned int pin)
1034 {
1035  (void)pin;
1036 
1037  return PIN_OK;
1038 }
1039 
1040 brain_pin_diag_e Tle8888::getDiag(size_t pin)
1041 {
1042  if (pin >= TLE8888_SIGNALS)
1043  return PIN_UNKNOWN;
1044 
1045  if (pin < TLE8888_OUTPUTS)
1046  return getOutputDiag(pin);
1047  else
1048  return getInputDiag(pin);
1049 }
1050 
1051 int Tle8888::chip_init_data() {
1052  int ret = 0;
1053 
1054  o_direct_mask = 0;
1055  o_oe_mask = 0;
1056  o_pp_mask = 0;
1057 
1058  /* mark pins used */
1059  if (cfg->reset.port != NULL) {
1060  ret |= gpio_pin_markUsed(cfg->reset.port, cfg->reset.pad, DRIVER_NAME " RST");
1061  palSetPadMode(cfg->reset.port, cfg->reset.pad, PAL_MODE_OUTPUT_PUSHPULL);
1062  palSetPort(cfg->reset.port, PAL_PORT_BIT(cfg->reset.pad));
1063  }
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));
1068  }
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));
1073  }
1074 
1075  for (int i = 0; i < TLE8888_DIRECT_MISC; i++) {
1076  /* Set some invalid default OUT number...
1077  * Keeping this register default (0) will map one of input signals
1078  * to OUT5 and no control over SPI for this pin will be possible.
1079  * If some other pin is also mapped to OUT5 both inputs should be
1080  * high (logical AND) to enable OUT5.
1081  * Set non-exist output in case no override is provided in config.
1082  * See code below */
1083  InConfig[i] = 25 - 1 - 4;
1084  }
1085 
1086  for (int i = 0; i < TLE8888_DIRECT_OUTPUTS; i++) {
1087  int out = -1;
1088  uint32_t mask;
1089 
1090  if (i < 4) {
1091  /* injector */
1092  out = i;
1093  } else if (i < 8) {
1094  /* ignition */
1095  out = (i - 4) + 24;
1096  } else {
1097  /* remappable */
1098  /* in config counted from 1 */
1099  out = cfg->direct_maps[i - 8].output - 1;
1100  }
1101 
1102  if ((out < 0) || (cfg->direct_gpio[i].port == NULL)) {
1103  /* now this is safe, InConfig[] is inited with some non-exist output */
1104  continue;
1105  }
1106 
1107  /* TODO: implement PP pin driving throught direct gpio */
1108  if ((cfg->stepper) && (out >= 20) && (out <= 23)) {
1109  /* now this is safe, InConfig[] is inited with some non-exist output */
1110  continue;
1111  }
1112 
1113  /* calculate mask */
1114  mask = BIT(out);
1115 
1116  /* check if output already occupied */
1117  if (o_direct_mask & mask) {
1118  /* incorrect config? */
1119  ret = -1;
1120  goto err_gpios;
1121  }
1122 
1123  /* configure source gpio */
1124  ret = gpio_pin_markUsed(cfg->direct_gpio[i].port, cfg->direct_gpio[i].pad, DRIVER_NAME " DIRECT IO");
1125  if (ret) {
1126  ret = -1;
1127  goto err_gpios;
1128  }
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));
1131 
1132  /* enable direct drive */
1133  o_direct_mask |= mask;
1134 
1135  /* calculate INCONFIG - aux input mapping for IN9..IN12 */
1136  if (i >= 8) {
1137  if ((out < 4) || (out >= 24)) {
1138  ret = -1;
1139  goto err_gpios;
1140  }
1141  InConfig[i - 8] = out - 4;
1142  }
1143  }
1144 
1145  /* Enable Push-Pull mode for OUT21..OUT24 */
1146  if (cfg->stepper) {
1147  o_pp_mask |= BIT(20) | BIT(21) | BIT(22) | BIT(23);
1148  }
1149 
1150  /* enable all direct driven */
1151  o_oe_mask |= o_direct_mask;
1152 
1153  /* enable all ouputs
1154  * TODO: add API to enable/disable? */
1155  o_oe_mask |= 0x0ffffff0;
1156 
1157  return 0;
1158 
1159 err_gpios:
1160  /* unmark pins */
1161  if (cfg->inj_en.port != NULL)
1162  gpio_pin_markUnused(cfg->inj_en.port, cfg->inj_en.pad);
1163  if (cfg->ign_en.port != NULL)
1164  gpio_pin_markUnused(cfg->ign_en.port, cfg->ign_en.pad);
1165  if (cfg->reset.port != NULL)
1166  gpio_pin_markUnused(cfg->reset.port, cfg->reset.pad);
1167  for (int i = 0; i < TLE8888_DIRECT_OUTPUTS; i++) {
1168  if (cfg->direct_gpio[i].port) {
1169  gpio_pin_markUnused(cfg->direct_gpio[i].port, cfg->direct_gpio[i].pad);
1170  }
1171  }
1172 
1173  return ret;
1174 }
1175 
1176 int Tle8888::init()
1177 {
1178  int ret;
1179 
1180  /* check for multiple init */
1181  if (drv_state != TLE8888_WAIT_INIT)
1182  return -1;
1183 
1184  ret = chip_reset();
1185  if (ret)
1186  return ret;
1187 
1188  ret = chip_init_data();
1189  if (ret)
1190  return ret;
1191 
1192  /* force init from driver thread */
1193  need_init = true;
1194 
1195  /* instance is ready */
1196  drv_state = TLE8888_READY;
1197 
1198  /* init semaphore */
1199  chSemObjectInit(&wake, 10);
1200 
1201  /* start thread */
1202  thread = chThdCreateStatic(thread_wa, sizeof(thread_wa),
1203  PRIO_GPIOCHIP, tle8888_driver_thread, this);
1204 
1205  return 0;
1206 }
1207 
1208 int Tle8888::deinit()
1209 {
1210  /* disable pins */
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));
1215 
1216  /* stop thread */
1217  chThdTerminate(thread);
1218 
1219  return 0;
1220 }
1221 
1222 /**
1223  * @brief TLE8888 driver add.
1224  * @details Checks for valid config
1225  * @return return gpio chip base
1226  */
1227 
1228 int tle8888_add(brain_pin_e base, unsigned int index, const tle8888_config *cfg) {
1229 
1230  efiAssert(ObdCode::OBD_PCM_Processor_Fault, cfg != NULL, "8888CFG", 0)
1231 
1232  /* no config or no such chip */
1233  if ((!cfg) || (!cfg->spi_bus) || (index >= BOARD_TLE8888_COUNT))
1234  return -1;
1235 
1236  /* check for valid chip select.
1237  * TODO: remove this check? CS can be driven by SPI */
1238  if (cfg->spi_config.ssport == NULL)
1239  return -1;
1240 
1241  Tle8888* chip = &chips[index];
1242 
1243  /* already initted? */
1244  if (chip->cfg)
1245  return -1;
1246 
1247  chip->cfg = cfg;
1248  chip->o_state = 0;
1249  chip->o_direct_mask = 0;
1250  chip->o_data_cached = 0;
1251  chip->drv_state = TLE8888_WAIT_INIT;
1252 
1253  /* register */
1254  int ret = gpiochip_register(base, DRIVER_NAME, *chip, TLE8888_OUTPUTS);
1255  if (ret < 0)
1256  return ret;
1257 
1258  /* set default pin names, board init code can rewrite */
1260 
1261  return ret;
1262 }
1263 
1264 /*==========================================================================*/
1265 /* Driver exported debug functions. */
1266 /*==========================================================================*/
1267 void Tle8888::read_reg(uint16_t reg, uint16_t *val)
1268 {
1269  spi_rw(CMD_R(reg), val);
1270 }
1271 
1273  auto& tle = chips[0];
1274 
1275  tle.need_init = true;
1276  tle.init_req_cnt++;
1277 }
1278 
1280  auto& chip = chips[0];
1281 
1282  // since responses are always in the NEXT transmission we will have this one first
1283  chip.read_reg(0, NULL);
1284 
1285  efiPrintf("register: data");
1286  for (int request = 0; request <= 0x7e + 1; request++) {
1287  uint16_t tmp;
1288  chip.read_reg(request < (0x7e + 1) ? request : 0x7e, &tmp);
1289  uint8_t reg = getRegisterFromResponse(tmp);
1290  uint8_t data = getDataFromResponse(tmp);
1291 
1292  efiPrintf("%02x: %02x", reg, data);
1293  }
1294 }
1295 
1296 #else /* BOARD_TLE8888_COUNT > 0 */
1297 
1298 int tle8888_add(brain_pin_e base, unsigned int index, const tle8888_config *cfg)
1299 {
1300  (void)base; (void)index; (void)cfg;
1301 
1302  return -1;
1303 }
1304 
1305 #endif /* (BOARD_TLE8888_COUNT > 0) */
TunerStudioOutputChannels outputChannels
Definition: engine.h:96
Gpio
int gpiochip_register(brain_pin_e base, const char *name, GpioChip &gpioChip, size_t size)
Register gpiochip.
Definition: core.cpp:125
int gpiochips_setPinNames(brain_pin_e base, const char **names)
Set pins names for registered gpiochip.
Definition: core.cpp:205
Engine * engine
static THD_WORKING_AREA(flashWriteStack, 3 *UTILITY_THREAD_STACK_SIZE)
uint32_t iomode_t
Digital I/O modes.
Definition: hal_pal_lld.h:83
static semaphore_t wake
Definition: hip9011.cpp:77
static SPIDriver * spi
Definition: hip9011.cpp:93
void writePad(const char *msg, brain_pin_e pin, int bit)
Definition: io_pins.cpp:115
@ 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)
brain_pin_diag_e
Definition: rusefi_enums.h:43
virtual brain_pin_diag_e getDiag(size_t)
Definition: gpio_ext.h:30
virtual int writePad(size_t, int)
Definition: gpio_ext.h:28
virtual int readPad(size_t)
Definition: gpio_ext.h:29
virtual int deinit()
Definition: gpio_ext.h:31
virtual int init()=0
virtual int setPadMode(size_t, iomode_t)
Definition: gpio_ext.h:27
SPIConfig spi_config
Definition: tle8888.h:44
SPIDriver * spi_bus
Definition: tle8888.h:43
const uint8_t tle8888_fwd_responses[16][4]
Definition: tle8888.cpp:138
static const char * tle8888_pin_names[TLE8888_SIGNALS]
Definition: tle8888.cpp:266
static brain_pin_diag_e tle8888_2b_to_diag_with_temp(unsigned int bits)
Definition: tle8888.cpp:607
static THD_FUNCTION(tle8888_driver_thread, p)
Definition: tle8888.cpp:815
void tle8888_dump_regs()
Definition: tle8888.cpp:1279
int tle8888_add(brain_pin_e base, unsigned int index, const tle8888_config *cfg)
TLE8888 driver add.
Definition: tle8888.cpp:1228
static Tle8888 chips[BOARD_TLE8888_COUNT]
Definition: tle8888.cpp:264
void tle8888PostState()
Definition: tle8888.cpp:279
void tle8888_req_init()
Definition: tle8888.cpp:1272
static Timer diagResponse
Definition: tle8888.cpp:42
tle8888_drv_state
Definition: tle8888.cpp:54
@ TLE8888_WAIT_INIT
Definition: tle8888.cpp:56
@ TLE8888_DISABLED
Definition: tle8888.cpp:55
@ TLE8888_FAILED
Definition: tle8888.cpp:58
@ TLE8888_READY
Definition: tle8888.cpp:57
static brain_pin_diag_e tle8888_2b_to_diag_no_temp(unsigned int bits)
Definition: tle8888.cpp:596
composite packet size