hisi3516dv300芯片基于hwmon驱动框架的温度获取驱动源码分析

1、内核hwmon驱动框架

参考博客:《内核hwmon驱动框架详解以及海思芯片温度驱动分析》

2、驱动实现的效果

/sys/devices/virtual/hwmon/hwmon0 # pwd
/sys/class/hwmon/hwmon0
/sys/devices/virtual/hwmon/hwmon0 # ls
power        subsystem    temp1_input  uevent
/sys/devices/virtual/hwmon/hwmon0 # cat temp1_input 
41
/sys/devices/virtual/hwmon/hwmon0 # 

(1)在sysfs中可以看到/sys/class/hwmon/hwmon0文件夹,里面有temp1_input文件;
(2)读取temp1_input文件,里面是芯片的温度值;
(3)文件夹名字不一定是hwmon0,如果你注册了不止一个hwmon设备,文件夹名字有可能是hwmon0或者hwmon1,看你注册hwmon设备的先后顺序;

3、获取芯片温度驱动的思路分析

(1)向内核hwmon驱动框架注册我们的驱动,在hwmon类下面创建相应的设备;
(2)填充创建的hwmon类设备的设备属性,创建保存温度值的文件,指定文件的show方法;
(3)对海思芯片温度传感器相关的寄存器进行动态映射;
(4)初始化海思芯片温度相关的寄存器,包括设置温度检测模式为循环模式、循环检测周期、使能等;
(5)应用通过读取temp1_input文件获取温度,实际就是执行temp1_input文件的show方法;
(6)在show方法中,读取温度记录值寄存器的值,计算出温度值并返回;

4、芯片自带的温度传感器

地址偏移量寄存器编号寄存器名字
0x00B4MISC_CTRL45Tsensor控制寄存器
0x00B8MISC_CTRL46Tsensor 状态寄存器
0x00BCMISC_CTRL47Tsensor 温度记录值寄存器 0
0x00C0MISC_CTRL48Tsensor 温度记录值寄存器 1
0x00C4MISC_CTRL49Tsensor 温度记录值寄存器 2
0x00C8MISC_CTRL50Tsensor 温度记录值寄存器 3

5、寄存器功能描述

5.1、Tsensor控制寄存器

在这里插入图片描述

(1)温度检测模式:一般选择循环检测模式,不停的去检测温度;
(2)循环检测周期:当设置为循环检测模式时要设置,就是每隔多长时间去检测一次温度,注意单位是2ms;
(3)温度上/下溢值:往寄存器写入值,表示芯片温度超过这个值时会触发Tsensor 状态寄存器的温度上/下溢报警位。这几个寄存器的位不是直接写温度值,有换算关系,hisi3516dv300的数据手册没有明确写出,但是按照海思其他芯片推测,应该是(tsensor_uplimit -136)/793*165-40

5.2、Tsensor 状态寄存器

在这里插入图片描述

(1)如果在Tsensor控制寄存器寄存器中设置了温度上/下溢值,则需要检测温度下溢告警位;
(2)其他的位不用也没什么影响,不设置也是可以正常工作;

5.3、Tsensor温度记录值寄存器

在这里插入图片描述

(1)总共有4个温度记录值寄存器,每个寄存器的bit位含义都是一样的;
(2)每个温度记录值寄存器都保存了两个温度值,分别保存在[9:0]和[25:16]bit位;
(3)Soc在4个温度记录值寄存器中保存了8个温度值,我们需要读出8个温度值来计算一个平均的温度值;
(4)温度计算公式:Temprature=(tsensor_result[0:1] -136)/793*165-40(单位:度);

6、芯片内部温度检测流程

步骤 1:设置 T-Sensor 采集模式 MISC_CTRL45[30]。
步骤 2:如果设置为循环采集模式,需设置循环采集周期 MISC_CTRL45[27:20];如果设置为单次采集模式,可略过此步骤。循环采集周期计算公式为: T = N × 2(ms),其中 N=MISC_CTRL45[27:20]。
步骤 3:使能 T-Sensor MISC_CTRL45[31],开始温度采集
步骤 4:软件读取T-Sensor采集到的温度码(十六进制值)。单次采集模式下,只有 MISC_CTRL47[9:0]中记录的温度记录码0有效。
循环采集模式下,MISC_CTRL47[31:0]~MISC_CTRL50[31:0]记录了最近八次温度记录码 0~7,其中最新的温度记录值为温度记录码 0。
步骤 5:根据温度记录码计算出对应的温度值。Temprature=(T-Senso -136)/793*165-40(单位:度);

7、驱动源码分析

7.1、驱动的注册函数

static int hisi3516d_hwmon_init(void)
{
	int ret;

	//向hwmon驱动框架注册我们的驱动
	hisi3516d_hwmon_dev = hwmon_device_register(NULL);
	if(IS_ERR(hisi3516d_hwmon_dev)){
		
		printk(KERN_ERR "hwmod device register faild\n");
		ret = PTR_ERR((void *)hisi3516d_hwmon_dev);
		goto err_exit_3;
	}

	//填充hwmon驱动框架返回的设备,也就是创建设备下面的文件以及show、store方法
	ret = sysfs_create_group(&hisi3516d_hwmon_dev->kobj,
                                &hisi3516d_hwmon_attribute_group);
	if(ret){

		printk(KERN_ERR "create sysfs group faild\n");
		goto err_exit_2;
	}

	//映射芯片温度相关寄存器的地址
	ret = reg_remap();
	if(ret){
		printk(KERN_ERR "hi3559a hwmon ioremap faild\n");
		goto err_exit_1;
	}

	//初始化海思芯片的Tsensor寄存器
	hisi3516d_temp_init();

	return 0;
	
err_exit_1:
	sysfs_remove_group(&hisi3516d_hwmon_dev->kobj,&hisi3516d_hwmon_attribute_group);
err_exit_2:
	hwmon_device_unregister(hisi3516d_hwmon_dev);
err_exit_3:
	return ret;
	
}

module_init(hisi3516d_hwmon_init);

(1)向hwmon驱动框架注册我们的驱动,得到一个设备结构体;
(2)填充设备结构体,给设备创建文件以及show、store方法;
(3)映射芯片温度相关寄存器的地址,这里采用的动态映射;
(4)初始化海思芯片的Tsensor寄存器,设置温度检测模式为循环模式、循环检测周期、使能等;

7.2、驱动的卸载函数

static void hisi3516d_hwmon_exit(void)
{
	//解除寄存器的映射
	reg_unmap();
	
	//注销设备下的文件
	sysfs_remove_group(&hisi3516d_hwmon_dev->kobj,&hisi3516d_hwmon_attribute_group);
	
	//从hwmon驱动框架中注销驱动
	hwmon_device_unregister(hisi3516d_hwmon_dev);
}

module_exit(hisi3516d_hwmon_exit);

就是注册函数的逆过程,释放资源,删除sysfs中创建的文件,从hwmon驱动框架中注销驱动;

7.3、创建temp1_input文件

struct device *hisi3516d_hwmon_dev;

static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL, 0);

static struct attribute *hisi3516d_hwmon_attributes[] = {
	&sensor_dev_attr_temp1_input.dev_attr.attr,
	NULL,
};

static struct attribute_group hisi3516d_hwmon_attribute_group = {
	.attrs = hisi3516d_hwmon_attributes,
};

(1)hisi3516d_hwmon_attribute_group变量是用来创建设备下的文件以及文件show、store方法的;
(2)文件名字是temp1_input,show方法是show_temp1_input()函数;
(3)SENSOR_DEVICE_ATTR宏的分析参考博客:https://blog.csdn.net/weixin_42031299/article/details/124890370;

7.4、读取Tsensor寄存器温度的函数

static ssize_t show_temp1_input(struct device *dev,
		struct device_attribute *da, char *buf)
{
	volatile unsigned int reg_val = 0;
	unsigned int tmp_val = 0;
	int32_t temperature_val = 0;
	int32_t i = 0;

	//获取温度记录值寄存器0寄存器中保存的两个温度值
    reg_val = ioread32((void __iomem *)tsensorviraddr + T_SENSOR_RESULT0);
    for(i = 0; i < 2; i++)
    {
        tmp_val = (reg_val >> (16*i)) & 0x3ff;
        temperature_val += (tmp_val - 136)/793*165 - 40;
    }

	//获取温度记录值寄存器1寄存器中保存的两个温度值
    reg_val = ioread32((void __iomem *)tsensorviraddr + T_SENSOR_RESULT1);
    for(i = 0; i < 2; i++)
    {
        tmp_val = (reg_val >> (16*i)) & 0x3ff;
        temperature_val += (tmp_val - 136)/793*165 - 40;
    }

	//获取温度记录值寄存器2寄存器中保存的两个温度值
    reg_val = ioread32((void __iomem *)tsensorviraddr + T_SENSOR_RESULT2);
    for(i = 0; i < 2; i++)
    {
        tmp_val = (reg_val >> (16*i)) & 0x3ff;
        temperature_val += (tmp_val - 136)/793*165 - 40;
    }

	//获取温度记录值寄存器3寄存器中保存的两个温度值
    reg_val = ioread32((void __iomem *)tsensorviraddr + T_SENSOR_RESULT3);
    for(i = 0; i < 2; i++)
    {
        tmp_val = (reg_val >> (16*i)) & 0x3ff;
        temperature_val += (tmp_val - 136)/793*165 - 40;
    }

	//温度值除以8,获取平均值
	temperature_val = temperature_val >> 3;
	
	sprintf(buf, "%d", temperature_val);
	return strlen(buf);
}

(1)tsensorviraddr:温度相关寄存器动态映射后得到的基地址;
(2)获取8个温度值,然后再返回温度的平均值;
(3)当我们用"cat /sys/class/hwmon/hwmon0/temp1_input"命令读取temp1_input文件时,驱动里就调用show_temp1_input()函数,这是temp1_input文件的show方法;

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正在起飞的蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值