34#if EFI_PROD_CODE && (BOARD_L9779_COUNT > 0)
46#define DRIVER_NAME "l9779"
48#define DIAG_PERIOD_MS (7)
61#define MSG_SET_DATA(d) (((d) & 0xff) << 1)
63#define MSG_SET_SUBADDR(s) (((s) & 0x1f) << 1)
66#define MSG_SET_ADDR(a) (((a) & 0x1f) << 10)
70#define MSG_READ_ADDR (0x10)
72#define MSG_W(a, d) (static_cast<uint16_t>((MSG_SET_ADDR(a) | MSG_SET_DATA(d))))
73#define MSG_R(a) (static_cast<uint16_t>((MSG_SET_ADDR(MSG_READ_ADDR) | MSG_SET_SUBADDR(d))))
77#define MSG_GET_PARITY(x) (((x) >> 0) & 0x01)
79#define MSG_GET_ADDR(x) (((x) >> 10) & 0x1f)
81#define MSG_GET_DATA(x) (((x) >> 1) & 0xff)
85#define MSG_GET_SUBADDR(tx) (MSG_GET_DATA(tx) & 0x1f)
89#define MSG_GET_WR(rx) (((rx) >> 9) & 0x01)
91#define MSG_GET_SPIERROR(rx) (((rx) >> 15) & 0x01)
94#define REG_INVALID 0xff
97#define CMD_CLOCK_UNLOCK_SW_RST(d) MSG_W(0x0c, (d))
98#define CMD_START_REACT(d) MSG_W(0x0d, (d))
99#define CMD_CONTR_REG(n, d) MSG_W(0x08 + (n), (d))
104#define OUT_DIRECT_DRIVE_MASK 0x7ff
124 bool spi_parity_odd(uint16_t x);
125 int spi_validate(uint16_t rx);
126 int spi_rw(uint16_t tx, uint16_t *rx_ptr);
127 int spi_rw_array(
const uint16_t *tx, uint16_t *rx,
int n);
130 int update_direct_output(
size_t pin,
int value);
134 int chip_init_data();
152 uint32_t o_data_cached;
159 uint8_t last_subaddr;
175static L9779
chips[BOARD_L9779_COUNT];
178 "L9779.IGN1",
"L9779.IGN2",
"L9779.IGN3",
"L9779.IGN4",
179 "L9779.OUT1",
"L9779.OUT2",
"L9779.OUT3",
"L9779.OUT4",
180 "L9779.OUT5",
"L9779.OUT6",
"L9779.OUT7",
"L9779.OUT8",
181 "L9779.OUT9",
"L9779.OUT10",
"L9779.OUT11",
"L9779.OUT12",
182 "L9779.OUT13",
"L9779.OUT14",
"L9779.OUT15",
"L9779.OUT16",
183 "L9779.OUT17",
"L9779.OUT18",
"L9779.OUT19",
"L9779.OUT20",
184 "L9779.OUTA",
"L9779.OUTB",
"L9779.OUTC",
"L9779.OUTD",
185 "L9779.OUT25",
"L9779.OUT26",
"L9779.OUT27",
"L9779.OUT28",
186 "L9779.MRD",
"L9779.KEY"
194bool L9779::spi_parity_odd(uint16_t x)
204int L9779::spi_validate(uint16_t rx)
206 if (!spi_parity_odd(rx)) {
211 if (MSG_GET_SPIERROR(rx)) {
218 if (last_subaddr != REG_INVALID) {
221 if (!MSG_GET_WR(rx)) {
224 if (MSG_GET_ADDR(rx) != last_subaddr) {
236 if (last_addr == 0x0c) {
239 }
else if (last_addr == 0x0d) {
249int L9779::spi_rw(uint16_t tx, uint16_t *rx_ptr)
253 SPIDriver *spi = cfg->spi_bus;
256 tx |= !spi_parity_odd(tx);
261 spiStart(spi, &cfg->spi_config);
265 rx = spiPolledExchange(spi, tx);
280 ret = spi_validate(rx);
282 last_addr = MSG_GET_ADDR(recentTx);
283 if (last_addr == MSG_READ_ADDR)
284 last_subaddr = MSG_GET_SUBADDR(recentTx);
286 last_subaddr = REG_INVALID;
293int L9779::spi_rw_array(
const uint16_t *tx, uint16_t *rx,
int n)
296 SPIDriver *spi = cfg->spi_bus;
305 spiStart(spi, &cfg->spi_config);
307 for (
int i = 0; i < n; i++) {
311 uint16_t rxdata = spiPolledExchange(spi, tx[i]);
324 ret = spi_validate(rxdata);
326 last_addr = MSG_GET_ADDR(recentTx);
327 if (last_addr == MSG_READ_ADDR)
328 last_subaddr = MSG_GET_SUBADDR(recentTx);
330 last_subaddr = REG_INVALID;
343#define OUT_ENABLED(n) (!!(o_state & BIT((n) + L9779_OUTPUTS_IGN - 1)))
344#define SHIFT_N_OUT_TO_M(n, m) (OUT_ENABLED(n) << (m))
347#define IGN_ENABLED(n) (!!(o_state & BIT((n) - 1)))
348#define SHIFT_N_IGN_TO_M(n, m) (IGN_ENABLED(n) << (m))
350int L9779::update_output()
356 uint32_t o_data = o_state & ~OUT_DIRECT_DRIVE_MASK;
359 o_data = o_state | (o_oe_mask & OUT_DIRECT_DRIVE_MASK);
363 SHIFT_N_OUT_TO_M( 1, 7) |
364 SHIFT_N_OUT_TO_M( 2, 6) |
365 SHIFT_N_OUT_TO_M( 3, 5) |
366 SHIFT_N_OUT_TO_M( 4, 4) |
367 SHIFT_N_OUT_TO_M( 5, 3) |
368 SHIFT_N_OUT_TO_M(20, 2);
370 SHIFT_N_OUT_TO_M(15, 7) |
371 SHIFT_N_OUT_TO_M(14, 6) |
373 SHIFT_N_IGN_TO_M( 1, 3) |
374 SHIFT_N_IGN_TO_M( 2, 2) |
375 SHIFT_N_IGN_TO_M( 3, 1) |
376 SHIFT_N_IGN_TO_M( 4, 0);
378 SHIFT_N_OUT_TO_M(22, 7) |
379 SHIFT_N_OUT_TO_M(21, 6) |
380 SHIFT_N_OUT_TO_M(16, 5) |
381 SHIFT_N_OUT_TO_M(14, 4) |
382 SHIFT_N_OUT_TO_M(17, 3) |
383 SHIFT_N_OUT_TO_M(18, 2) |
384 SHIFT_N_OUT_TO_M( 7, 1) |
385 SHIFT_N_OUT_TO_M( 6, 0);
387 SHIFT_N_OUT_TO_M(28, 5) |
388 SHIFT_N_OUT_TO_M(27, 4) |
389 SHIFT_N_OUT_TO_M(26, 3) |
390 SHIFT_N_OUT_TO_M(25, 2) |
391 SHIFT_N_OUT_TO_M(24, 1) |
392 SHIFT_N_OUT_TO_M(23, 0);
395 CMD_CONTR_REG(0, regs[0]),
396 CMD_CONTR_REG(1, regs[1]),
397 CMD_CONTR_REG(2, regs[2]),
398 CMD_CONTR_REG(3, regs[3])
400 ret = spi_rw_array(tx, NULL, efi::size(tx));
404 o_data_cached = o_data;
410int L9779::update_direct_output(
size_t pin,
int value)
413 if (cfg->direct_gpio[
pin].port == NULL)
417 palSetPort(cfg->direct_gpio[
pin].port,
418 PAL_PORT_BIT(cfg->direct_gpio[
pin].pad));
420 palClearPort(cfg->direct_gpio[
pin].port,
421 PAL_PORT_BIT(cfg->direct_gpio[
pin].pad));
430int L9779::wake_driver()
433 chibios_rt::CriticalSectionLocker csl;
435 if (!port_is_isr_context()) {
446int L9779::chip_reset() {
449 last_addr = REG_INVALID;
450 last_subaddr = REG_INVALID;
452 ret = spi_rw(CMD_CLOCK_UNLOCK_SW_RST(BIT(1)), NULL);
456 chThdSleepMilliseconds(3);
458 last_addr = REG_INVALID;
459 last_subaddr = REG_INVALID;
469 L9779 *chip =
reinterpret_cast<L9779*
>(p);
470 sysinterval_t poll_interval = 0;
472 chRegSetThreadName(DRIVER_NAME);
476 msg_t msg = chSemWaitTimeout(&chip->wake, poll_interval);
482 poll_interval = TIME_MS2I(DIAG_PERIOD_MS);
484 if ((chip->cfg == NULL) ||
490 bool wd_happy = chip->wd_happy;
493 if ((wd_happy) || (1)) {
494 ret = chip->update_output();
500 ret = chip->wd_feed();
506 if ((chip->wd_happy != wd_happy) && (chip->wd_happy)) {
507 chip->need_init =
true;
511 if (chip->need_init) {
513 chip->need_init =
false;
517 chip->update_output();
521 if (chip->need_init ==
false) {
523 ret = chip->update_output();
529 if (chip->diag_ts <= chVTGetSystemTimeX()) {
531 ret = chip->update_status_and_diag();
546 chip->diag_ts = chTimeAddX(chVTGetSystemTimeX(), TIME_MS2I(DIAG_PERIOD_MS));
548 poll_interval = chip->calc_sleep_interval();
561int L9779::setPadMode(
unsigned int pin,
iomode_t mode) {
562 if (
pin >= L9779_SIGNALS)
570int L9779::writePad(
unsigned int pin,
int value) {
571 if (
pin >= L9779_OUTPUTS)
575 chibios_rt::CriticalSectionLocker csl;
578 o_state |= (1 <<
pin);
580 o_state &= ~(1 <<
pin);
585 if (OUT_DIRECT_DRIVE_MASK & BIT(
pin)) {
586 return update_direct_output(
pin, value);
588 return wake_driver();
608int L9779::readPad(
size_t pin) {
609 if (
pin >= L9779_SIGNALS)
618 if (
pin >= L9779_SIGNALS)
621 if (
pin < L9779_OUTPUTS)
622 return getOutputDiag(
pin);
624 return getInputDiag(
pin);
628int L9779::chip_init_data(
void)
634 for (
int i = 0; i < L9779_DIRECT_OUTPUTS; i++) {
635 if (cfg->direct_gpio[i].port == NULL)
639 ret =
gpio_pin_markUsed(cfg->direct_gpio[i].port, cfg->direct_gpio[i].pad, DRIVER_NAME
" DIRECT IO");
644 palSetPadMode(cfg->direct_gpio[i].port, cfg->direct_gpio[i].pad, PAL_MODE_OUTPUT_PUSHPULL);
645 palClearPort(cfg->direct_gpio[i].port, PAL_PORT_BIT(cfg->direct_gpio[i].pad));
653 o_oe_mask |= ~OUT_DIRECT_DRIVE_MASK;
659 for (
int i = 0; i < L9779_DIRECT_OUTPUTS; i++) {
660 if (cfg->direct_gpio[i].port) {
668int L9779::chip_init()
676 ret = spi_rw(CMD_CLOCK_UNLOCK_SW_RST(0), NULL);
681 ret = spi_rw(CMD_START_REACT(BIT(1)), NULL);
702 ret = chip_init_data();
713 chSemObjectInit(&wake, 10);
716 thread = chThdCreateStatic(thread_wa,
sizeof(thread_wa),
717 PRIO_GPIOCHIP, l9779_driver_thread,
this);
738 if ((!cfg) || (!cfg->
spi_bus) || (index >= BOARD_L9779_COUNT))
741 L9779* chip = &
chips[index];
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.
uint32_t iomode_t
Digital I/O modes.
static const char * l9779_pin_names[L9779_SIGNALS]
static THD_FUNCTION(l9779_driver_thread, p)
static L9779 chips[BOARD_L9779_COUNT]
int l9779_add(brain_pin_e base, unsigned int index, const l9779_config *cfg)
L9779 driver add.
@ OBD_PCM_Processor_Fault
void gpio_pin_markUnused(ioportid_t port, ioportmask_t pin)
bool gpio_pin_markUsed(ioportid_t port, ioportmask_t pin, const char *msg)
static THD_WORKING_AREA(storageManagerThreadStack, 3 *UTILITY_THREAD_STACK_SIZE)
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)
static Timer diagResponse