linux内核驱动:电流/电压/功率监控模块INA226调试

发布于:2025-08-02 ⋅ 阅读:(13) ⋅ 点赞:(0)

背景

最近调试了一款德州仪器的带有I2C控制接口的可以实现电压、电流、功率监测,并可以进行报警设置的芯片INA226;
本文主要总结在linux 5.10下怎么配置内核将此芯片用起来,并总结内核中此芯片的驱动实现;

一、芯片介绍

INA226 是具有 I2C™ 或 SMBUS 兼容接口的电流分流
器和功率监测器。该器件同时监控分流压降和总线电源
电压。可编程校准值、转换时间、和均值计算,与一个
内部乘法器相组合,实现电流值(安培)和功率值
(瓦)的直接读取。
INA226 可在 0V 至 36V 的共模总线电压范围内感测电
流,与电源电压无关。 该器件由一个 2.7V 至 5.5V 的
单电源供电,汲取 330μA 的典型电源电流。该器件的
额定工作温度范围为 –40°C 至 125°C,I2C 兼容接口
上具有多达 16 个可编程地址。

二、手册

https://www.ti.com.cn/product/cn/INA226/part-details/INA226AIDGST
详细描述和硬件参考设计等见手册;

三、内核驱动配置

3.1 设备树配置

&i2cXXX {
status = “okay”;
ina226@xx {
compatible = “ti,ina226”;
reg = <0xXX>; //器件地址结合手册和硬件配置定义
shunt-resistor = <1000>; //采样电阻值单位是: micro-ohm 微欧姆,如果是1毫欧就乘以1000
};
};

3.2 修改内核配置文件

修改内核源码/arch/arm64/configs/xxxxxxx_defconfg配置文件,添加编译选项
CONFIG_SENSORS_INA2XX=y 编译到内核 或者
CONFIG_SENSORS_INA2XX=m 编译成模块

3.3 编译

配置成模块时,查看是否生成ina2xx.o 和 ina2xx.ko;
配置编译到内核时,查看是否生成ina2xx.o;

四、内核驱动分析

1、初始化流程

驱动和设备树表示的设备match后 -> ina2xx_probe 执行

static int ina2xx_probe(struct i2c_client *client)
{
	struct device *dev = &client->dev;
	struct ina2xx_data *data;
	struct device *hwmon_dev;
	u32 val;
	int ret, group = 0;
	enum ina2xx_ids chip;
	if (client->dev.of_node)
		chip = (enum ina2xx_ids)of_device_get_match_data(&client->dev);//获取设备与驱动匹配后的of_device_id 结构里的数据,这的data为驱动不同芯片自定义的索引 ina219 为0 ,ina226为1
	else
		chip = i2c_match_id(ina2xx_id, client)->driver_data;
	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); //分配data结构的内存
	if (!data)
		return -ENOMEM;

	/* set the device type */
	data->config = &ina2xx_config[chip]; //结构ina2xx_config 的结构体赋值
	mutex_init(&data->config_lock);

	if (of_property_read_u32(dev->of_node, "shunt-resistor", &val) < 0) {
		struct ina2xx_platform_data *pdata = dev_get_platdata(dev); //读取设备树中定义的采样电阻值

		if (pdata)
			val = pdata->shunt_uohms; //得到采样电阻的阻值微欧姆
		else
			val = INA2XX_RSHUNT_DEFAULT;
	}

	ina2xx_set_shunt(data, val);//  struct ina2xx_data结构成员初始化
	ina2xx_regmap_config.max_register = data->config->registers; //芯片寄存器的个数
	data->regmap = devm_regmap_init_i2c(client, &ina2xx_regmap_config);//寄存器地址和值的位宽定义
	if (IS_ERR(data->regmap)) {
		dev_err(dev, "failed to allocate register map\n");
		return PTR_ERR(data->regmap);
	}
	ret = ina2xx_init(data);//初始化将默认值配置给配置寄存器,校准值配置给校准寄存器
	if (ret < 0) {
		dev_err(dev, "error configuring the device: %d\n", ret);
		return -ENODEV;
	}
	data->groups[group++] = &ina2xx_group;//通用属性组
	if (chip == ina226)
		data->groups[group++] = &ina226_group; //ina226 属性组
	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
							   data, data->groups); //注册成硬件监控设备类
	if (IS_ERR(hwmon_dev))
		return PTR_ERR(hwmon_dev);
	dev_info(dev, "power monitor %s (Rshunt = %li uOhm)\n",
		 client->name, data->rshunt);
	return 0;
}

2、属性文件/解释

1、会生成如下属性文件和目录
在这里插入图片描述
2、举例解释

//属性文件in0_input ,ina2xx_value 属性只读对应 ina2xx_value_show 函数,INA2XX_SHUNT_VOLTAGE  采样电阻分压寄存器
static SENSOR_DEVICE_ATTR_RO(in0_input, ina2xx_value, INA2XX_SHUNT_VOLTAGE);

//属性文件in1_input ,ina2xx_value 属性只读对应ina2xx_value_show 函数,INA2XX_BUS_VOLTAGE总线电压寄存器
static SENSOR_DEVICE_ATTR_RO(in1_input, ina2xx_value, INA2XX_BUS_VOLTAGE);

五、调试和计算

1、安装模块 或者编译进内核启动;
2、查看板卡/设备内属性目录
ls /sys/class/hwmon/hwmonX
在这里插入图片描述
3、以上属性文件内的数据为数字值,根据表示的数据内容的含义乘以分辨率,并结合具体的单位即可计算测量值,也可以与一期测量结果进行对比;