You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
404 lines
13 KiB
404 lines
13 KiB
/* |
|
* Copyright (c) 2024 Analog Devices Inc. |
|
* Copyright (c) 2024 Baylibre SAS |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <zephyr/drivers/gpio.h> |
|
#include <zephyr/drivers/spi.h> |
|
#include <zephyr/kernel.h> |
|
#include <zephyr/sys/byteorder.h> |
|
|
|
#define LOG_LEVEL CONFIG_GPIO_LOG_LEVEL |
|
#include <zephyr/logging/log.h> |
|
|
|
LOG_MODULE_REGISTER(gpio_max14916); |
|
|
|
#include <zephyr/drivers/gpio/gpio_utils.h> |
|
|
|
#include "gpio_max14916.h" |
|
#include "gpio_max149x6.h" |
|
|
|
static int gpio_max14916_diag_chan_get(const struct device *dev); |
|
|
|
static int max14916_pars_spi_diag(const struct device *dev, uint8_t *rx_diag_buff, uint8_t rw) |
|
{ |
|
struct max14916_data *data = dev->data; |
|
int ret = 0; |
|
|
|
if (rx_diag_buff[0]) { |
|
LOG_ERR("[DIAG] MAX14916 in SPI diag - error detected"); |
|
|
|
data->glob.interrupt.reg_bits.SHT_VDD_FLT = MAX149X6_GET_BIT(rx_diag_buff[0], 5); |
|
data->glob.interrupt.reg_bits.OW_ON_FLT = MAX149X6_GET_BIT(rx_diag_buff[0], 4); |
|
data->glob.interrupt.reg_bits.OW_OFF_FLT = MAX149X6_GET_BIT(rx_diag_buff[0], 3); |
|
data->glob.interrupt.reg_bits.CURR_LIM = MAX149X6_GET_BIT(rx_diag_buff[0], 2); |
|
data->glob.interrupt.reg_bits.OVER_LD_FLT = MAX149X6_GET_BIT(rx_diag_buff[0], 1); |
|
|
|
if (MAX149X6_GET_BIT(rx_diag_buff[0], 0)) { |
|
LOG_ERR("[DIAG] MAX14916 in SPI diag - GLOBAL FAULT detected"); |
|
} |
|
|
|
ret = -EIO; |
|
|
|
PRINT_ERR(data->glob.interrupt.reg_bits.SHT_VDD_FLT); |
|
PRINT_ERR(data->glob.interrupt.reg_bits.OW_ON_FLT); |
|
PRINT_ERR(data->glob.interrupt.reg_bits.OW_OFF_FLT); |
|
PRINT_ERR(data->glob.interrupt.reg_bits.CURR_LIM); |
|
PRINT_ERR(data->glob.interrupt.reg_bits.OVER_LD_FLT); |
|
} |
|
|
|
if (rw == MAX149x6_WRITE && (rx_diag_buff[1] & 0x0f)) { |
|
/* +-----------------------------------------------------------------------+ |
|
* | LSB BYTE 2 MSB | |
|
* +--------+--------+--------+--------+--------+--------+--------+--------+ |
|
* | BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7 | |
|
* +--------+--------+--------+--------+--------+--------+--------+--------+ |
|
* | Fault1 | Fault2 | Fault3 | Fault4 | Fault5 | Fault6 | Fault7 | Fault8 | |
|
* +--------+--------+--------+--------+--------+--------+--------+--------+ |
|
*/ |
|
|
|
LOG_ERR("[DIAG] Flt1[%x] Flt2[%x] Flt3[%x]" |
|
"Flt4[%x] Flt5[%x] Flt6[%x] Flt7[%x] Flt8[%x]\n", |
|
MAX149X6_GET_BIT(rx_diag_buff[1], 0), MAX149X6_GET_BIT(rx_diag_buff[1], 1), |
|
MAX149X6_GET_BIT(rx_diag_buff[1], 2), MAX149X6_GET_BIT(rx_diag_buff[1], 3), |
|
MAX149X6_GET_BIT(rx_diag_buff[1], 4), MAX149X6_GET_BIT(rx_diag_buff[1], 5), |
|
MAX149X6_GET_BIT(rx_diag_buff[1], 6), MAX149X6_GET_BIT(rx_diag_buff[1], 7)); |
|
|
|
if (rx_diag_buff[1]) { |
|
LOG_ERR("[DIAG] gpio_max14916_diag_chan_get(%x)\n", rx_diag_buff[1] & 0x0f); |
|
ret = gpio_max14916_diag_chan_get(dev); |
|
} |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
static int max14916_reg_trans_spi_diag(const struct device *dev, uint8_t addr, uint8_t tx, |
|
uint8_t rw) |
|
{ |
|
const struct max14916_config *config = dev->config; |
|
uint8_t rx_diag_buff[2]; |
|
|
|
if (!gpio_pin_get_dt(&config->fault_gpio)) { |
|
LOG_ERR(" >>> FLT PIN"); |
|
} |
|
|
|
int ret = max149x6_reg_transceive(dev, addr, tx, rx_diag_buff, rw); |
|
|
|
if (max14916_pars_spi_diag(dev, rx_diag_buff, rw)) { |
|
ret = -EIO; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
#define MAX14916_REG_READ(dev, addr) max14916_reg_trans_spi_diag(dev, addr, 0, MAX149x6_READ) |
|
#define MAX14916_REG_WRITE(dev, addr, val) \ |
|
max14916_reg_trans_spi_diag(dev, addr, val, MAX149x6_WRITE) |
|
|
|
static int gpio_max14916_diag_chan_get(const struct device *dev) |
|
{ |
|
const struct max14916_config *config = dev->config; |
|
struct max14916_data *data = dev->data; |
|
int ret = 0; |
|
|
|
if (!gpio_pin_get_dt(&config->fault_gpio)) { |
|
LOG_ERR("FLT flag is rised"); |
|
ret = -EIO; |
|
} |
|
|
|
data->glob.interrupt.reg_raw = |
|
max149x6_reg_transceive(dev, MAX14916_INT_REG, 0, NULL, MAX149x6_READ); |
|
|
|
if (data->glob.interrupt.reg_raw) { |
|
if (data->glob.interrupt.reg_bits.OVER_LD_FLT) { |
|
data->chan.ovr_ld = max149x6_reg_transceive(dev, MAX14916_OVR_LD_REG, 0, |
|
NULL, MAX149x6_READ); |
|
} |
|
if (data->glob.interrupt.reg_bits.CURR_LIM) { |
|
data->chan.curr_lim = max149x6_reg_transceive(dev, MAX14916_CURR_LIM_REG, 0, |
|
NULL, MAX149x6_READ); |
|
} |
|
if (data->glob.interrupt.reg_bits.OW_OFF_FLT) { |
|
data->chan.ow_off = max149x6_reg_transceive(dev, MAX14916_OW_OFF_FLT_REG, 0, |
|
NULL, MAX149x6_READ); |
|
} |
|
if (data->glob.interrupt.reg_bits.OW_ON_FLT) { |
|
data->chan.ow_on = max149x6_reg_transceive(dev, MAX14916_OW_ON_FLT_REG, 0, |
|
NULL, MAX149x6_READ); |
|
} |
|
if (data->glob.interrupt.reg_bits.SHT_VDD_FLT) { |
|
data->chan.sht_vdd = max149x6_reg_transceive(dev, MAX14916_SHT_VDD_FLT_REG, |
|
0, NULL, MAX149x6_READ); |
|
} |
|
|
|
if (data->glob.interrupt.reg_bits.SUPPLY_ERR) { |
|
data->glob.glob_err.reg_raw = max149x6_reg_transceive( |
|
dev, MAX14916_GLOB_ERR_REG, 0, NULL, MAX149x6_READ); |
|
PRINT_ERR(data->glob.glob_err.reg_bits.VINT_UV); |
|
PRINT_ERR(data->glob.glob_err.reg_bits.VA_UVLO); |
|
PRINT_ERR(data->glob.glob_err.reg_bits.VDD_BAD); |
|
PRINT_ERR(data->glob.glob_err.reg_bits.VDD_WARN); |
|
PRINT_ERR(data->glob.glob_err.reg_bits.VDD_UVLO); |
|
PRINT_ERR(data->glob.glob_err.reg_bits.THRMSHUTD); |
|
PRINT_ERR(data->glob.glob_err.reg_bits.SYNC_ERR); |
|
PRINT_ERR(data->glob.glob_err.reg_bits.WDOG_ERR); |
|
} |
|
|
|
if (data->glob.interrupt.reg_bits.COM_ERR) { |
|
LOG_ERR("MAX14916 Communication Error"); |
|
} |
|
ret = -EIO; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
static int gpio_max14916_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) |
|
{ |
|
int ret; |
|
uint32_t reg_val = 0; |
|
|
|
ret = MAX14916_REG_READ(dev, MAX14916_SETOUT_REG); |
|
reg_val = ret | pins; |
|
|
|
return MAX14916_REG_WRITE(dev, MAX14916_SETOUT_REG, reg_val); |
|
} |
|
|
|
static int gpio_max14916_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) |
|
{ |
|
int ret; |
|
uint32_t reg_val = 0; |
|
|
|
ret = MAX14916_REG_READ(dev, MAX14916_SETOUT_REG); |
|
reg_val = ret & ~pins; |
|
|
|
return MAX14916_REG_WRITE(dev, MAX14916_SETOUT_REG, reg_val); |
|
} |
|
|
|
static int gpio_max14916_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) |
|
{ |
|
int err = 0; |
|
|
|
if ((flags & (GPIO_INPUT | GPIO_OUTPUT)) == GPIO_DISCONNECTED) { |
|
return -ENOTSUP; |
|
} |
|
|
|
if ((flags & GPIO_SINGLE_ENDED) != 0) { |
|
return -ENOTSUP; |
|
} |
|
|
|
if ((flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != 0) { |
|
return -ENOTSUP; |
|
} |
|
|
|
if (flags & GPIO_INT_ENABLE) { |
|
return -ENOTSUP; |
|
} |
|
|
|
switch (flags & GPIO_DIR_MASK) { |
|
case GPIO_OUTPUT: |
|
break; |
|
case GPIO_INPUT: |
|
default: |
|
LOG_ERR("NOT SUPPORTED OPTION!"); |
|
return -ENOTSUP; |
|
} |
|
|
|
return err; |
|
} |
|
|
|
static int gpio_max14916_port_get_raw(const struct device *dev, gpio_port_value_t *value) |
|
{ |
|
*value = MAX14916_REG_READ(dev, MAX14916_SETOUT_REG); |
|
|
|
return 0; |
|
} |
|
|
|
static int gpio_max14916_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) |
|
{ |
|
int ret; |
|
uint32_t reg_val = 0; |
|
|
|
ret = MAX14916_REG_READ(dev, MAX14916_SETOUT_REG); |
|
|
|
reg_val = ret; |
|
reg_val ^= pins; |
|
|
|
MAX14916_REG_WRITE(dev, MAX14916_SETOUT_REG, reg_val); |
|
|
|
return 0; |
|
} |
|
|
|
static int gpio_max14916_clean_on_power(const struct device *dev) |
|
{ |
|
int ret; |
|
|
|
/* Clear the latched faults generated at power up */ |
|
ret = MAX14916_REG_READ(dev, MAX14916_OW_OFF_FLT_REG); |
|
if (ret < 0) { |
|
LOG_ERR("Error reading MAX14916_OW_OFF_FLT_REG"); |
|
goto err_clean_on_power_max14916; |
|
} |
|
|
|
ret = MAX14916_REG_READ(dev, MAX14916_OVR_LD_REG); |
|
if (ret < 0) { |
|
LOG_ERR("Error reading MAX14916_OVR_LD_REG"); |
|
goto err_clean_on_power_max14916; |
|
} |
|
|
|
ret = MAX14916_REG_READ(dev, MAX14916_SHT_VDD_FLT_REG); |
|
if (ret < 0) { |
|
LOG_ERR("Error reading MAX14916_SHD_VDD_FLT_REG"); |
|
goto err_clean_on_power_max14916; |
|
} |
|
|
|
ret = MAX14916_REG_READ(dev, MAX14916_GLOB_ERR_REG); |
|
if (ret < 0) { |
|
LOG_ERR("Error reading MAX14916_GLOBAL_FLT_REG"); |
|
goto err_clean_on_power_max14916; |
|
} |
|
|
|
err_clean_on_power_max14916: |
|
return ret; |
|
} |
|
|
|
static int gpio_max14916_config_diag(const struct device *dev) |
|
{ |
|
const struct max14916_config *config = dev->config; |
|
struct max14916_data *data = dev->data; |
|
|
|
MAX14916_REG_WRITE(dev, MAX14916_CONFIG1_REG, config->config1.reg_raw); |
|
MAX14916_REG_WRITE(dev, MAX14916_CONFIG2_REG, config->config2.reg_raw); |
|
MAX14916_REG_WRITE(dev, MAX14916_OW_OFF_EN_REG, data->chan_en.ow_on_en); |
|
MAX14916_REG_WRITE(dev, MAX14916_OW_OFF_EN_REG, data->chan_en.ow_off_en); |
|
MAX14916_REG_WRITE(dev, MAX14916_SHT_VDD_EN_REG, data->chan_en.sht_vdd_en); |
|
return 0; |
|
} |
|
|
|
static int gpio_max14916_init(const struct device *dev) |
|
{ |
|
const struct max14916_config *config = dev->config; |
|
int err = 0; |
|
|
|
LOG_DBG(" --- GPIO MAX14916 init IN ---"); |
|
|
|
if (!spi_is_ready_dt(&config->spi)) { |
|
LOG_ERR("SPI bus is not ready\n"); |
|
return -ENODEV; |
|
} |
|
|
|
/* setup READY gpio - normal low */ |
|
if (!gpio_is_ready_dt(&config->ready_gpio)) { |
|
LOG_ERR("READY GPIO device not ready"); |
|
return -ENODEV; |
|
} |
|
|
|
err = gpio_pin_configure_dt(&config->ready_gpio, GPIO_INPUT); |
|
if (err < 0) { |
|
LOG_ERR("Failed to configure reset GPIO"); |
|
return err; |
|
} |
|
|
|
/* setup FLT gpio - normal high */ |
|
if (!gpio_is_ready_dt(&config->fault_gpio)) { |
|
LOG_ERR("FLT GPIO device not ready"); |
|
return -ENODEV; |
|
} |
|
|
|
err = gpio_pin_configure_dt(&config->fault_gpio, GPIO_INPUT); |
|
if (err < 0) { |
|
LOG_ERR("Failed to configure DC GPIO"); |
|
return err; |
|
} |
|
|
|
/* setup LATCH gpio - normal high */ |
|
if (!gpio_is_ready_dt(&config->sync_gpio)) { |
|
LOG_ERR("SYNC GPIO device not ready"); |
|
return -ENODEV; |
|
} |
|
|
|
err = gpio_pin_configure_dt(&config->sync_gpio, GPIO_OUTPUT_INACTIVE); |
|
if (err < 0) { |
|
LOG_ERR("Failed to configure busy GPIO"); |
|
return err; |
|
} |
|
|
|
/* setup LATCH gpio - normal high */ |
|
if (!gpio_is_ready_dt(&config->en_gpio)) { |
|
LOG_ERR("SYNC GPIO device not ready"); |
|
return -ENODEV; |
|
} |
|
|
|
err = gpio_pin_configure_dt(&config->en_gpio, GPIO_OUTPUT_INACTIVE); |
|
if (err < 0) { |
|
LOG_ERR("Failed to configure busy GPIO"); |
|
return err; |
|
} |
|
|
|
gpio_pin_set_dt(&config->en_gpio, 1); |
|
gpio_pin_set_dt(&config->sync_gpio, 1); |
|
|
|
LOG_ERR("[GPIO] FALUT - %d\n", gpio_pin_get_dt(&config->fault_gpio)); |
|
LOG_ERR("[GPIO] READY - %d\n", gpio_pin_get_dt(&config->ready_gpio)); |
|
LOG_ERR("[GPIO] SYNC - %d\n", gpio_pin_get_dt(&config->sync_gpio)); |
|
LOG_ERR("[GPIO] EN - %d\n", gpio_pin_get_dt(&config->en_gpio)); |
|
|
|
int ret = gpio_max14916_clean_on_power(dev); |
|
|
|
MAX14916_REG_WRITE(dev, MAX14916_SETOUT_REG, 0); |
|
|
|
gpio_max14916_config_diag(dev); |
|
|
|
LOG_DBG(" --- GPIO MAX14916 init OUT ---"); |
|
|
|
return ret; |
|
} |
|
|
|
static DEVICE_API(gpio, gpio_max14916_api) = { |
|
.pin_configure = gpio_max14916_config, |
|
.port_get_raw = gpio_max14916_port_get_raw, |
|
.port_set_bits_raw = gpio_max14916_port_set_bits_raw, |
|
.port_clear_bits_raw = gpio_max14916_port_clear_bits_raw, |
|
.port_toggle_bits = gpio_max14916_port_toggle_bits, |
|
}; |
|
|
|
#define GPIO_MAX14906_DEVICE(id, model) \ |
|
static const struct max14916_config max##model##_##id##_cfg = { \ |
|
.spi = SPI_DT_SPEC_INST_GET(id, SPI_OP_MODE_MASTER | SPI_WORD_SET(8U), 0U), \ |
|
.ready_gpio = GPIO_DT_SPEC_INST_GET(id, drdy_gpios), \ |
|
.fault_gpio = GPIO_DT_SPEC_INST_GET(id, fault_gpios), \ |
|
.sync_gpio = GPIO_DT_SPEC_INST_GET(id, sync_gpios), \ |
|
.en_gpio = GPIO_DT_SPEC_INST_GET(id, en_gpios), \ |
|
.crc_en = DT_INST_PROP(id, crc_en), \ |
|
.config1.reg_bits.FLED_SET = DT_INST_PROP(id, fled_set), \ |
|
.config1.reg_bits.SLED_SET = DT_INST_PROP(id, sled_set), \ |
|
.config1.reg_bits.FLED_STRETCH = DT_INST_PROP(id, fled_stretch), \ |
|
.config1.reg_bits.FFILTER_EN = DT_INST_PROP(id, ffilter_en), \ |
|
.config1.reg_bits.FILTER_LONG = DT_INST_PROP(id, filter_long), \ |
|
.config1.reg_bits.FLATCH_EN = DT_INST_PROP(id, flatch_en), \ |
|
.config1.reg_bits.LED_CURR_LIM = DT_INST_PROP(id, led_cur_lim), \ |
|
.config2.reg_bits.VDD_ON_THR = DT_INST_PROP(id, vdd_on_thr), \ |
|
.config2.reg_bits.SYNCH_WD_EN = DT_INST_PROP(id, synch_wd_en), \ |
|
.config2.reg_bits.SHT_VDD_THR = DT_INST_PROP(id, sht_vdd_thr), \ |
|
.config2.reg_bits.OW_OFF_CS = DT_INST_PROP(id, ow_off_cs), \ |
|
.config2.reg_bits.WD_TO = DT_INST_PROP(id, wd_to), \ |
|
.pkt_size = (DT_INST_PROP(id, crc_en) & 0x1) ? 3 : 2, \ |
|
.spi_addr = DT_INST_PROP(id, spi_addr), \ |
|
}; \ |
|
\ |
|
static struct max14916_data max##model##_##id##_data; \ |
|
\ |
|
DEVICE_DT_INST_DEFINE(id, &gpio_max14916_init, NULL, &max##model##_##id##_data, \ |
|
&max##model##_##id##_cfg, POST_KERNEL, \ |
|
CONFIG_GPIO_MAX14916_INIT_PRIORITY, &gpio_max14916_api); |
|
|
|
#undef DT_DRV_COMPAT |
|
#define DT_DRV_COMPAT adi_max14915_gpio |
|
DT_INST_FOREACH_STATUS_OKAY_VARGS(GPIO_MAX14906_DEVICE, 14915) |
|
|
|
#undef DT_DRV_COMPAT |
|
#define DT_DRV_COMPAT adi_max14916_gpio |
|
DT_INST_FOREACH_STATUS_OKAY_VARGS(GPIO_MAX14906_DEVICE, 14916)
|
|
|