基于I.MX6UL平台的ADS1256驱动开发三.基础驱动框架
我们通过前两章的内容完成了驱动移植和重构的准备工作,下面我们就开始处理驱动代码了。
驱动的基础架构我们采用和前面学习的platform框架一样,并且通过GPIO子系统对GPIO实现初始化的配置。
1 /** 2 * @file ads1256_base1.c 3 * @author your name (you@domain.com) 4 * @brief platform基础框架 5 * @version 0.1 6 * @date 2022-12-05 7 * 8 * @copyright Copyright (c) 2022 9 * 10 */ 11 #include <linux/module.h> 12 #include <linux/kernel.h> 13 #include <linux/init.h> 14 #include <linux/fs.h> 15 #include <linux/uaccess.h> 16 #include <linux/io.h> 17 #include <linux/types.h> 18 #include <linux/cdev.h> 19 #include <linux/device.h> 20 #include <linux/of.h> 21 #include <linux/of_address.h> 22 #include <linux/of_irq.h> 23 #include <linux/gpio.h> 24 #include <linux/of_gpio.h> 25 #include <linux/irq.h> 26 #include <linux/interrupt.h> 27 #include <linux/input.h> 28 #include <linux/spi/spi.h> 29 #include <linux/delay.h> 30 #include <linux/platform_device.h> 31 32 #include "ads1256.h" 33 #include "ads1256reg.h" 34 /* 35 ADS1256模块 开发板 36 +5V <------ 5.0V 5V供电 37 GND ------- GND 地 38 PDWN <------ PC8 掉电控制 常高 39 RST <------ PC13 复位信号 常高 40 41 DRDY ------> GPIO1_IO24(8) 准备就绪 42 DIN <------ GPIO1_IO22(9) SPI_MOSI 43 DOUT ------> GPIO1_IO23(10) SPI_MISO 44 SCLK <------ GPIO1_IO21(11) SPI时钟 45 CS <------ GPIO1_IO03(15) SPI_CS 46 47 NC 空脚 48 NC 空脚 49 */ 50 51 #define ads1256_CNT 1 52 #define ads1256_NAME "ads1256" 53 54 struct ads1256_device ads1256_dev; 55 56 #define CS_0() gpio_set_value(ads1256_dev.cs_gpio, 0) 57 #define CS_1() gpio_set_value(ads1256_dev.cs_gpio, 1) 58 59 #define SCK_0() gpio_set_value(ads1256_dev.clk_gpio, 0) 60 #define SCK_1() gpio_set_value(ads1256_dev.clk_gpio, 1) 61 62 #define DI_0() gpio_set_value(ads1256_dev.mosi_gpio, 0) 63 #define DI_1() gpio_set_value(ads1256_dev.mosi_gpio, 1) 64 65 #define DO_IS_HIGH() gpio_get_value(ads1256_dev.miso_gpio)==1 66 #define DRDY_IS_LOW() gpio_get_value(ads1256_dev.drdy_gpio)==0 67 68 69 static int ads1256_open(struct inode *inode, struct file *file) 70 { 71 int ret = 0; 72 printk("file open!\r\n"); 73 return ret; 74 } 75 76 ssize_t ads1256_read(struct file *file, char __user *buf, size_t cnt, loff_t *off) 77 { 78 int ret = 0; 79 return ret; 80 } 81 static int ads1256_release(struct inode *inode, struct file *file) 82 { 83 int ret = 0; 84 return ret; 85 } 86 87 struct file_operations ads1256_fops = { 88 .owner = THIS_MODULE, 89 .open = ads1256_open, 90 .read = ads1256_read, 91 .release = ads1256_release, 92 }; 93 94 95 static int ads1256_probe(struct platform_device *dev) 96 { 97 int ret = 0; 98 printk("ads1256 probe\r\n"); 99 100 /*注册字符设备号*/ 101 ads1256_dev.major = 0; 102 if(ads1256_dev.major){ 103 ads1256_dev.dev_id = MKDEV(ads1256_dev.major,0); 104 ret = register_chrdev_region(ads1256_dev.dev_id,ads1256_CNT,ads1256_NAME); 105 } 106 else{ 107 ret = alloc_chrdev_region(&ads1256_dev.dev_id,0,ads1256_CNT,ads1256_NAME); 108 ads1256_dev.major = MAJOR(ads1256_dev.dev_id); 109 ads1256_dev.minor = MINOR(ads1256_dev.dev_id); 110 } 111 printk("major\r\n"); 112 113 if(ret<0) 114 { 115 printk("ads1256 chrdev_region err\r\n"); 116 goto fail_devid; 117 } 118 119 /*添加字符设备*/ 120 ads1256_dev.cdev.owner = THIS_MODULE; 121 cdev_init(&ads1256_dev.cdev,&ads1256_fops); 122 ret = cdev_add(&ads1256_dev.cdev,ads1256_dev.dev_id,ads1256_CNT); 123 if(ret<0) 124 { 125 goto fail_cdev; 126 } 127 128 ads1256_dev.class = class_create(THIS_MODULE,ads1256_NAME); 129 if(IS_ERR(ads1256_dev.class)) 130 { 131 ret = PTR_ERR(ads1256_dev.class); 132 goto fail_class; 133 } 134 135 ads1256_dev.device = device_create(ads1256_dev.class,NULL, 136 ads1256_dev.dev_id,NULL,ads1256_NAME); 137 if(IS_ERR(ads1256_dev.device)) 138 { 139 ret = PTR_ERR(ads1256_dev.device); 140 goto fail_device; 141 } 142 143 /*gpio初始化*/ 144 ads1256_dev.node =of_find_node_by_path("/ads1256"); //获取节点 145 /*片选引脚*/ 146 ads1256_dev.cs_gpio = of_get_named_gpio(ads1256_dev.node,"ads1256-gpios",0); 147 if(ads1256_dev.cs_gpio < 0 ){ 148 printk("can't get gpio cs\r\n"); 149 goto fail_gpio; 150 } 151 152 ret = gpio_request(ads1256_dev.cs_gpio,"cs"); //这里省略判定 153 ret = gpio_direction_output(ads1256_dev.cs_gpio,1); //默认高电平 154 155 /*时钟引脚*/ 156 ads1256_dev.clk_gpio = of_get_named_gpio(ads1256_dev.node,"ads1256-gpios",1); 157 if(ads1256_dev.clk_gpio < 0 ){ 158 printk("can't get gpio clk\r\n"); 159 goto fail_gpio; 160 } 161 162 ret = gpio_request(ads1256_dev.clk_gpio,"clk"); //这里省略判定 163 ret = gpio_direction_output(ads1256_dev.clk_gpio,0); //默认低 164 if(ret<0){ 165 printk("clk_gpio request faild\r\n"); 166 goto fail_gpio; 167 } 168 169 /*MOSI引脚*/ 170 ads1256_dev.mosi_gpio = of_get_named_gpio(ads1256_dev.node,"ads1256-gpios",2); 171 if(ads1256_dev.mosi_gpio < 0 ){ 172 printk("can't get gpio mosi\r\n"); 173 goto fail_gpio; 174 } 175 176 ret = gpio_request(ads1256_dev.mosi_gpio,"mosi"); //这里省略判定 177 ret = gpio_direction_output(ads1256_dev.mosi_gpio,0); //默认低电平 178 if(ret<0){ 179 printk("mosi_gpio request faild\r\n"); 180 goto fail_gpio; 181 } 182 183 /*MISO引脚*/ 184 ads1256_dev.miso_gpio = of_get_named_gpio(ads1256_dev.node,"ads1256-gpios",3); 185 if(ads1256_dev.miso_gpio < 0 ){ 186 printk("can't get gpio miso\r\n"); 187 goto fail_gpio; 188 } 189 190 ret = gpio_request(ads1256_dev.miso_gpio,"miso"); 191 if(ret<0){ 192 printk("miso_gpio request faild\r\n"); 193 goto fail_gpio; 194 } 195 196 /*DRDY引脚*/ 197 ads1256_dev.drdy_gpio = of_get_named_gpio(ads1256_dev.node,"ads1256-gpios",4); 198 if(ads1256_dev.drdy_gpio<0){ 199 printk("can't get gpio drdy"); 200 goto fail_gpio; 201 } 202 203 ret = gpio_request(ads1256_dev.drdy_gpio,"drdy"); 204 if(ret<0){ 205 printk("drdy_gpio request faild\r\n"); 206 goto fail_gpio; 207 } 208 209 return 0; 210 211 fail_gpio: 212 fail_device: 213 class_destroy(ads1256_dev.class); 214 fail_class: 215 cdev_del(&ads1256_dev.cdev); 216 fail_cdev: 217 unregister_chrdev_region(ads1256_dev.dev_id,ads1256_CNT); 218 fail_devid: 219 return 0; 220 } 221 222 223 static int ads1256_remove(struct platform_device *dev) 224 { 225 int ret = 0; 226 227 cdev_del(&ads1256_dev.cdev); 228 unregister_chrdev_region(ads1256_dev.dev_id,ads1256_CNT); 229 device_destroy(ads1256_dev.class,ads1256_dev.dev_id); 230 class_destroy(ads1256_dev.class); 231 gpio_free(ads1256_dev.cs_gpio); 232 gpio_free(ads1256_dev.clk_gpio); 233 gpio_free(ads1256_dev.mosi_gpio); 234 gpio_free(ads1256_dev.miso_gpio); 235 gpio_free(ads1256_dev.drdy_gpio); 236 237 printk("device remove\r\n"); 238 239 return 0; 240 } 241 242 static const struct of_device_id ads1256_of_match[] = { 243 {.compatible = "ads1256"}, 244 {} 245 }; 246 247 248 struct platform_driver ads1256_driver = { 249 .driver = { 250 .name = "ads1256", 251 .of_match_table = ads1256_of_match, 252 }, 253 .probe = ads1256_probe, 254 .remove = ads1256_remove, 255 }; 256 257 static int __init ads1256_init(void) 258 { 259 int ret = 0; 260 printk("__init\r\n"); 261 ret = platform_driver_register(&ads1256_driver); 262 return ret; 263 } 264 265 static void __exit ads1256_exit(void) 266 { 267 platform_driver_unregister(&ads1256_driver); 268 } 269 270 module_init(ads1256_init); 271 module_exit(ads1256_exit); 272 MODULE_LICENSE("GPL"); 273 MODULE_AUTHOR("AC");
整个框架的流程很清楚了!倒着看比较合适
257~263行是驱动的入口,用来匹配ads1256的驱动,加载的过程
248~255行是定义的platform_driver结构体,通过242~245行的结构体进行匹配,在设备树下匹配到一致名称的device,就可以驱动设备,执行第253行probe指向的函数(ads1256_probe)。
ads1256_probe是驱动的主体,主要完成了字符串设备的注册,然后是GPIO的初始化。整个流程在前面写字符设备驱动的流程是完全一致的。没什么可说的。
ads1256_remove函数是驱动卸载时执行的函数,里面就是所用资源的释放。
架构完成以后,可以make生成对应的ko文件,复制到rootfs下加载一下看看效果
一定要重复加载和卸载驱动模块的过程,防止在卸载过程中有哪些资源没有完全释放,导致驱动重新加载失败。(这一章节我把文件名设置为ads1256_base1,表示为驱动基础框架)
上面的内容完成以后,说明GPIO已经可以供我们使用了,我们可以测试一下CS、CLK和MOSI的输出
CS_0(); int i = 0; for(i=0; i<10;i++) { printk("%d\r\n",i); if(i%2==0){ DI_0(); SCK_0(); } else{ DI_1(); SCK_1(); } mdelay(5); } CS_1();
代码直接放在gpio初始化后面,其中DI_0。SCK_1等是前面定义的宏, 直接操作CPIO输出对应的高低电平。
用逻辑分析仪看一下
CS信号应该是一直拉低的,但是会跟着其他两个信号跳变。调整一下代码会发现是时钟信号导致的,不操作时钟的时候就没问题了。
不过这个状态对实际使用时没有影响的,不知道是不是硬件上有什么问题。
下面就需要按照前面的资料完成IC的相关操作了!