blob: 023f65d00766a0f846698d28010783d51e1a8d5b [file] [log] [blame]
/*
* Copyright (c) 2022 Leica Geosystems AG
*
* Copyright 2022 Google LLC
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT sbs_sbs_gauge_new_api
#include "sbs_gauge.h"
#include <zephyr/drivers/fuel_gauge.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/byteorder.h>
LOG_MODULE_REGISTER(sbs_gauge);
static int sbs_cmd_reg_read(const struct device *dev, uint8_t reg_addr, uint16_t *val)
{
const struct sbs_gauge_config *cfg;
uint8_t i2c_data[2];
int status;
cfg = dev->config;
status = i2c_burst_read_dt(&cfg->i2c, reg_addr, i2c_data, ARRAY_SIZE(i2c_data));
if (status < 0) {
LOG_ERR("Unable to read register");
return status;
}
*val = sys_get_le16(i2c_data);
return 0;
}
static int sbs_gauge_get_prop(const struct device *dev, struct fuel_gauge_get_property *prop)
{
int rc = 0;
uint16_t val = 0;
switch (prop->property_type) {
case FUEL_GAUGE_AVG_CURRENT:
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_AVG_CURRENT, &val);
prop->value.avg_current = val * 1000;
break;
case FUEL_GAUGE_CYCLE_COUNT:
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_CYCLE_COUNT, &val);
prop->value.cycle_count = val;
break;
case FUEL_GAUGE_CURRENT:
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_CURRENT, &val);
prop->value.current = val * 1000;
break;
case FUEL_GAUGE_FULL_CHARGE_CAPACITY:
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_FULL_CAPACITY, &val);
prop->value.full_charge_capacity = val * 1000;
break;
case FUEL_GAUGE_REMAINING_CAPACITY:
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_REM_CAPACITY, &val);
prop->value.remaining_capacity = val * 1000;
break;
case FUEL_GAUGE_RUNTIME_TO_EMPTY:
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_RUNTIME2EMPTY, &val);
prop->value.runtime_to_empty = val;
break;
case FUEL_GAUGE_RUNTIME_TO_FULL:
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_AVG_TIME2FULL, &val);
prop->value.runtime_to_empty = val;
break;
case FUEL_GAUGE_STATE_OF_CHARGE:
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_ASOC, &val);
prop->value.state_of_charge = val;
break;
case FUEL_GAUGE_TEMPERATURE:
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_TEMP, &val);
prop->value.temperature = val;
break;
case FUEL_GAUGE_VOLTAGE:
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_VOLTAGE, &val);
prop->value.voltage = val * 1000;
break;
default:
rc = -ENOTSUP;
}
prop->status = rc;
return rc;
}
static int sbs_gauge_get_props(const struct device *dev, struct fuel_gauge_get_property *props,
size_t len)
{
int ret = 0;
for (int i = 0; i < len; i++) {
ret |= sbs_gauge_get_prop(dev, props + i);
}
return ret;
}
/**
* @brief initialize the fuel gauge
*
* @return 0 for success
*/
static int sbs_gauge_init(const struct device *dev)
{
const struct sbs_gauge_config *cfg;
cfg = dev->config;
if (!device_is_ready(cfg->i2c.bus)) {
LOG_ERR("Bus device is not ready");
return -ENODEV;
}
return 0;
}
static const struct battery_driver_api sbs_gauge_driver_api = {
.get_property = &sbs_gauge_get_props,
};
/* FIXME: fix init priority */
#define SBS_GAUGE_INIT(index) \
\
static const struct sbs_gauge_config sbs_gauge_config_##index = { \
.i2c = I2C_DT_SPEC_INST_GET(index), \
}; \
\
DEVICE_DT_INST_DEFINE(index, &sbs_gauge_init, NULL, NULL, &sbs_gauge_config_##index, \
POST_KERNEL, 90, &sbs_gauge_driver_api);
DT_INST_FOREACH_STATUS_OKAY(SBS_GAUGE_INIT)