驱动开发流程包括:
1、需要查看原理图,数据手册,了解设备的操作方法,属于业务方面内容,在此不做赘述;
2、实现驱动程序的初始化,比如内核注册这个驱动程序,如果该设备有中断响应需要处理,则还要进行中断的定义和初始化工作,内核注册需要用到
Z_DEVICE_DEFINE(node_id, dev_name, drv_name, init_fn, pm_device,\
data_ptr, cfg_ptr, level, prio, api_ptr, state_ptr, ...)
完成定义设备实例并声明其初始化函数的工作,其中init_fn为驱动及中断响应的定义及初始化工作,api_ptr为注册的设备驱动API接口,data_ptr为设备实例私有数据(在data_ptr设置的信息可以通过device handle->data直接使用),cfg_ptr为设备实例配置信息(在cfg_ptr设置的cfg信息可以通过device handle->config直接使用),举例如下:
typedef struct {
uint32_t cfg_reg_base_addr;
uint32_t cmd_queue_base_addr;
} test_device_cfg_t;static test_device_cfg_t s_test_device_cfg = {
.cfg_reg_base_addr = 0x40000000,
.cmd_queue_base_addr = 0x40001000,
};typedef struct {
hal_test_device_callback_t callback;
void *userdata;
} test_device_data_t;static test_device_data_t s_test_device_data = {
.callback = NULL,
.userdata = NULL,
};static xerror_t test_device_enable_irqs(hal_test_device_handle_t handle,
uint32_t irqs)
{
test_device_cfg_t *test_device_cfg =
(test_device_cfg_t *) ((hal_device_handle_t) handle)->config;
.........................................................................
在函数内就可以使用test_device_cfg处理和struct test_device_cfg_t字段相关的内容
.........................................................................
return SUCCESS;
}/*test_device_register_callback调用点在业务代码侧,实现并注册callback,
在业务代码侧以初始化方式注册到操作系统中,在实际业务调度时生效*/
static xerror_t test_device_register_callback(hal_test_device_handle_t handle,
void *callback, void *userdata)
{
test_device_data_t *test_device_data =
(test_device_data_t *) ((hal_device_handle_t) handle)->data;test_device_data->callback = callback;
test_device_data->userdata = userdata;return XRTE_SUCCESS;
}hal_test_device_api_t s_test_device_api = {
...
.register_callback = test_device_register_callback,
...
}Z_DEVICE_DEFINE(..., ..., &s_test_device_data, &s_test_device_cfg,
..., ..., ..., ..., &s_test_device_api )
内核注册主要是一些设备设备相关内容,所以需要每次操作都可以获取设备句柄(如上述例子中的hal_test_device_handle_t handle),获取方式为通过static inline const struct device * device_get_binding(const char * name)即可,其中name即为设备树中lable属性的值信息。
3、设计所要实现的操作:比如open、close、read、writ、设备寄存器操作等函数;
4、实现中断服务,并不是每个设备驱动都必须的,处理中断函数模型如下
TEST_DEV_FUNC_IRQ_MASK = GENMASK(11, 0),
/*处理中断前首先需要屏蔽该设备的中断功能*/
test_dev_mask_func_inter(test_dev_cfg->cfg_reg_base_addr, TEST_DEV_FUNC_IRQ_MASK);
............
处理中断
............
/*中断处理结束后需要将该中断清掉*/
test_dev_clr_func_irq(test_dev_cfg->cfg_reg_base_addr, func_irq_status & TEST_DEV_FUNC_IRQ_MASK);
/*处理中断前首先需要打开该设备的中断功能*/
test_dev_unmask_func_inter(test_dev_cfg->cfg_reg_base_addr, TEST_DEV_FUNC_IRQ_MASK);
5、编译驱动到内核,或作为模块动态加载;
通过CMakeLists.txt实现编译进内核
6、测试驱动;