mt8167s溫溼度傳感器框架分析——kernel層

前言

前面我們已經講解了sensor框架中的framework到vendor層,這篇文章我們將會講解kernel層的內容。不過不同的芯片平臺,kernel層中的sensor框架是不同的,這裏針對的是mt8167s平臺。不過這裏提醒一下,MTK平臺應該從kernel 3.x版本後就不支持溫溼度傳感器的框架了,不過幸好他們還保留了框架的雛形在,我們需要自行解決一下編譯問題。

正文

我們先看一下代碼的具體目錄:

drivers/misc/mediatek/sensors-1.0$ ls
accelerometer/    alsps/      dummy.c     humidity/       magnetometer/  sensorHub/        accelgyro/
barometer/        geofence/   hwmon/      Makefile        situation/     activity_sensor/  
biometric/        gyroscope/  Kconfig     sensorfusion/   step_counter/

目錄結構很清晰,不同的sensor都有單獨的目錄,這篇文章我們還是以溼度傳感器爲例,所以這裏單獨研究一下humidity。還是先看一下代碼目錄結構:

drivers/misc/mediatek/sensors-1.0/humidity$ ls
aht10/  hmdyhub/  humidity.c  humidity_factory.c  inc/  Kconfig  Makefile

humidity.c文件爲不同型號的溼度傳感器驅動提供一些公共的接口,也可以說是MTK爲我們抽象一個有關humidity sensor的基本架構。在移植一個新型號的sensor時,只要將其通過公共接口註冊進系統就可以了。

1、初始化

static struct hmdy_init_info aht10_init_info = {
		.name = "aht10",
		.init = aht10_local_init,
		.uninit = aht10_local_uninit,
	
};

static int __init aht10_init(void)
{
	hmdy_driver_add(&aht10_init_info);
	AHT_FUN();   
	return 0;
}

module_init(aht10_init);

在aht10驅動初始化的時候,通過hmdy_driver_add接口把我們的aht10驅動註冊進系統

int hmdy_driver_add(struct hmdy_init_info *obj)
{
	int err = 0;
	int i = 0;

	HMDY_FUN();
	if (!obj) {
		HMDY_PR_ERR("HMDY driver add fail, hmdy_init_info is NULL\n");
		return -1;
	}
	
	for (i = 0; i < MAX_CHOOSE_HMDY_NUM; i++) {
		if (i == 0) {
			HMDY_LOG("register humidity driver for the first time\n");
			if (platform_driver_register(&humidity_driver))
				HMDY_PR_ERR("failed to register gensor driver already exist\n");
		}
	
		if (humidity_init_list[i] == NULL) {
			obj->platform_diver_addr = &humidity_driver;
			humidity_init_list[i] = obj;
			break;
		}
	}
	if (i >= MAX_CHOOSE_HMDY_NUM) {
		HMDY_PR_ERR("HMDY driver add err\n");
		err = -1;
	}
	
	return err;

}

其實就是將我們自定義的struct hmdy_init_info aht10_init_info結構體保存到全局變量數組humidity_init_list中。然後在humidity驅動起來的時候,會通過hmdy_real_driver_init()接口調用已經註冊的sensor的init函數:

static int hmdy_real_driver_init(void)
{
	int i = 0;
	int err = 0;

	for (i = 0; i < MAX_CHOOSE_HMDY_NUM; i++) {
		if (humidity_init_list[i] != 0) {
			err = humidity_init_list[i]->init();
			if (err == 0) {
				break;
			}
		}
	}
	
	if (i == MAX_CHOOSE_HMDY_NUM) {
		err = -1;
	}
	return err;

}

這裏的init()函數對應到我們sensor的aht10_local_init函數:

static int aht10_local_init(void)
{
    if (i2c_add_driver(&aht10_i2c_driver)) {
		return -1;
	}
	if (-1 == aht10_init_flag) {
		return -1;
	}
	return 0;
}

到這裏就是我們熟悉的I2C設備註冊函數了i2c_add_driver()。假設我們的sensor設備也正常加入到系統,調用我們自定義的probe函數,這裏面就需要我們進行三步重要的操作:

(1)設置設備資源
sensor框架爲我們提供了接口get_hmdy_dts_func()去解析我們的設備資源,包含I2C的地址,是否支持設置採樣率等等。

(2)struct hmdy_control_path
我們要設置自己的struct hmdy_control_path結構體初始值:

struct hmdy_control_path hmdy_control_path = {0};

hmdy_control_path.is_use_common_factory = false;
hmdy_control_path.open_report_data = aht10_open_report_data; /* 作用未知,一般直接返回就好 */
hmdy_control_path.enable_nodata = aht10_enable_nodata; /* 上層在打開sensor設備的時候,會調用到這個函數 */
hmdy_control_path.set_delay = aht10_set_delay; /* 字面上是用來設置延時,不過如果不需要可以直接返回 */
hmdy_control_path.is_report_input_direct = false; 
hmdy_control_path.is_support_batch = dev_data->hw->is_batch_supported_hmdy; /* 是否支持設置採樣率 */

ret = hmdy_register_control_path(&hmdy_control_path); /* 將前面設置好的struct hmdy_control_path結構體通過公共接口註冊進系統 */
if (ret) {
	AHT_INFO("register hmdy control path err\n");
	goto exit_delete_attr;
}

(3)struct hmdy_data_path

struct hmdy_data_path hmdy_data_path = {0};
hmdy_data_path.get_data = aht10_get_humidity_data;
hmdy_data_path.vender_div = 10;
ret = hmdy_register_data_path(&hmdy_data_path);
if (ret) {
	AHT_INFO("hmdy_register_data_path failed, ret = %d\n", ret);
	goto exit_delete_attr;
}

這個結構體纔是重頭戲,其中get_data接口就是用來獲取sensor想要上報的數據:

int (*get_data)(int *value, int *status);

其中,value就是上報的數據值,同時通過status上報sensor的狀態。另外,上報的數據有時候需要調整一個百分比,那麼就會用到vender_div值了,在調試過程中自行調整即可。設置完畢就可以通過接口hmdy_register_data_path()將我們自定義的結構體註冊進系統了。

結語

kernel層框架的要點大概就這麼多,不同的sensor,基本的驅動流程都類似,讀完我這系列文章後應該就能一通百通了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章