【MTK sensor】alsps分析(以色温为例)

-----欢迎点赞,收藏和关注------

alsps架构分析

以ams_tcs3707色温为例

1.sensor驱动添加
int alsps_driver_add(struct alsps_init_info *obj)

所有的sensor驱动都是通过上述函数添加到alsps框架中,注册的结构体自行定义,注意在结构struct alsps_init_info的成员中完成添加的sensor的驱动注册。

alsps_driver_add函数会把结构体struct alsps_init_info保存在一个全局的结构体数组中,如下:

struct alsps_init_info *alsps_init_list[MAX_CHOOSE_ALSPS_NUM];

完成sensor驱动添加的流程是:定义一个struct alsps_init_info结构体,完善结构体成员init,在init中注册sensor驱动,示例:

static int tcs3707_remove(void)
{
	printk("tcs3707_remove\n");
	i2c_del_driver(&ams_driver);
	return 0;
}

static int tcs3707_local_init(void)
{
	printk("tcs3707_local_init\n");
	if (i2c_add_driver(&ams_driver)) {
		APS_ERR("add driver error\n");
		return -1;
	}

	return 0;
}

static struct alsps_init_info tcs3707_init_info = {
		.name = "tcs3707",
		.init = tcs3707_local_init,
		.uninit = tcs3707_remove,
};

static int __init tcs3707_init(void)
{
	printk("tcs3707_init\n");
	if( alsps_driver_add(&tcs3707_init_info) ){
		pr_err("add driver error\n");
		return -1;
	}

	return 0;
}

到此为止sensor驱动就添加进mtk的alsps框架中去了,但是还没有打通和上层的交互的数据流控制流通道。

2.alsps框架运行流程

代码地址:kernel-4.14\drivers\misc\mediatek\sensors-1.0\alsps\alsps.c

alsps框架主要看两个函数:alsps_context_alloc_object()和alsps_real_driver_init()。

alsps框架运行起来时,主要执行上述两个函数,先执行alsps_context_alloc_object(),再执行alsps_real_driver_init()。

alsps_context_alloc_object()函数主要是实现数据上报的工作队列和数据轮询定时器。在alsps_context_alloc_object函数中已经有了光距感的als和ps的数据上报工作队列和数据轮询定时器,但是没有色温的,那么参照als的添加色温的数据上报工作队列、数据轮询定时器和其他数据即可。

alsps_real_driver_init()函数主要是通过前面提到的全局结构体数组调用struct alsps_init_info结构体的init成员,完成sensor驱动的注册。

到此整个alsps的整体框架就跑完了,接下来就要了解alsps框架的数据流和控制流。

3.sensor控制流通道和数据流通道
控制流

首先要知道上层是通过什么接口来通知驱动使能sensor上报数。

可以通过追踪前面提到的alsps_context_alloc_object()函数中的的数据上报工作队列在哪里被调用了。例如:

static struct alsps_context *alsps_context_alloc_object(void)
{	
    ......
    INIT_WORK(&obj->report_als, als_work_func);
	INIT_WORK(&obj->report_ps, ps_work_func);
	INIT_WORK(&obj->report_als_rgb, als_rgb_work_func);//自己添加的色温数据上报工作队列
    init_timer(&obj->timer_als);
	init_timer(&obj->timer_ps);
	init_timer(&obj->timer_als_rgb);//自己添加的色温数据轮询定时器
    ......
}

可以搜索report_als,找到als_poll函数里会调用als的数据上报工作队列,而als_poll是als的数据轮询定时器工作函数,那么可以继续查找als的定时器工作函数在哪里被调用,搜索timer_als,可以看到:

static int als_enable_and_batch(void){
    ......
            if (cxt->is_als_polling_run == false) {
                mod_timer(&cxt->timer_als,jiffies +atomic_read(&cxt->delay_als) 
                       /(1000 / HZ));
                cxt->is_als_polling_run = true;
				cxt->is_als_first_data_after_enable = true;
			}
	......
}

再继续追查als_enable_and_batch函数们可以看到:

static ssize_t als_store_active(struct device *dev,
				struct device_attribute *attr, const char *buf,
				size_t count)
{
	......
	if (handle == ID_LIGHT) {
		if (en) {
			cxt->als_enable = 1;
			last_als_report_data = -1;
		} else if (!en) {
			cxt->als_enable = 0;
		} else {
			pr_err("alsps_store_active error !!\n");
			err = -1;
			goto err_out;
		}
#if defined(CONFIG_NANOHUB) && defined(CONFIG_MTK_ALSPSHUB)
	......
#else
		err = als_enable_and_batch();//als使能控制函数
#endif
	} else if (handle == ID_RGBW) {
		if (en)
			cxt->rgbw_enable = 1;
		else if (!en)
			cxt->rgbw_enable = 0;
		else {
			pr_err("alsps_store_active error !!\n");
			err = -1;
			goto err_out;
		}
#if defined(CONFIG_NANOHUB) && defined(CONFIG_MTK_ALSPSHUB)
	......
#else
	err = als_rgb_enable_and_batch();//模仿als_enable_and_batch添加的色温使能控制函数。
#endif
	}
	......
}

als_store_active函数为上层使能sensor的调用接口,在系统文件的位置为:

/sys/devices/virtual/sensor/m_als_misc/alsactive

alsactive节点的调用可在vendor\mediatek\proprietary\hardware\sensor\sensors-1.0\AmbienteLight.cpp文件中查看。

整个控制流为:向文件alsactive写入数据,使能sensor并轮询sensor数据。

添加的色温sensor需要去模仿als_enable_and_batch实现相同功能的函数als_rgb_enable_and_batch,在这个函数中要主要去实现sensor的使能,定时器实现步骤很简单(定时器按照前面alsps_context_alloc_object函数中的内容添加)。

sensor的控制有一个专门的结构体struct als_control_path去实现,als_control_path结构体中只有als的控制函数成员,这里添加色温的内容到其中:

struct als_control_path {
	int (*open_report_data)(int open); /* open data rerport to HAL */
	int (*enable_nodata)(int en); /* only enable not report event to HAL */
	int (*set_delay)(u64 delay);
	int (*batch)(int flag, int64_t samplingPeriodNs,
		int64_t maxBatchReportLatencyNs);
	int (*flush)(void);	    /* open data rerport to HAL */
	int (*set_cali)(uint8_t *data, uint8_t count);
+	int (*rgbw_enable)(int en);
+	int (*rgbw_batch)(int flag, int64_t samplingPeriodNs,
		int64_t maxBatchReportLatencyNs);
+	int (*rgbw_flush)(void);
	int (*access_data_fifo)(void);
	bool is_report_input_direct;
	bool is_support_batch;
	bool is_polling_mode;
	bool is_use_common_factory;
+	bool is_rgbw_register;
};

此结构体的填充由函数als_register_control_path完成,同样我们要添加和色温相关的控制内容到其中:

int als_register_control_path(struct als_control_path *ctl)
{
	struct alsps_context *cxt = NULL;
	int err = 0;

	cxt = alsps_context_obj;
+	if(ctl->is_rgbw_register){
+		cxt->als_ctl.rgbw_enable = ctl->rgbw_enable;
+		cxt->als_ctl.rgbw_batch = ctl->rgbw_batch;
+		cxt->als_ctl.rgbw_flush = ctl->rgbw_flush;
+		return 0;
+	}
	cxt->als_ctl.set_delay = ctl->set_delay;
	cxt->als_ctl.open_report_data = ctl->open_report_data;
	cxt->als_ctl.enable_nodata = ctl->enable_nodata;
	cxt->als_ctl.batch = ctl->batch;
	cxt->als_ctl.flush = ctl->flush;
	cxt->als_ctl.set_cali = ctl->set_cali;
	cxt->als_ctl.is_support_batch = ctl->is_support_batch;
	cxt->als_ctl.is_report_input_direct = ctl->is_report_input_direct;
	cxt->als_ctl.is_use_common_factory = ctl->is_use_common_factory;

	if (cxt->als_ctl.enable_nodata == NULL || cxt->als_ctl.batch == NULL ||
	    cxt->als_ctl.flush == NULL) {
		printk("als register control path fail\n");
		return -1;
	}

	/* add misc dev for sensor hal control cmd */
	err = als_misc_init(alsps_context_obj);
	if (err) {
		pr_err("unable to register alsps misc device!!\n");
		return -2;
	}
	err = sysfs_create_group(&alsps_context_obj->als_mdev.this_device->kobj,
				 &als_attribute_group);//创建文件节点
	if (err < 0) {
		pr_err("unable to create alsps attribute file\n");
		return -3;
	}
	kobject_uevent(&alsps_context_obj->als_mdev.this_device->kobj,
		       KOBJ_ADD);
	return 0;
}

可以看到als_register_control_path函数中创建了上层调用的节点,在本驱动中既要使用光距感也要使用色温,都会使用这个函数添加控制节点,因此添加了判断标识is_rgbw_register,这样就不会重复创建文件节点和设置其他属性导致出错。

在源码内搜索als_register_control_path函数,可以看到,在自带的源码sensor驱动中的probe中调用了该函数,添加自己要用到的控制函数和变量:

static int stk3a5x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    ...
    struct als_control_path als_ctl = { 0 };
    ...
    als_ctl.open_report_data = als_open_report_data;
	als_ctl.enable_nodata = als_enable_nodata;
	als_ctl.set_delay = als_set_delay;
	als_ctl.batch = als_batch;
	als_ctl.flush = als_flush;
	als_ctl.is_report_input_direct = false;
	als_ctl.is_use_common_factory = false;

	if (1 == obj->hw->polling_mode_als)
	{
		als_ctl.is_polling_mode = true;
	}
	else
	{
		als_ctl.is_polling_mode = false;
	}

#ifdef CUSTOM_KERNEL_SENSORHUB
	als_ctl.is_support_batch = obj->hw.is_batch_supported_als;
#else
	als_ctl.is_support_batch = false;
#endif
	APS_ERR("stk3a5x 24778451 als_register_control_path\n");
	err = als_register_control_path(&als_ctl);
    ......
}         

那么色温sensor的驱动也同样要按照这种格式添加自己的控制函数,实现如下:

int tcs3707_als_interface_init(void)
{

	int err = 0;
	struct als_control_path als_ctl = { 0 };
	struct als_rgb_data_path als_rgb_data = { 0 };
    /*控制流*/
	als_ctl.is_rgbw_register = 1;
	als_ctl.rgbw_enable = rgbw_enable;
	als_ctl.rgbw_batch = rgbw_batch;
	als_ctl.rgbw_flush = rgbw_flush;
	err = als_register_control_path(&als_ctl);
	if (err) {
		APS_ERR("register fail = %d\n", err);
	}
	/*数据流*/
	als_rgb_data.get_data = als_get_data;
	als_rgb_data.als_rgb_get_raw_data = als_get_raw_data;
	err = als_rgb_register_data_path(&als_rgb_data);
	if (err) {
		APS_ERR("als_rgb_register_data_path register fail = %d\n", err);
	}
	als_ctl.is_rgbw_register = 0;	

	return 0;
}

把该函数添加到色温驱动的probe函数中即可,然后实现三个函数(rgbw_enable、rgbw_batch和rgbw_flush)。

到此上层对底层的控制基本就完成了,重要的还是rgbw_enable函数,其他可以为空。

数据流

数据是通过输入sensor_input_event函数上报,前面已经提到数据的轮询,和数据上报工作队列。

重点就是要完成数据上报工作对列函数,数据轮询是每隔一段调用数据上报工作队列。

同样的模仿als的work_fun函数添加自己的rgb_work_func函数:

static void als_rgb_work_func(struct work_struct *work)
{
	struct alsps_context *cxt = NULL;
	static int32_t value[4];
	int err = 0;
	
	cxt  = alsps_context_obj;
	if (cxt->als_rgb_data.als_rgb_get_raw_data == NULL) {
		ALSPS_PR_ERR("alsps driver not register als_rgb_get_raw_data path\n");
		return;
	}	
	
	err = cxt->als_rgb_data.als_rgb_get_raw_data((int32_t*)value);
	if (err) {
		ALSPS_PR_ERR("get alsps rgb data fails!!\n");
		goto als_loop;
	}	
	rgbw_data_report((int32_t*)value);//对sensor_input_event函数进行了封装
	
als_loop:
	if (true == cxt->is_als_rgb_polling_run)
		mod_timer(&cxt->timer_als_rgb, jiffies + atomic_read(&cxt->delay_als_rgb)/(1000/HZ));
}

可以看到有用到获取数据的结构体,同样模仿als_data,来添加自己的结构als_rgb_data:

struct als_data_path {
	int (*get_data)(int *als_value, int *status);
	int (*als_get_raw_data)(int *als_value);
	int vender_div;
};

struct als_rgb_data_path {
	int (*get_data)(int *rgb_value, int *status);
	int (*als_rgb_get_raw_data)(int *rgb_value);
	int vender_div;
};

struct alsps_context {
	struct input_dev *idev;
	struct sensor_attr_t als_mdev;
	struct sensor_attr_t ps_mdev;
	struct work_struct report_ps;
	struct work_struct report_als;
+	struct work_struct report_als_rgb;
	
	struct mutex alsps_op_mutex;
	struct timer_list timer_als; /*als polling timer */
	struct timer_list timer_ps;  /* ps polling timer */
+	struct timer_list timer_als_rgb;

	atomic_t trace;
	atomic_t delay_als; /*als polling period for reporting input event*/
	atomic_t delay_ps;  /*ps polling period for reporting input event*/
+	atomic_t delay_als_rgb;
	atomic_t wake;      /*user-space request to wake-up, used with stop*/

	atomic_t early_suspend;

	struct alsps_data drv_data;
	struct als_control_path als_ctl;
	struct als_data_path als_data;
+	struct als_rgb_data_path als_rgb_data;
	struct ps_control_path ps_ctl;
	struct ps_data_path ps_data;
	/* Active, but HAL don't need data sensor.such as orientation need */
	bool is_als_active_nodata;
	bool is_als_active_data;   /* Active and HAL need data . */
	/* Active, but HAL don't need data sensor.such as orientation need */
	bool is_ps_active_nodata;
	bool is_ps_active_data;    /* Active and HAL need data . */

	bool is_als_first_data_after_enable;
	bool is_ps_first_data_after_enable;
	bool is_als_polling_run;
	bool is_ps_polling_run;
	bool is_als_rgb_polling_run;
	/* v2.judging whether sensor is in batch mode */
	bool is_als_batch_enable;
	bool is_ps_batch_enable;
	bool is_get_valid_ps_data_after_enable;
	bool is_get_valid_als_data_after_enable;
	int als_power;
+	int rgbw_power;
	int als_enable;
+	int rgbw_enable;
	int64_t als_delay_ns;
	int64_t als_latency_ns;
	int64_t als_rgb_delay_ns;
	int64_t als_rgb_latency_ns;
+	int64_t rgbw_delay_ns;
+	int64_t rgbw_latency_ns;
};

这里的struct alsps_context结构的成员添加,在前面的介绍中就应该已经添加完,这贴出来做参考。

数据结构也要通过一个函数来添加到全局结构体struct alsps_context中,模仿als_register_data_path函数添加als_rgb_register_data_path函数:

int als_rgb_register_data_path(struct als_rgb_data_path *data)
{
	struct alsps_context *cxt = NULL;
	cxt = alsps_context_obj;
	cxt->als_rgb_data.als_rgb_get_raw_data = data->als_rgb_get_raw_data;
	if (cxt->als_rgb_data.als_rgb_get_raw_data == NULL) {
		ALSPS_LOG("als rgbw register data path fail\n");
		return -1;
	}
	return 0;
}

然后继续完成struct als_rgb_data_path 结构体成员的添加(已经在控制流阶段贴出代码,这里删减后再贴出):

int tcs3707_als_interface_init(void)
{

	int err = 0;
	struct als_rgb_data_path als_rgb_data = { 0 };
    ...
	/*数据流*/
	als_rgb_data.get_data = als_get_data;
	als_rgb_data.als_rgb_get_raw_data = als_get_raw_data;
	err = als_rgb_register_data_path(&als_rgb_data);
	if (err) {
		APS_ERR("als_rgb_register_data_path register fail = %d\n", err);
	}
	...

	return 0;
}

函数als_get_data可以为空,不进行调用。主要去完成als_get_raw_data函数,和色温驱动的数据获取函数对接,按照rgb数据格式上报数据即可。

到此alsps的框架就分析完了,了解上层是通过哪些节点(系统文件夹m_als_misc下)控制sensor的状态,了解数据是如何上报(通过定时器每隔一段时间,去调用工作队列获取sensor数据然后上报)。

其他的sensor框架和alsps类似,可做为参考。

-----欢迎点赞,收藏和关注------

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MTK Sensor框架是指在MTK(联发科技)芯片上运行的安卓系统的传感器框架。该框架基于MTK芯片的特性和安卓系统的要求,提供了传感器的驱动和数据处理功能。 MTK Sensor框架的主要特点包括: - 驱动程序:MTK Sensor框架提供了传感器驱动程序,用于与硬件传感器进行通信和控制。这些驱动程序负责读取传感器的原始数据,并将其传递给上层应用程序。 - 数据处理:MTK Sensor框架还提供了数据处理功能,用于对传感器数据进行处理和解析。这些功能包括数据滤波、校准和转换等,以确保传感器数据的准确性和可靠性。 - 上层接口:MTK Sensor框架通过一组API(应用程序接口)提供给上层应用程序使用。开发人员可以使用这些API来访问传感器数据,并根据需要进行处理和分析。 高通Sensor框架是指在高通(Qualcomm)芯片上运行的安卓系统的传感器框架。与MTK Sensor框架类似,高通Sensor框架也提供了传感器的驱动和数据处理功能。 高通Sensor框架的主要特点包括: - 驱动程序:高通Sensor框架提供了传感器驱动程序,用于与硬件传感器进行通信和控制。这些驱动程序负责读取传感器的原始数据,并将其传递给上层应用程序。 - 数据处理:高通Sensor框架还提供了数据处理功能,用于对传感器数据进行处理和解析。这些功能包括数据滤波、校准和转换等,以确保传感器数据的准确性和可靠性。 - 上层接口:高通Sensor框架通过一组API(应用程序接口)提供给上层应用程序使用。开发人员可以使用这些API来访问传感器数据,并根据需要进行处理和分析。 总结来说,MTK Sensor框架和高通Sensor框架都是在安卓系统用于处理传感器数据的框架。它们提供了驱动程序和数据处理功能,以及上层接口供开发人员使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值