Initial import of firmware and host projects
This commit is contained in:
152
modules/ip5306/drivers/power/ip5306.c
Normal file
152
modules/ip5306/drivers/power/ip5306.c
Normal file
@@ -0,0 +1,152 @@
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/power/ip5306.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#include "ip5306_priv.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_IP5306_KEEPALIVE_HW_NRF)
|
||||
#include <soc_nrf_common.h>
|
||||
#define IP5306_CFG_KEEPALIVE_PSEL_INIT(inst) \
|
||||
.keepalive_psel = NRF_DT_GPIOS_TO_PSEL_OR(DT_DRV_INST(inst), keepalive_gpios, 0),
|
||||
#else
|
||||
#define IP5306_CFG_KEEPALIVE_PSEL_INIT(inst)
|
||||
#endif
|
||||
|
||||
LOG_MODULE_REGISTER(ip5306, LOG_LEVEL_INF);
|
||||
|
||||
#define DT_DRV_COMPAT injoinic_ip5306
|
||||
|
||||
#define IP5306_REG_READ0 0x70
|
||||
#define IP5306_REG_READ1 0x71
|
||||
#define IP5306_STATUS_BIT BIT(3)
|
||||
|
||||
static int ip5306_read_reg(const struct device *dev, uint8_t reg, uint8_t *val)
|
||||
{
|
||||
const struct ip5306_config *cfg = dev->config;
|
||||
|
||||
return i2c_reg_read_byte_dt(&cfg->i2c, reg, val);
|
||||
}
|
||||
|
||||
static int ip5306_get_status_bit(const struct device *dev, uint8_t reg, bool *flag)
|
||||
{
|
||||
uint8_t value = 0U;
|
||||
int ret;
|
||||
|
||||
if (flag == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = ip5306_read_reg(dev, reg, &value);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
*flag = ((value & IP5306_STATUS_BIT) != 0U);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ip5306_api_is_charging(const struct device *dev, bool *charging)
|
||||
{
|
||||
return ip5306_get_status_bit(dev, IP5306_REG_READ0, charging);
|
||||
}
|
||||
|
||||
static int ip5306_api_is_charge_full(const struct device *dev, bool *full)
|
||||
{
|
||||
return ip5306_get_status_bit(dev, IP5306_REG_READ1, full);
|
||||
}
|
||||
|
||||
static void ip5306_keepalive_start(const struct device *dev)
|
||||
{
|
||||
struct ip5306_data *data = dev->data;
|
||||
const struct ip5306_config *cfg = dev->config;
|
||||
|
||||
if (!cfg->has_keepalive_gpio || (data->keepalive_interval_ms == 0U)) {
|
||||
data->backend = IP5306_KEEPALIVE_BACKEND_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 选择策略:
|
||||
* 1) DTS 显式请求硬件 offload 时,先尝试硬件后端;
|
||||
* 2) 若硬件依赖不可用或资源被占用,则告警后回退软件后端。
|
||||
*/
|
||||
if (cfg->keepalive_offload) {
|
||||
#if IS_ENABLED(CONFIG_IP5306_KEEPALIVE_HW_NRF)
|
||||
int ret = ip5306_keepalive_hw_nrf_start(dev);
|
||||
|
||||
if (ret == 0) {
|
||||
LOG_INF("Keepalive backend=HW(nRF), pulse=%ums interval=%ums",
|
||||
data->keepalive_pulse_ms, data->keepalive_interval_ms);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_WRN("HW keepalive unavailable (%d), fallback to SW backend", ret);
|
||||
#else
|
||||
LOG_WRN("HW keepalive requested but HW backend is not built, fallback to SW backend");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ip5306_keepalive_sw_start(dev);
|
||||
LOG_INF("Keepalive backend=SW, pulse=%ums interval=%ums",
|
||||
data->keepalive_pulse_ms, data->keepalive_interval_ms);
|
||||
}
|
||||
|
||||
static int ip5306_init(const struct device *dev)
|
||||
{
|
||||
const struct ip5306_config *cfg = dev->config;
|
||||
struct ip5306_data *data = dev->data;
|
||||
|
||||
if (!i2c_is_ready_dt(&cfg->i2c)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (cfg->has_keepalive_gpio) {
|
||||
if (!gpio_is_ready_dt(&cfg->keepalive_gpio)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (gpio_pin_configure_dt(&cfg->keepalive_gpio, GPIO_OUTPUT_INACTIVE) != 0) {
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
data->keepalive_high = false;
|
||||
data->dev = dev;
|
||||
data->backend = IP5306_KEEPALIVE_BACKEND_NONE;
|
||||
data->keepalive_pulse_ms = (cfg->keepalive_pulse_ms != 0U) ?
|
||||
cfg->keepalive_pulse_ms : IP5306_KEEPALIVE_DEFAULT_PULSE_MS;
|
||||
data->keepalive_interval_ms = (cfg->keepalive_interval_ms != 0U) ?
|
||||
cfg->keepalive_interval_ms : IP5306_KEEPALIVE_DEFAULT_INTERVAL_MS;
|
||||
|
||||
ip5306_keepalive_start(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ip5306_driver_api ip5306_api = {
|
||||
.is_charging = ip5306_api_is_charging,
|
||||
.is_charge_full = ip5306_api_is_charge_full,
|
||||
};
|
||||
|
||||
#define IP5306_DEFINE(inst) \
|
||||
static struct ip5306_data ip5306_data_##inst; \
|
||||
static const struct ip5306_config ip5306_cfg_##inst = { \
|
||||
.i2c = I2C_DT_SPEC_INST_GET(inst), \
|
||||
.keepalive_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, keepalive_gpios, {0}), \
|
||||
IP5306_CFG_KEEPALIVE_PSEL_INIT(inst) \
|
||||
.keepalive_pulse_ms = DT_INST_PROP(inst, keepalive_pulse_ms), \
|
||||
.keepalive_interval_ms = DT_INST_PROP(inst, keepalive_interval_ms), \
|
||||
.has_keepalive_gpio = DT_INST_NODE_HAS_PROP(inst, keepalive_gpios), \
|
||||
.keepalive_offload = DT_INST_PROP_OR(inst, keepalive_offload, false), \
|
||||
}; \
|
||||
DEVICE_DT_INST_DEFINE(inst, ip5306_init, NULL, &ip5306_data_##inst, \
|
||||
&ip5306_cfg_##inst, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
|
||||
&ip5306_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(IP5306_DEFINE)
|
||||
Reference in New Issue
Block a user