【Linux驱动开发】基础流程

一、修改设备树

1、在pinctrl子系统对应节点添加子节点,即在 iomuxciomuxc_snvs 节点添加新的子节点,即添加设备对应的 IO 。

示例

pinctrl_i2c1: i2c1grp { 
		fsl,pins = < 
			MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0
			MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0
		>;
};

节点标签:节点名{
        引脚属性字符串 = <
            使用的引脚_引脚复用功能 电气特性(IO 的上/下拉、驱动能力和速度等)
        >;
}

注意:节点标签,节点名可自定义,但节点标签前缀一定要为 pinctrl_

2、在 I2C 、SPI 等节点下添加子节点,杂项驱动(MISC)在根节点下添加节点,配置设备相关属性信息

示例

&i2c1 {
	clock-frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c1>;
	status = "okay";
 
	ap3216c@1e { 
		compatible = "iot,ap3216c"; 
		reg = <0x1e>;
	};	

};


&节点标签 {
	属性 = 值;
	pinctrl-names = "default";    //设备的状态(state),default(默认状态)和sleep(休眠状态)。
	pinctrl-0 = <&节点标签>;        //"default"状态,对应的引脚在pinctrl-0定义
	pinctrl-1 = <&节点标签>;     //"sleep"状态,对应的引脚在pinctrl-1定义
	status = "okay";               //状态值
 
        /*追加子节点-i2c1上的设备*/
	子节点名@地址 { 
        兼容性属性 = 匹配字符串;
		reg = <0x1e>;    //地址
	};	
 
};

3、编译设备树

make dtbs

 

二、编写设备驱动程序

1、编写设备驱动程序

/* 驱动的probe函数 */
static int xxx_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	/* 具体实现 */
}
 
/* 驱动的remove函数 */
static int xxx_remove(struct i2c_client *client)
{
	/* 具体实现 */
}

/* 传统匹配方式ID列表 */
static const struct i2c_device_id xxx_id[] = {
	{"xxx,xxx", 0},  //匹配在设备树对应xxx节点下定义的compatible 
	{}
};

/* 设备树匹配列表 */
static const struct of_device_id ap3216c_of_match[] = {
	{ .compatible = "iot,xxx" },    //匹配在设备树对应xxx节点下定义的compatible
	{ /* Sentinel */ }
};
 
//=======================================================================================
/* i2c驱动结构体 */	
static struct i2c_driver xxx_driver = {
	.probe = xxx_probe,        //探测函数(查询、注册、创建设备等)
	.remove = xxx_remove,    //卸载函数(删除设备)
	.driver = {
			.owner = THIS_MODULE,  //当前模块
		   	.name = "xxx",        //设备名
		   	.of_match_table = xxx_of_match, //设备树匹配表(匹配设备树里面的定义)
		   },
	.id_table = xxx_id,    //id匹配表
};
//=======================================================================================
		   
/* 驱动入口函数 */
static int __init xxx_init(void)
{
	int ret = 0;
 
	ret = i2c_add_driver(&xxx_driver);
	return ret;
}
 
/* 驱动出口函数 */
static void __exit xxx_exit(void)
{
	i2c_del_driver(&xxx_driver);
}
 
module_init(xxx_init);    //指定驱动入口函数
module_exit(xxx_exit);    //指定驱动出口函数

MODULE_LICENSE("GPL");    //LICENSE
MODULE_AUTHOR("pjw");    //作者信息

(1)根据结构体需要编写对应的 probe函数、remove函数、设备树匹配表、ID匹配表等。

  • platform 有对应的 platform_driver 结构体。
  • I2C 有对应的 i2c_driver 结构体。
  • SPI 有对应的 spi_driver 结构体。

(2)指定驱动入口函数和出口函数。

  • platform 使用 platform_driver_register(注册)函数、platform_driver_unregister(注销)函数。
  • I2C 使用 i2c_add_driver(注册)函数、i2c_del_driver (注销)函数。
  • SPI 使用 spi_register_driver(注册)函数、spi_unregister_driver(注销)函数。

 

2、编写应用程序

3、编写Makefile

 

三、编译设备驱动

make -j12    //编译驱动
arm-linux-gnueabihf-gcc xxxApp.c -o xxxApp    //编译应用程序

 

四、测试设备驱动

1、Linux 系统选择通过 TFTP 从网络启动,并且使用 NFS 挂载网络根文件系统

(1)将编译出的 imx6ull-iot-emmc.dtb (arch/arm/boot/dts/目录)与 zImage(arch/arm/boot/目录)复制到 tftp 文件夹
(2)设置 bootargs 环境变量,根文件系统从 nfs/roofts 启动

setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs rw nfsroot=192.168.137.18:/home/pjw/linux/nfs/rootfs ip=192.168.137.20:192.168.137.18:192.168.1.1:255.255.255.0::eth0:off'

(3)设置 bootcmd 环境变量,通过 TFTP 启动内核和设备树

setenv bootcmd 'tftp 80800000 zImage;tftp 83000000 imx6ull-iot-emmc.dtb;bootz 80800000 - 83000000'

(4)使用新的 imx6ull-alientek-emmc.dtb 启动 Linux 内核。启动成功以后进入 /proc/device-tree/ 目录中查看节点。
 

2、加载驱动模块

depmod                 //第一次加载驱动的时候需要运行此命令
modprobe xxx.ko         //加载驱动 xxx

lsmod                   //查看当前系统中存在的模块
cat /proc/devices        //查看当前系统中的设备

 

 3、测试应用程序

./xxxApp /dev/xxx

 

4、卸载模块

rmmod xxx.ko

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值