drivers: sensor: ina230: driver refactoring

Create an explicit ina230 driver which is supposed to
work with 230 and 231 variants. While at it switch
to i2c_dt_spec helpers and change device-tree node
names to use - instead of _ in order to follow
convention.

Signed-off-by: Bartosz Bilas <b.bilas@grinn-global.com>
This commit is contained in:
Bartosz Bilas 2021-11-15 19:51:09 +01:00 committed by Maureen Helm
commit 2df7140947
14 changed files with 556 additions and 579 deletions

View file

@ -2,6 +2,6 @@
zephyr_library()
zephyr_library_sources(ina23x.c)
zephyr_library_sources(ina23x_common.c)
zephyr_library_sources_ifdef(CONFIG_INA23X_TRIGGER ina23x_trigger.c)
zephyr_library_sources_ifdef(CONFIG_INA230 ina230.c)
zephyr_library_sources_ifdef(CONFIG_INA230_TRIGGER ina230_trigger.c)

View file

@ -10,8 +10,14 @@ config INA23X
if INA23X
config INA23X_TRIGGER
bool "Trigger mode"
config INA230
bool "INA230"
help
Enable driver for INA230/INA231.
config INA230_TRIGGER
bool "INA230 trigger mode"
depends on INA230
help
Set to enable trigger mode using gpio interrupt, where
interrupts are configured to line ALERT PIN.

View file

@ -0,0 +1,349 @@
/*
* Copyright 2021 The Chromium OS Authors
* Copyright 2021 Grinn
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT ti_ina230
#include <logging/log.h>
#include <drivers/sensor.h>
#include "ina230.h"
#include "ina23x_common.h"
LOG_MODULE_REGISTER(INA230, CONFIG_SENSOR_LOG_LEVEL);
/**
* @brief Internal fixed value of INA230 that is used to ensure
* scaling is properly maintained.
*
*/
#define INA230_INTERNAL_FIXED_SCALING_VALUE 5120
/**
* @brief The LSB value for the bus voltage register.
*
*/
#define INA230_BUS_VOLTAGE_LSB 125
/**
* @brief The LSB value for the power register.
*
*/
#define INA230_POWER_VALUE_LSB 25
/**
* @brief sensor value get
*
* @retval 0 for success
* @retval -ENOTSUP for unsupported channels
*/
static int ina230_channel_get(const struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
struct ina230_data *data = dev->data;
const struct ina230_config *const config = dev->config;
switch (chan) {
case SENSOR_CHAN_VOLTAGE:
if (config->current_lsb == INA23X_CURRENT_LSB_1MA) {
uint32_t bus_mv = ((data->bus_voltage *
INA230_BUS_VOLTAGE_LSB) / 100);
val->val1 = bus_mv / 1000U;
val->val2 = (bus_mv % 1000) * 1000;
} else {
val->val1 = data->bus_voltage;
val->val2 = 0;
}
break;
case SENSOR_CHAN_CURRENT:
if (config->current_lsb == INA23X_CURRENT_LSB_1MA) {
/**
* If current is negative, convert it to a
* magnitude and return the negative of that
* magnitude.
*/
if (data->current & INA23X_CURRENT_SIGN_BIT) {
uint16_t current_mag = (~data->current + 1);
val->val1 = -(current_mag / 1000U);
val->val2 = -(current_mag % 1000) * 1000;
} else {
val->val1 = data->current / 1000U;
val->val2 = (data->current % 1000) * 1000;
}
} else {
val->val1 = data->current;
val->val2 = 0;
}
break;
case SENSOR_CHAN_POWER:
if (config->current_lsb == INA23X_CURRENT_LSB_1MA) {
uint32_t power_mw = data->power * INA230_POWER_VALUE_LSB;
val->val1 = power_mw / 1000U;
val->val2 = (power_mw % 1000) * 1000;
} else {
val->val1 = data->power;
val->val2 = 0;
}
break;
default:
return -ENOTSUP;
}
return 0;
}
/**
* @brief sensor sample fetch
*
* @retval 0 for success
* @retval -ENOTSUP for unsupported channels
*/
static int ina230_sample_fetch(const struct device *dev,
enum sensor_channel chan)
{
struct ina230_data *data = dev->data;
const struct ina230_config *config = dev->config;
int ret;
if (chan != SENSOR_CHAN_ALL &&
chan != SENSOR_CHAN_VOLTAGE &&
chan != SENSOR_CHAN_CURRENT &&
chan != SENSOR_CHAN_POWER) {
return -ENOTSUP;
}
if ((chan == SENSOR_CHAN_ALL) || (chan == SENSOR_CHAN_VOLTAGE)) {
ret = ina23x_reg_read_16(&config->bus, INA230_REG_BUS_VOLT, &data->bus_voltage);
if (ret < 0) {
LOG_ERR("Failed to read bus voltage");
return ret;
}
}
if ((chan == SENSOR_CHAN_ALL) || (chan == SENSOR_CHAN_CURRENT)) {
ret = ina23x_reg_read_16(&config->bus, INA230_REG_CURRENT, &data->current);
if (ret < 0) {
LOG_ERR("Failed to read current");
return ret;
}
}
if ((chan == SENSOR_CHAN_ALL) || (chan == SENSOR_CHAN_POWER)) {
ret = ina23x_reg_read_16(&config->bus, INA230_REG_POWER, &data->power);
if (ret < 0) {
LOG_ERR("Failed to read power");
return ret;
}
}
return 0;
}
/**
* @brief sensor attribute set
*
* @retval 0 for success
* @retval -ENOTSUP for unsupported channels
* @retval -EIO for i2c write failure
*/
static int ina230_attr_set(const struct device *dev, enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
const struct ina230_config *config = dev->config;
uint16_t data = val->val1;
switch (attr) {
case SENSOR_ATTR_CONFIGURATION:
return ina23x_reg_write(&config->bus, INA230_REG_CONFIG, data);
case SENSOR_ATTR_CALIBRATION:
return ina23x_reg_write(&config->bus, INA230_REG_CALIB, data);
case SENSOR_ATTR_FEATURE_MASK:
return ina23x_reg_write(&config->bus, INA230_REG_MASK, data);
case SENSOR_ATTR_ALERT:
return ina23x_reg_write(&config->bus, INA230_REG_ALERT, data);
default:
LOG_ERR("INA230 attribute not supported.");
return -ENOTSUP;
}
}
/**
* @brief sensor attribute get
*
* @retval 0 for success
* @retval -ENOTSUP for unsupported channels
* @retval -EIO for i2c read failure
*/
static int ina230_attr_get(const struct device *dev, enum sensor_channel chan,
enum sensor_attribute attr,
struct sensor_value *val)
{
const struct ina230_config *config = dev->config;
uint16_t data;
int ret;
switch (attr) {
case SENSOR_ATTR_CONFIGURATION:
ret = ina23x_reg_read_16(&config->bus, INA230_REG_CONFIG, &data);
if (ret < 0) {
return ret;
}
break;
case SENSOR_ATTR_CALIBRATION:
ret = ina23x_reg_read_16(&config->bus, INA230_REG_CALIB, &data);
if (ret < 0) {
return ret;
}
break;
case SENSOR_ATTR_FEATURE_MASK:
ret = ina23x_reg_read_16(&config->bus, INA230_REG_MASK, &data);
if (ret < 0) {
return ret;
}
break;
case SENSOR_ATTR_ALERT:
ret = ina23x_reg_read_16(&config->bus, INA230_REG_ALERT, &data);
if (ret < 0) {
return ret;
}
break;
default:
LOG_ERR("INA230 attribute not supported.");
return -ENOTSUP;
}
val->val1 = data;
val->val2 = 0;
return 0;
}
/**
* @brief sensor calibrate
*
* @retval 0 for success
* @retval -EIO for i2c write failure
*/
static int ina230_calibrate(const struct device *dev)
{
const struct ina230_config *config = dev->config;
uint16_t val;
int ret;
val = (INA230_INTERNAL_FIXED_SCALING_VALUE / (config->current_lsb * config->rshunt));
ret = ina23x_reg_write(&config->bus, INA230_REG_CALIB, val);
if (ret < 0) {
return ret;
}
return 0;
}
/**
* @brief Initialize the INA230
*
* @retval 0 for success
* @retval -EINVAL on error
*/
static int ina230_init(const struct device *dev)
{
const struct ina230_config *const config = dev->config;
int ret;
if (!device_is_ready(config->bus.bus)) {
LOG_ERR("I2C bus %s is not ready", config->bus.bus->name);
return -ENODEV;
}
ret = ina23x_reg_write(&config->bus, INA230_REG_CONFIG, config->config);
if (ret < 0) {
LOG_ERR("Failed to write configuration register!");
return ret;
}
ret = ina230_calibrate(dev);
if (ret < 0) {
LOG_ERR("Failed to write calibration register!");
return ret;
}
#ifdef CONFIG_INA230_TRIGGER
if (config->trig_enabled) {
ret = ina230_trigger_mode_init(dev);
if (ret < 0) {
LOG_ERR("Failed to init trigger mode\n");
return ret;
}
ret = ina23x_reg_write(&config->bus, INA230_REG_ALERT,
config->alert_limit);
if (ret < 0) {
LOG_ERR("Failed to write alert register!");
return ret;
}
ret = ina23x_reg_write(&config->bus, INA230_REG_MASK, config->mask);
if (ret < 0) {
LOG_ERR("Failed to write mask register!");
return ret;
}
}
#endif /* CONFIG_INA230_TRIGGER */
return 0;
}
static const struct sensor_driver_api ina230_driver_api = {
.attr_set = ina230_attr_set,
.attr_get = ina230_attr_get,
#ifdef CONFIG_INA230_TRIGGER
.trigger_set = ina230_trigger_set,
#endif
.sample_fetch = ina230_sample_fetch,
.channel_get = ina230_channel_get,
};
BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) > 0,
"No compatible ina230 instances found");
#ifdef CONFIG_INA230_TRIGGER
#define INA230_CFG_IRQ(inst) \
.trig_enabled = true, \
.mask = DT_INST_PROP(inst, mask), \
.alert_limit = DT_INST_PROP(inst, alert_limit), \
.gpio_alert = GPIO_DT_SPEC_INST_GET(inst, irq_gpios)
#else
#define INA230_CFG_IRQ(inst)
#endif /* CONFIG_INA230_TRIGGER */
#define INA230_DRIVER_INIT(inst) \
static struct ina230_data drv_data_##inst; \
static const struct ina230_config drv_config_##inst = { \
.bus = I2C_DT_SPEC_INST_GET(inst), \
.config = DT_INST_PROP(inst, config), \
.current_lsb = DT_INST_PROP(inst, current_lsb), \
.rshunt = DT_INST_PROP(inst, rshunt), \
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \
(INA230_CFG_IRQ(inst)), ()) \
}; \
DEVICE_DT_INST_DEFINE(inst, \
&ina230_init, \
NULL, \
&drv_data_##inst, \
&drv_config_##inst, \
POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, \
&ina230_driver_api);
DT_INST_FOREACH_STATUS_OKAY(INA230_DRIVER_INIT)

View file

@ -0,0 +1,54 @@
/*
* Copyright 2021 The Chromium OS Authors
* Copyright (c) 2021 Grinn
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_SENSOR_INA23X_INA230_H_
#define ZEPHYR_DRIVERS_SENSOR_INA23X_INA230_H_
#include <drivers/gpio.h>
#include <drivers/i2c.h>
#define INA230_REG_CONFIG 0x00
#define INA230_REG_SHUNT_VOLT 0x01
#define INA230_REG_BUS_VOLT 0x02
#define INA230_REG_POWER 0x03
#define INA230_REG_CURRENT 0x04
#define INA230_REG_CALIB 0x05
#define INA230_REG_MASK 0x06
#define INA230_REG_ALERT 0x07
struct ina230_data {
const struct device *dev;
uint16_t current;
uint16_t bus_voltage;
uint16_t power;
#ifdef CONFIG_INA230_TRIGGER
const struct device *gpio;
struct gpio_callback gpio_cb;
struct k_work work;
sensor_trigger_handler_t handler_alert;
#endif /* CONFIG_INA230_TRIGGER */
};
struct ina230_config {
struct i2c_dt_spec bus;
uint16_t config;
uint16_t current_lsb;
uint16_t rshunt;
#ifdef CONFIG_INA230_TRIGGER
bool trig_enabled;
uint16_t mask;
const struct gpio_dt_spec gpio_alert;
uint16_t alert_limit;
#endif /* CONFIG_INA230_TRIGGER */
};
int ina230_trigger_mode_init(const struct device *dev);
int ina230_trigger_set(const struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler);
#endif /* ZEPHYR_DRIVERS_SENSOR_INA23X_INA230_H_ */

View file

@ -1,5 +1,6 @@
/*
* Copyright 2021 The Chromium OS Authors
* Copyright 2021 Grinn
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -8,44 +9,44 @@
#include <drivers/gpio.h>
#include <logging/log.h>
#include "ina23x.h"
#include "ina230.h"
LOG_MODULE_DECLARE(INA23X, CONFIG_SENSOR_LOG_LEVEL);
LOG_MODULE_DECLARE(INA230, CONFIG_SENSOR_LOG_LEVEL);
static void ina23x_gpio_callback(const struct device *port,
static void ina230_gpio_callback(const struct device *port,
struct gpio_callback *cb, uint32_t pin)
{
struct sensor_trigger ina23x_trigger;
struct ina23x_data *ina23x = CONTAINER_OF(cb, struct ina23x_data, gpio_cb);
const struct device *dev = (const struct device *)ina23x->dev;
struct sensor_trigger ina230_trigger;
struct ina230_data *ina230 = CONTAINER_OF(cb, struct ina230_data, gpio_cb);
const struct device *dev = (const struct device *)ina230->dev;
ARG_UNUSED(port);
ARG_UNUSED(pin);
ARG_UNUSED(cb);
if (ina23x->handler_alert) {
ina23x_trigger.type = SENSOR_TRIG_DATA_READY;
ina23x->handler_alert(dev, &ina23x_trigger);
if (ina230->handler_alert) {
ina230_trigger.type = SENSOR_TRIG_DATA_READY;
ina230->handler_alert(dev, &ina230_trigger);
}
}
int ina23x_trigger_set(const struct device *dev,
int ina230_trigger_set(const struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler)
{
struct ina23x_data *ina23x = dev->data;
struct ina230_data *ina230 = dev->data;
ARG_UNUSED(trig);
ina23x->handler_alert = handler;
ina230->handler_alert = handler;
return 0;
}
int ina23x_trigger_mode_init(const struct device *dev)
int ina230_trigger_mode_init(const struct device *dev)
{
struct ina23x_data *ina23x = dev->data;
const struct ina23x_config *config = dev->config;
struct ina230_data *ina230 = dev->data;
const struct ina230_config *config = dev->config;
int ret;
/* setup alert gpio interrupt */
@ -54,7 +55,7 @@ int ina23x_trigger_mode_init(const struct device *dev)
return -ENODEV;
}
ina23x->dev = dev;
ina230->dev = dev;
ret = gpio_pin_configure_dt(&config->gpio_alert, GPIO_INPUT);
if (ret < 0) {
@ -62,11 +63,11 @@ int ina23x_trigger_mode_init(const struct device *dev)
return ret;
}
gpio_init_callback(&ina23x->gpio_cb,
ina23x_gpio_callback,
gpio_init_callback(&ina230->gpio_cb,
ina230_gpio_callback,
BIT(config->gpio_alert.pin));
ret = gpio_add_callback(config->gpio_alert.port, &ina23x->gpio_cb);
ret = gpio_add_callback(config->gpio_alert.port, &ina230->gpio_cb);
if (ret < 0) {
LOG_ERR("Could not set gpio callback");
return ret;

View file

@ -1,374 +0,0 @@
/*
* Copyright 2021 The Chromium OS Authors
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT ti_ina23x
#include <sys/byteorder.h>
#include <device.h>
#include <drivers/gpio.h>
#include <drivers/i2c.h>
#include <logging/log.h>
#include <drivers/sensor.h>
#include "ina23x.h"
LOG_MODULE_REGISTER(INA23X, CONFIG_SENSOR_LOG_LEVEL);
/**
* @brief Macro used to test if the current's sign bit is set
*/
#define CURRENT_SIGN_BIT 0x8000
/**
* @brief Macro used to check if the current's LSB is 1mA
*/
#define CURRENT_LSB_1MA 1
/**
* @brief Macro for creating the INA23X calibration value
* CALIB = (5120 / (current_lsb * rshunt))
* NOTE: The 5120 value is a fixed value internal to the
* INA23X that is used to ensure scaling is properly
* maintained.
*
* @param current_lsb Value of the Current register LSB in milliamps
* @param rshunt Shunt resistor value in milliohms
*/
#define INA23X_CALIB(current_lsb, rshunt) (5120 / ((current_lsb) * (rshunt)))
/**
* @brief Macro to convert raw Bus voltage to millivolts when current_lsb is
* set to 1mA.
*
* reg value read from bus voltage register
* clsb value of current_lsb
*/
#define INA23X_BUS_MV(reg) ((reg) * 125 / 100)
/**
* @brief Macro to convert raw power value to milliwatts when current_lsb is
* set to 1mA.
*
* reg value read from power register
* clsb value of current_lsb
*/
#define INA23X_POW_MW(reg) ((reg) * 25)
static int ina23x_reg_read(const struct device *dev, uint8_t reg, int16_t *val)
{
const struct ina23x_config *const config = dev->config;
uint8_t data[2];
int ret;
ret = i2c_burst_read(config->bus, config->i2c_slv_addr, reg, data, 2);
if (ret < 0) {
return ret;
}
*val = sys_get_be16(data);
return ret;
}
static int ina23x_reg_write(const struct device *dev, uint8_t reg, uint16_t val)
{
const struct ina23x_config *const config = dev->config;
uint8_t tx_buf[3];
tx_buf[0] = reg;
sys_put_be16(val, &tx_buf[1]);
return i2c_write(config->bus, tx_buf, sizeof(tx_buf), config->i2c_slv_addr);
}
/**
* @brief sensor value get
*
* @return 0 for success
* @return -ENOTSUP for unsupported channels
*/
static int ina23x_channel_get(const struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
struct ina23x_data *ina23x = dev->data;
const struct ina23x_config *const config = dev->config;
switch (chan) {
case SENSOR_CHAN_VOLTAGE:
if (config->current_lsb == CURRENT_LSB_1MA) {
val->val1 = INA23X_BUS_MV(ina23x->bus_voltage) / 1000U;
val->val2 = (INA23X_BUS_MV(ina23x->bus_voltage) % 1000) * 1000;
} else {
val->val1 = ina23x->bus_voltage;
val->val2 = 0;
}
break;
case SENSOR_CHAN_CURRENT:
if (config->current_lsb == CURRENT_LSB_1MA) {
/**
* If current is negative, convert it to a
* magnitude and return the negative of that
* magnitude.
*/
if (ina23x->current & CURRENT_SIGN_BIT) {
uint16_t current_mag = (~ina23x->current + 1);
val->val1 = -(current_mag / 1000U);
val->val2 = -(current_mag % 1000) * 1000;
} else {
val->val1 = ina23x->current / 1000U;
val->val2 = (ina23x->current % 1000) * 1000;
}
} else {
val->val1 = ina23x->current;
val->val2 = 0;
}
break;
case SENSOR_CHAN_POWER:
if (config->current_lsb == CURRENT_LSB_1MA) {
val->val1 = INA23X_POW_MW(ina23x->power) / 1000U;
val->val2 = (INA23X_POW_MW(ina23x->power) % 1000) * 1000;
} else {
val->val1 = ina23x->power;
val->val2 = 0;
}
break;
default:
return -ENOTSUP;
}
return 0;
}
/**
* @brief sensor sample fetch
*
* @return 0 for success
* @return -ENOTSUP for unsupported channels
*/
static int ina23x_sample_fetch(const struct device *dev,
enum sensor_channel chan)
{
struct ina23x_data *ina23x = dev->data;
int ret;
if (chan != SENSOR_CHAN_ALL &&
chan != SENSOR_CHAN_VOLTAGE &&
chan != SENSOR_CHAN_CURRENT &&
chan != SENSOR_CHAN_POWER) {
return -ENOTSUP;
}
if ((chan == SENSOR_CHAN_ALL) || (chan == SENSOR_CHAN_VOLTAGE)) {
ret = ina23x_reg_read(dev, INA23X_REG_BUS_VOLT, &ina23x->bus_voltage);
if (ret < 0) {
LOG_ERR("Failed to read bus voltage");
return ret;
}
}
if ((chan == SENSOR_CHAN_ALL) || (chan == SENSOR_CHAN_CURRENT)) {
ret = ina23x_reg_read(dev, INA23X_REG_CURRENT, &ina23x->current);
if (ret < 0) {
LOG_ERR("Failed to read current");
return ret;
}
}
if ((chan == SENSOR_CHAN_ALL) || (chan == SENSOR_CHAN_POWER)) {
ret = ina23x_reg_read(dev, INA23X_REG_POWER, &ina23x->power);
if (ret < 0) {
LOG_ERR("Failed to read power");
return ret;
}
}
return 0;
}
/**
* @brief sensor attribute set
*
* @return 0 for success
* @return -ENOTSUP for unsupported channels
* @return -EIO for i2c write failure
*/
static int ina23x_attr_set(const struct device *dev, enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
uint16_t data = val->val1;
switch (attr) {
case SENSOR_ATTR_CONFIGURATION:
return ina23x_reg_write(dev, INA23X_REG_CONFIG, data);
case SENSOR_ATTR_CALIBRATION:
return ina23x_reg_write(dev, INA23X_REG_CALIB, data);
case SENSOR_ATTR_FEATURE_MASK:
return ina23x_reg_write(dev, INA23X_REG_MASK, data);
case SENSOR_ATTR_ALERT:
return ina23x_reg_write(dev, INA23X_REG_ALERT, data);
default:
LOG_ERR("INA23X attribute not supported.");
return -ENOTSUP;
}
}
/**
* @brief sensor attribute get
*
* @return 0 for success
* @return -ENOTSUP for unsupported channels
* @return -EIO for i2c read failure
*/
static int ina23x_attr_get(const struct device *dev, enum sensor_channel chan,
enum sensor_attribute attr,
struct sensor_value *val)
{
uint16_t data;
int ret;
switch (attr) {
case SENSOR_ATTR_CONFIGURATION:
ret = ina23x_reg_read(dev, INA23X_REG_CONFIG, &data);
if (ret < 0) {
return ret;
}
break;
case SENSOR_ATTR_CALIBRATION:
ret = ina23x_reg_read(dev, INA23X_REG_CALIB, &data);
if (ret < 0) {
return ret;
}
break;
case SENSOR_ATTR_FEATURE_MASK:
ret = ina23x_reg_read(dev, INA23X_REG_MASK, &data);
if (ret < 0) {
return ret;
}
break;
case SENSOR_ATTR_ALERT:
ret = ina23x_reg_read(dev, INA23X_REG_ALERT, &data);
if (ret < 0) {
return ret;
}
break;
default:
LOG_ERR("INA23X attribute not supported.");
return -ENOTSUP;
}
val->val1 = data;
val->val2 = 0;
return 0;
}
/**
* @brief Initialize the INA23x
*
* @return 0 for success
* @return -EINVAL on error
*/
static int ina23x_init(const struct device *dev)
{
const struct ina23x_config *const config = dev->config;
uint16_t cal;
int ret;
if (!device_is_ready(config->bus)) {
LOG_ERR("Device %s is not ready", config->bus->name);
return -ENODEV;
}
ret = ina23x_reg_write(dev, INA23X_REG_CONFIG, config->config);
if (ret < 0) {
LOG_ERR("Failed to write configuration register!");
return ret;
}
cal = INA23X_CALIB(config->current_lsb, config->rshunt);
ret = ina23x_reg_write(dev, INA23X_REG_CALIB, cal);
if (ret < 0) {
LOG_ERR("Failed to write calibration register!");
return ret;
}
#ifdef CONFIG_INA23X_TRIGGER
if (config->trig_enabled) {
ret = ina23x_trigger_mode_init(dev);
if (ret < 0) {
LOG_ERR("Failed to init trigger mode\n");
return ret;
}
ret = ina23x_reg_write(dev, INA23X_REG_ALERT,
config->alert_limit);
if (ret < 0) {
LOG_ERR("Failed to write alert register!");
return ret;
}
ret = ina23x_reg_write(dev, INA23X_REG_MASK, config->mask);
if (ret < 0) {
LOG_ERR("Failed to write mask register!");
return ret;
}
}
#endif /* CONFIG_INA23X_TRIGGER */
return 0;
}
static const struct sensor_driver_api ina23x_driver_api = {
.attr_set = ina23x_attr_set,
.attr_get = ina23x_attr_get,
#ifdef CONFIG_INA23X_TRIGGER
.trigger_set = ina23x_trigger_set,
#endif
.sample_fetch = ina23x_sample_fetch,
.channel_get = ina23x_channel_get,
};
BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) > 0,
"No compatible ina23x instances found");
#ifdef CONFIG_INA23X_TRIGGER
#define INA23X_CFG_IRQ(inst) \
.trig_enabled = true, \
.mask = DT_INST_PROP(inst, mask), \
.alert_limit = DT_INST_PROP(inst, alert_limit), \
.gpio_alert = GPIO_DT_SPEC_INST_GET(inst, irq_gpios)
#else
#define INA23X_CFG_IRQ(inst)
#endif /* CONFIG_INA23X_TRIGGER */
#define INA23X_DRIVER_INIT(inst) \
static struct ina23x_data drv_data_##inst; \
static const struct ina23x_config drv_config_##inst = { \
.bus = DEVICE_DT_GET(DT_INST_BUS(inst)), \
.i2c_slv_addr = DT_INST_REG_ADDR(inst), \
.config = DT_INST_PROP(inst, config), \
.current_lsb = DT_INST_PROP(inst, current_lsb), \
.rshunt = DT_INST_PROP(inst, rshunt), \
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \
(INA23X_CFG_IRQ(inst)), ()) \
}; \
DEVICE_DT_INST_DEFINE(inst, \
&ina23x_init, \
NULL, \
&drv_data_##inst, \
&drv_config_##inst, \
POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, \
&ina23x_driver_api);
DT_INST_FOREACH_STATUS_OKAY(INA23X_DRIVER_INIT)

View file

@ -1,53 +0,0 @@
/*
* Copyright (c) 2021 The Chromium OS Authors
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_SENSOR_INA23X_H_
#define ZEPHYR_DRIVERS_SENSOR_INA23X_H_
#include <drivers/gpio.h>
#define INA23X_REG_CONFIG 0x00
#define INA23X_REG_SHUNT_VOLT 0x01
#define INA23X_REG_BUS_VOLT 0x02
#define INA23X_REG_POWER 0x03
#define INA23X_REG_CURRENT 0x04
#define INA23X_REG_CALIB 0x05
#define INA23X_REG_MASK 0x06
#define INA23X_REG_ALERT 0x07
struct ina23x_data {
const struct device *dev;
uint16_t current;
uint16_t bus_voltage;
uint16_t power;
#ifdef CONFIG_INA23X_TRIGGER
const struct device *gpio;
struct gpio_callback gpio_cb;
struct k_work work;
sensor_trigger_handler_t handler_alert;
#endif /* CONFIG_INA23X_TRIGGER */
};
struct ina23x_config {
const struct device *bus;
const uint16_t i2c_slv_addr;
uint16_t config;
uint16_t current_lsb;
uint16_t rshunt;
#ifdef CONFIG_INA23X_TRIGGER
bool trig_enabled;
uint16_t mask;
const struct gpio_dt_spec gpio_alert;
uint16_t alert_limit;
#endif /* CONFIG_INA23X_TRIGGER */
};
int ina23x_trigger_mode_init(const struct device *dev);
int ina23x_trigger_set(const struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler);
#endif /* ZEPHYR_DRIVERS_SENSOR_INA23X_H_ */

View file

@ -0,0 +1,36 @@
#
# Copyright 2021 The Chromium OS Authors
# Copyright 2021 Grinn
#
# SPDX-License-Identifier: Apache-2.0
#
description: |
TI INA230 and INA231 Bidirectional Current and Power Monitor.
The <include/dt-bindings/sensor/ina230.h> file should be included
in the DeviceTree and it provides macro that can be used for
initializing the configuration register.
compatible: "ti,ina230"
include: ti,ina23x-common.yaml
properties:
mask:
type: int
required: false
default: 0
# default all alert sources to disabled
description: Mask register, default matches the power-on reset value
alert-limit:
type: int
required: false
default: 0
# default alert limit is 0V
description: Alert register, default matches the power-on reset value
irq-gpios:
type: phandle-array
required: false
description: IRQ Alert pin

View file

@ -1,56 +0,0 @@
#
# Copyright 2021 The Chromium OS Authors
#
# SPDX-License-Identifier: Apache-2.0
#
description: |
TI INA230 and INA231 Bidirectional Current and Power Monitor.
The <include/dt-bindings/sensor/ina23x.h> file should be included
in the DeviceTree and it provides Macros that can be used for
initializing the Configuration register.
compatible: "ti,ina23x"
include: i2c-device.yaml
properties:
config:
type: int
required: true
description: Configuration register
current_lsb:
type: int
required: true
description: |
Value of Current LSB in milliamps. When set to 1mA,
Current is read in A, Bus Voltage in V, Shunt
Voltage in V, and Power in mW. Any other value
results in Current, Voltage, and Power registers
being read in counts.
rshunt:
type: int
required: true
description: Shunt resistor value in milliohms
mask:
type: int
required: false
default: 0
# default all alert sources to disabled
description: Mask register, default matches the power-on reset value
alert_limit:
type: int
required: false
default: 0
# default alert limit is 0V
description: Alert register, default matches the power-on reset value
irq-gpios:
type: phandle-array
required: false
description: IRQ Alert pin

View file

@ -0,0 +1,68 @@
/*
* Copyright 2021 The Chromium OS Authors
* Copyright (c) 2021 Grinn
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_INA230_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_INA230_H_
#include <dt-bindings/dt-util.h>
/* Mask/Enable bits that asserts the ALERT pin */
#define INA230_SHUNT_VOLTAGE_OVER BIT(15)
#define INA230_SHUNT_VOLTAGE_UNDER BIT(14)
#define INA230_BUS_VOLTAGE_OVER BIT(13)
#define INA230_BUS_VOLTAGE_UNDER BIT(12)
#define INA230_OVER_LIMIT_POWER BIT(11)
#define INA230_CONVERSION_READY BIT(10)
#define INA230_ALERT_FUNCTION_FLAG BIT(4)
#define INA230_CONVERSION_READY_FLAG BIT(3)
#define INA230_MATH_OVERFLOW_FLAG BIT(2)
#define INA230_ALERT_POLARITY BIT(1)
#define INA230_ALERT_LATCH_ENABLE BIT(0)
/* Operating Mode */
#define INA230_OPER_MODE_POWER_DOWN 0x00
#define INA230_OPER_MODE_SHUNT_VOLTAGE_TRIG 0x01
#define INA230_OPER_MODE_BUS_VOLTAGE_TRIG 0x02
#define INA230_OPER_MODE_SHUNT_BUS_VOLTAGE_TRIG 0x03
#define INA230_OPER_MODE_SHUNT_VOLTAGE_CONT 0x05
#define INA230_OPER_MODE_BUS_VOLTAGE_CONT 0x06
#define INA230_OPER_MODE_SHUNT_BUS_VOLTAGE_CONT 0x07
/* Conversion time for bus and shunt in micro-seconds */
#define INA230_CONV_TIME_140 0x00
#define INA230_CONV_TIME_204 0x01
#define INA230_CONV_TIME_332 0x02
#define INA230_CONV_TIME_588 0x03
#define INA230_CONV_TIME_1100 0x04
#define INA230_CONV_TIME_2116 0x05
#define INA230_CONV_TIME_4156 0x06
#define INA230_CONV_TIME_8244 0x07
/* Averaging Mode */
#define INA230_AVG_MODE_1 0x00
#define INA230_AVG_MODE_4 0x01
#define INA230_AVG_MODE_16 0x02
#define INA230_AVG_MODE_64 0x03
#define INA230_AVG_MODE_128 0x04
#define INA230_AVG_MODE_256 0x05
#define INA230_AVG_MODE_512 0x06
#define INA230_AVG_MODE_1024 0x07
/**
* @brief Macro for creating the INA230 configuration value
*
* @param mode Operating mode.
* @param svct Conversion time for shunt voltage.
* @param bvct Conversion time for bus voltage.
* @param avg Averaging mode.
*/
#define INA230_CONFIG(mode, \
svct, \
bvct, \
avg) \
(((avg) << 9) | ((bvct) << 6) | ((svct) << 3) | (mode))
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_INA230_H_ */

View file

@ -1,67 +0,0 @@
/*
* Copyright 2021 The Chromium OS Authors
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_INA23X_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_INA23X_H_
#include <dt-bindings/dt-util.h>
/* Mask/Enable bits that asserts the ALERT pin */
#define INA23X_SHUNT_VOLTAGE_OVER BIT(15)
#define INA23X_SHUNT_VOLTAGE_UNDER BIT(14)
#define INA23X_BUS_VOLTAGE_OVER BIT(13)
#define INA23X_BUS_VOLTAGE_UNDER BIT(12)
#define INA23X_OVER_LIMIT_POWER BIT(11)
#define INA23X_CONVERSION_READY BIT(10)
#define INA23X_ALERT_FUNCTION_FLAG BIT(4)
#define INA23X_CONVERSION_READY_FLAG BIT(3)
#define INA23X_MATH_OVERFLOW_FLAG BIT(2)
#define INA23X_ALERT_POLARITY BIT(1)
#define INA23X_ALERT_LATCH_ENABLE BIT(0)
/* Operating Mode */
#define INA23X_OPER_MODE_POWER_DOWN 0x00
#define INA23X_OPER_MODE_SHUNT_VOLTAGE_TRIG 0x01
#define INA23X_OPER_MODE_BUS_VOLTAGE_TRIG 0x02
#define INA23X_OPER_MODE_SHUNT_BUS_VOLTAGE_TRIG 0x03
#define INA23X_OPER_MODE_SHUNT_VOLTAGE_CONT 0x05
#define INA23X_OPER_MODE_BUS_VOLTAGE_CONT 0x06
#define INA23X_OPER_MODE_SHUNT_BUS_VOLTAGE_CONT 0x07
/* Conversion time for bus and shunt in micro-seconds */
#define INA23X_CONV_TIME_140 0x00
#define INA23X_CONV_TIME_204 0x01
#define INA23X_CONV_TIME_332 0x02
#define INA23X_CONV_TIME_588 0x03
#define INA23X_CONV_TIME_1100 0x04
#define INA23X_CONV_TIME_2116 0x05
#define INA23X_CONV_TIME_4156 0x06
#define INA23X_CONV_TIME_8244 0x07
/* Averaging Mode */
#define INA23X_AVG_MODE_1 0x00
#define INA23X_AVG_MODE_4 0x01
#define INA23X_AVG_MODE_16 0x02
#define INA23X_AVG_MODE_64 0x03
#define INA23X_AVG_MODE_128 0x04
#define INA23X_AVG_MODE_256 0x05
#define INA23X_AVG_MODE_512 0x06
#define INA23X_AVG_MODE_1024 0x07
/**
* @brief Macro for creating the INA23X configuration value
*
* @param mode Operating mode.
* @param svct Conversion time for shunt voltage.
* @param bvct Conversion time for bus voltage.
* @param avg Averaging mode.
*/
#define INA23X_CONFIG(mode, \
svct, \
bvct, \
avg) \
(((avg) << 9) | ((bvct) << 6) | ((svct) << 3) | (mode))
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_INA23X_H_ */

View file

@ -666,15 +666,15 @@ test_i2c_lm75: lm75@4e {
reg = <0x4e>;
};
test_i2c_ina23x: ina23x@4f {
compatible = "ti,ina23x";
label = "INA23X";
test_i2c_ina230: ina230@4f {
compatible = "ti,ina230";
label = "INA230";
reg = <0x4f>;
config = <0>;
current_lsb = <1>;
current-lsb = <1>;
rshunt = <0>;
mask = <0>;
alert_limit = <0>;
alert-limit = <0>;
irq-gpios = <&test_gpio 0 0>;
};
@ -684,3 +684,15 @@ test_i2c_lm77: lm77@50 {
reg = <0x50>;
int-gpios = <&test_gpio 0 0>;
};
test_i2c_ina231: ina231@51 {
compatible = "ti,ina230";
label = "INA231";
reg = <0x51>;
config = <0>;
current-lsb = <1>;
rshunt = <0>;
mask = <0>;
alert-limit = <0>;
irq-gpios = <&test_gpio 0 0>;
};

View file

@ -99,3 +99,4 @@ CONFIG_TMP116=y
CONFIG_VCNL4040=y
CONFIG_VL53L0X=y
CONFIG_INA23X=y
CONFIG_INA230=y

View file

@ -36,4 +36,4 @@ CONFIG_STTS751_TRIGGER_OWN_THREAD=y
CONFIG_SX9500_TRIGGER_OWN_THREAD=y
CONFIG_TMP007_TRIGGER_OWN_THREAD=y
CONFIG_VCNL4040_TRIGGER_OWN_THREAD=y
CONFIG_INA23X_TRIGGER=y
CONFIG_INA230_TRIGGER=y