158 lines
4.4 KiB
C
158 lines
4.4 KiB
C
/*
|
|
* Copyright (c) 2024 Analog Devices Inc.
|
|
* Copyright (c) 2024 Baylibre SAS
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#ifndef ZEPHYR_DRIVERS_GPIO_GPIO_MAX149X6_H_
|
|
#define ZEPHYR_DRIVERS_GPIO_GPIO_MAX149X6_H_
|
|
|
|
#define MAX149x6_READ 0
|
|
#define MAX149x6_WRITE 1
|
|
|
|
#define MAX149X6_GET_BIT(val, i) (0x1 & ((val) >> (i)))
|
|
#define PRINT_ERR_BIT(bit1, bit2) \
|
|
if ((bit1) & (bit2)) \
|
|
LOG_ERR("[%s] %d", #bit1, bit1)
|
|
#define PRINT_ERR(bit) \
|
|
if (bit) \
|
|
LOG_ERR("[DIAG] [%s] %d\n", #bit, bit)
|
|
#define PRINT_INF(bit) LOG_INFO("[%s] %d\n", #bit, bit)
|
|
#define LOG_DIAG(...) Z_LOG(LOG_LEVEL_ERR, __VA_ARGS__)
|
|
|
|
/**
|
|
* @brief Compute the CRC5 value for an array of bytes when writing to MAX149X6
|
|
* @param data - array of data to encode
|
|
* @param encode - action to be performed - true(encode), false(decode)
|
|
* @return the resulted CRC5
|
|
*/
|
|
static uint8_t max149x6_crc(uint8_t *data, bool encode)
|
|
{
|
|
uint8_t crc5_start = 0x1f;
|
|
uint8_t crc5_poly = 0x15;
|
|
uint8_t crc5_result = crc5_start;
|
|
uint8_t extra_byte = 0x00;
|
|
uint8_t data_bit;
|
|
uint8_t result_bit;
|
|
int i;
|
|
|
|
/*
|
|
* This is a custom implementation of a CRC5 algorithm, detailed here:
|
|
* https://www.analog.com/en/app-notes/how-to-program-the-max14906-quadchannel-
|
|
* industrial-digital-output-digital-input.html
|
|
*/
|
|
|
|
for (i = (encode) ? 0 : 2; i < 8; i++) {
|
|
data_bit = (data[0] >> (7 - i)) & 0x01;
|
|
result_bit = (crc5_result & 0x10) >> 4;
|
|
if (data_bit ^ result_bit) {
|
|
crc5_result = crc5_poly ^ ((crc5_result << 1) & 0x1f);
|
|
} else {
|
|
crc5_result = (crc5_result << 1) & 0x1f;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
data_bit = (data[1] >> (7 - i)) & 0x01;
|
|
result_bit = (crc5_result & 0x10) >> 4;
|
|
if (data_bit ^ result_bit) {
|
|
crc5_result = crc5_poly ^ ((crc5_result << 1) & 0x1f);
|
|
} else {
|
|
crc5_result = (crc5_result << 1) & 0x1f;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
data_bit = (extra_byte >> (7 - i)) & 0x01;
|
|
result_bit = (crc5_result & 0x10) >> 4;
|
|
if (data_bit ^ result_bit) {
|
|
crc5_result = crc5_poly ^ ((crc5_result << 1) & 0x1f);
|
|
} else {
|
|
crc5_result = (crc5_result << 1) & 0x1f;
|
|
}
|
|
}
|
|
|
|
return crc5_result;
|
|
}
|
|
|
|
/*
|
|
* @brief Register read/write function for MAX149x6
|
|
*
|
|
* @param dev - MAX149x6 device config.
|
|
* @param addr - Register value to which data is written.
|
|
* @param val - Value which is to be written to requested register.
|
|
* @return 0 in case of success, negative error code otherwise.
|
|
*/
|
|
static int max149x6_reg_transceive(const struct device *dev, uint8_t addr, uint8_t val,
|
|
uint8_t *rx_diag_buff, uint8_t rw)
|
|
{
|
|
uint8_t crc;
|
|
int ret;
|
|
|
|
uint8_t local_rx_buff[MAX149x6_MAX_PKT_SIZE] = {0};
|
|
uint8_t local_tx_buff[MAX149x6_MAX_PKT_SIZE] = {0};
|
|
|
|
const struct max149x6_config *config = dev->config;
|
|
|
|
struct spi_buf tx_buf = {
|
|
.buf = &local_tx_buff,
|
|
.len = config->pkt_size,
|
|
};
|
|
const struct spi_buf_set tx = {.buffers = &tx_buf, .count = 1};
|
|
|
|
struct spi_buf rx_buf = {
|
|
.buf = &local_rx_buff,
|
|
.len = config->pkt_size,
|
|
};
|
|
const struct spi_buf_set rx = {.buffers = &rx_buf, .count = 1};
|
|
|
|
if (config->crc_en & 0) {
|
|
rx_buf.len++;
|
|
}
|
|
|
|
local_tx_buff[0] = FIELD_PREP(MAX149x6_ADDR_MASK, addr) |
|
|
FIELD_PREP(MAX149x6_CHIP_ADDR_MASK, config->spi_addr) |
|
|
FIELD_PREP(MAX149x6_RW_MASK, rw & 0x1);
|
|
local_tx_buff[1] = val;
|
|
|
|
/* If CRC enabled calculate it */
|
|
if (config->crc_en) {
|
|
local_tx_buff[2] = max149x6_crc(&local_tx_buff[0], true);
|
|
}
|
|
|
|
/* write cmd & read resp at once */
|
|
ret = spi_transceive_dt(&config->spi, &tx, &rx);
|
|
|
|
if (ret) {
|
|
LOG_ERR("Err spi_transcieve_dt [%d]\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* if CRC enabled check readed */
|
|
if (config->crc_en) {
|
|
crc = max149x6_crc(&local_rx_buff[0], false);
|
|
if (crc != (local_rx_buff[2] & 0x1F)) {
|
|
LOG_ERR("READ CRC ERR (%d)-(%d)\n", crc, (local_rx_buff[2] & 0x1F));
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
if (rx_diag_buff != NULL) {
|
|
rx_diag_buff[0] = local_rx_buff[0];
|
|
}
|
|
|
|
/* In case of write we are getting 2 diagnostic bytes - byte0 & byte1
|
|
* and pass them to diag buffer to be parsed in next stage
|
|
*/
|
|
if ((MAX149x6_WRITE == rw) && (rx_diag_buff != NULL)) {
|
|
rx_diag_buff[1] = local_rx_buff[1];
|
|
} else {
|
|
ret = local_rx_buff[1];
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif
|