zoukankan      html  css  js  c++  java
  • 驱动开发之ADC驱动与通用设备树

    驱动开发之ADC驱动与通用设备树:

    通用设备树:

    让驱动去操作设备树,可以选择platform架构,也可以不选择platform架构。

    vi -t /arch/arm/boot/dts/exynos4412-fs4412中:

    566 ofled{
    567 led2 = <&gpx2 7 0>;
    568 led1 = <&gpx1 0 0>;
    569 led3-4 = <&gpf3 4 0>,<&gpf3 5 0>;
    570 };

    接口:

    1 struct device_node *of_find_node_by_path(const char *path)
    2 功能:查找设备树节点信息(必须包含路径)
    3 返回值:如果在设备树中找到了指定节点,返回值就指向了找到的节点。
    1 static inline int of_get_named_gpio(struct device_node *np,const char *propname, int index)
    2 参数1:of_find_node_by_path的返回值
    3 参数2:属性名称
    4 参数3:属性内容的索引值
    5 返回值:引脚编号(系统动态分配的一个整数值,让这个整数值和实际的物理引脚建立关系)

    ----->此时内核还不认识这些引脚编号么
    -------------->

    1 int gpio_request(unsigned gpio, const char *label)
    2 功能:注册引脚编号
    3 参数1:引脚编号
    4 参数2:引脚的别名
    1 static inline int gpio_direction_output(unsigned gpio, int value)
    2 功能:设置引脚为输出模式
    3 参数1:引脚编号
    4 参数2:指定的是数据寄存器中的默认值
    1 static inline void gpio_set_value(unsigned gpio, int value)
    2 功能:对指定引脚中的数据寄存器设置值
    3 参数1:引脚编号
    4 参数2:数据值
    1 static inline int gpio_to_irq(unsigned int gpio)
    2 功能:获取虚拟中断号
    3 参数:gpio引脚编号

    参考代码LED:

     1 #include <linux/init.h>
     2 #include <linux/module.h>
     3 #include <linux/fs.h>
     4 #include <linux/device.h>
     5 #include <asm/gpio.h>
     6 #include <linux/of.h>
     7 #include <linux/of_gpio.h>
     8 
     9 
    10 int major;
    11 struct class *cls;
    12 struct device *devs;
    13 struct device_node *np;
    14 
    15 int gpx2_7;
    16 int gpx1_0;
    17 int gpf3_4;
    18 int gpf3_5;
    19 
    20 int ofled_open(struct inode *inode,struct file *filp)
    21 {
    22     gpio_set_value(gpx2_7,1);
    23     gpio_set_value(gpx1_0,1);
    24     gpio_set_value(gpf3_4,1);
    25     gpio_set_value(gpf3_5,1);
    26     return 0;
    27 }
    28 
    29 int ofled_close(struct inode *inode,struct file *filp)
    30 {
    31     gpio_set_value(gpx2_7,0);
    32     gpio_set_value(gpx1_0,0);
    33     gpio_set_value(gpf3_4,0);
    34     gpio_set_value(gpf3_5,0);
    35     return 0;
    36 }
    37 
    38 struct file_operations fops = {
    39     .owner = THIS_MODULE,
    40     .open = ofled_open,
    41     .release = ofled_close,
    42 };
    43 
    44 int led_init(void)
    45 {
    46     major = register_chrdev(0,"ofled",&fops);
    47     cls = class_create(THIS_MODULE,"ofled");
    48     devs = device_create(cls,NULL,MKDEV(major,0),NULL,"ofled");
    49     
    50     //查找节点名称
    51     np = of_find_node_by_path("/ofled");
    52     
    53     //获取gpio引脚编号
    54     gpx2_7 = of_get_named_gpio(np,"led2",0);
    55     gpx1_0 = of_get_named_gpio(np,"led1",0);
    56     gpf3_4 = of_get_named_gpio(np,"led3-4",0);
    57     gpf3_5 = of_get_named_gpio(np,"led3-4",1);
    58 
    59     //注册引脚编号
    60     gpio_request(gpx2_7,NULL);
    61     gpio_request(gpx1_0,NULL);
    62     gpio_request(gpf3_4,NULL);
    63     gpio_request(gpf3_5,NULL);
    64     
    65     //设置输出模式
    66     gpio_direction_output(gpx2_7,1);
    67     gpio_direction_output(gpx1_0,1);
    68     gpio_direction_output(gpf3_4,1);
    69     gpio_direction_output(gpf3_5,1);
    70     return 0;
    71 }
    72 module_init(led_init);
    73 
    74 void led_exit(void)
    75 {
    76     return;
    77 }
    78 module_exit(led_exit);
    79 
    80 MODULE_LICENSE("GPL");
    ofled.c
     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/stat.h>
     4 #include <fcntl.h>
     5 
     6 int main(int argc, const char *argv[])
     7 {
     8     int fd;
     9 
    10     fd = open("/dev/ofled",O_RDWR);
    11 
    12     sleep(3);
    13 
    14     close(fd);
    15     return 0;
    16 }
    app.c

    参考代码KEY:

      1 #include <linux/init.h>
      2 #include <linux/module.h>
      3 #include <linux/fs.h>
      4 #include <linux/device.h>
      5 #include <linux/of.h>
      6 #include <linux/of_gpio.h>
      7 #include <asm/gpio.h>
      8 #include <linux/interrupt.h>
      9 #include <linux/irqreturn.h>
     10 #include <asm/uaccess.h>
     11 #include <linux/sched.h>
     12 
     13 struct device_node *np;
     14 
     15 int major;
     16 struct class *cls;
     17 struct device *devs;
     18 
     19 int gpx1_1;
     20 int gpx1_2;
     21 int gpx3_2;
     22 
     23 int irqno1;
     24 int irqno2;
     25 int irqno3;
     26 
     27 int key;
     28 
     29 wait_queue_head_t keyq;//创建等待队列头
     30 int flag = 0;
     31 
     32 irqreturn_t fs4412_ofkey_handler(int irqno,void *id) //中断处理函数
     33 {
     34     if(irqno == irqno1)//判断哪个按键被按下执行相应的操作
     35         key = 1;
     36     
     37     if(irqno == irqno2)
     38         key = 2;
     39 
     40     if(irqno == irqno3)
     41         key = 3;
     42 
     43     wake_up_interruptible(&keyq);//唤醒
     44     flag = 1;
     45     return IRQ_HANDLED;
     46 }
     47 
     48 int fs4412_ofkey_open(struct inode *inode,struct file *filp)
     49 {
     50     return 0;
     51 }
     52 
     53 ssize_t fs4412_ofkey_read(struct file *filp,char __user *ubuf,size_t size,loff_t *off)//给应用层提供接口
     54 {
     55     int ret;
     56 
     57     wait_event_interruptible(keyq,flag != 0);//阻塞等待,中断处理函数处理完成唤醒阻塞
     58     ret = copy_to_user(ubuf,&key,sizeof(key));//将数据拷贝到应用层
     59 
     60     flag = 0;//方便后面操作阻塞
     61     return sizeof(key);
     62 }
     63 //文件操作结构体
     64 struct file_operations fops = {
     65     .owner = THIS_MODULE,
     66     .open = fs4412_ofkey_open,
     67     .read = fs4412_ofkey_read,
     68 };
     69 
     70 int fs4412_ofkey_init(void)
     71 {
     72     int ret;
     73     major = register_chrdev(0,"ofkey",&fops);//注册设备编号
     74     cls = class_create(THIS_MODULE,"ofkey");//创建设备类(名为ofkey的目录)
     75     devs = device_create(cls,NULL,MKDEV(major,0),NULL,"ofkey");//创建设备文件(链接文件)
     76 
     77     np = of_find_node_by_path("/fskey");//查找设备树节点信息
     78 
     79     gpx1_1 = of_get_named_gpio(np,"key1",0);//获取引脚编号,0表示索引值,设备树中led1 = <>(0),<>(1),<>(3)...
     80     gpx1_2 = of_get_named_gpio(np,"key2",0);
     81     gpx3_2 = of_get_named_gpio(np,"key3",0);
     82 
     83     gpio_request(gpx1_1,NULL);//注册引脚编号,取别名不取默认为NULL
     84     gpio_request(gpx1_2,NULL);
     85     gpio_request(gpx3_2,NULL);
     86 
     87     gpio_direction_input(gpx1_1);//设置引脚为输出模式
     88     gpio_direction_input(gpx1_2);
     89     gpio_direction_input(gpx3_2);
     90     
     91     irqno1 = gpio_to_irq(gpx1_1);//获取中断号
     92     irqno2 = gpio_to_irq(gpx1_2);
     93     irqno3 = gpio_to_irq(gpx3_2);
     94 
     95     ret = request_irq(irqno1,fs4412_ofkey_handler,IRQF_TRIGGER_FALLING,"key1",NULL);//注册中断
     96     ret = request_irq(irqno2,fs4412_ofkey_handler,IRQF_TRIGGER_FALLING,"key2",NULL);//IRQF_TRIGGER_FALLING中断触发方式为下降沿触发
     97     ret = request_irq(irqno3,fs4412_ofkey_handler,IRQF_TRIGGER_FALLING,"key3",NULL);
     98 
     99     init_waitqueue_head(&keyq);//初始化等待队列头
    100     return 0;
    101 }
    102 module_init(fs4412_ofkey_init);//模块加载
    103 
    104 void fs4412_ofkey_exit(void)
    105 {
    106     return ;
    107 }
    108 module_exit(fs4412_ofkey_exit);//模块卸载
    109 MODULE_LICENSE("GPL");//模块声明
    ofkey.c
     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/stat.h>
     4 #include <fcntl.h>
     5 
     6 int main(int argc, const char *argv[])
     7 {
     8     int fd;
     9 
    10     fd = open("/dev/ofkey",O_RDWR);
    11 
    12     int key;
    13     while(1)
    14     {
    15         read(fd,&key,sizeof(key));
    16         printf("key = %d
    ",key);
    17     }
    18     close(fd);
    19     return 0;
    20 }
    app.c

    ADC底层驱动:

    添加设备树:

    1、查看原理图
      XadcAIN3 不是中断引脚,只是指定了ad转换通道为3
    2、查看芯片手册第十章
      INTG10 [3] ADC General ADC
      中断组合器的第十组,第三位控制了ADC中断
    3、vi Documetation/devicetree/bindings/arm/samsung/interrupt-combiner.txt
    4、需要使用寄存器
      ADCCON:
        [0] 代表ad转换的起始位,每次转换成功后都会被清零。每次转换数据成功后都会自动产生一次中断
        [13,6] 设置的预分频值
        [14] 使能预分频值
        [16] 设置转换精度
      ADCDAT:用来存放转换后的数据(驱动需要读取这里的内容)
      CLRINTADC:中断清除寄存器,被写入任意值。
      ADCMUX:设置AD转换通道为3

    ------>

    1 fs4412-adc{
    2 compatible = ",";
    3 interrupt-parent = <&combiner>; vi exynos4.dtsi文件中找到combiner:
    4 interrupts = <10 3>;
    5 reg = <126c0000 0x20>;
    6 };
    1 获取指定(IORESOURCEB表示中断)资源类型:
    2 platform_get_resource(pdev,IORESOURCE_IRQ,0);

    参考代码ADC:

      1 #include <linux/module.h>
      2 #include <linux/fs.h>
      3 #include <linux/platform_device.h>
      4 #include <linux/device.h>
      5 #include <asm/io.h>
      6 #include <asm/uaccess.h>
      7 #include <linux/interrupt.h>
      8 #include <linux/sched.h>
      9 #include <linux/irqreturn.h>
     10 
     11 
     12 int major;
     13 struct class *cls;
     14 struct device *devs;
     15 
     16 struct resource *res_mem;
     17 struct resource *res_irq;
     18 
     19 void __iomem *adc_base;//必须是void __iomem类型因为偏移地址不一样
     20 wait_queue_head_t adcq;
     21 int flag = 0;
     22 
     23 irqreturn_t fs4412_adc_handler(int irqno,void *id)
     24 {
     25     //开始必须要清中断,内核没有进行清中断我们必须在驱动中手动清中断
     26     writel(0,adc_base + 0x18);
     27     wake_up_interruptible(&adcq);
     28     flag = 1;
     29     return IRQ_HANDLED;
     30 }
     31 
     32 struct of_device_id fs4412_adc_match_tbl[] = {
     33     {
     34         .compatible = "fs4412,adc",
     35     },
     36     {},
     37 };
     38 
     39 int fs4412_adc_open(struct inode *inode,struct file *filp)
     40 {
     41     return 0;
     42 }
     43 
     44 ssize_t fs4412_adc_read(struct file *filp,char __user *ubuf,size_t size,loff_t *off)
     45 {
     46     int ret;
     47     int data;
     48     //开始转换数据
     49     writel(readl(adc_base) | 1 << 0,adc_base);//转换完成后才会出现中断
     50     
     51     //阻塞
     52     wait_event_interruptible(adcq,flag != 0);
     53 
     54     //只有转化完成且中断唤醒阻塞后才能读取数据,直接不能读取数据
     55     data = readl(adc_base + 0x0c) & 0xfff;
     56     ret = copy_to_user(ubuf,&data,sizeof(data));
     57     flag = 0;
     58     return sizeof(data);
     59 }
     60 
     61 struct file_operations fops = {
     62     .owner = THIS_MODULE,
     63     .open = fs4412_adc_open,
     64     .read = fs4412_adc_read,
     65 };
     66 
     67 int fs4412_adc_probe(struct platform_device *pdev)
     68 {
     69     int ret;
     70     printk("match ok
    ");
     71 
     72     major = register_chrdev(0,"adc",&fops);
     73     cls = class_create(THIS_MODULE,"adc");
     74     devs = device_create(cls,NULL,MKDEV(major,0),NULL,"adc");
     75 
     76     res_irq = platform_get_resource(pdev,IORESOURCE_IRQ,0);//获取指定(中断)资源类型
     77     ret = request_irq(res_irq->start,fs4412_adc_handler,0,"adc",NULL);
     78 
     79 
     80     res_mem = platform_get_resource(pdev,IORESOURCE_MEM,0);//获取指定(内存)资源类型
     81     adc_base = ioremap(res_mem->start,0x20);//将物理地址映射成虚拟地址
     82 
     83     writel(255 << 6 | 1 << 14 | 1 << 16,adc_base);
     84     writel(3,adc_base + 0x1c);
     85 
     86     init_waitqueue_head(&adcq);
     87     return 0;
     88 }
     89 
     90 int fs4412_adc_remove(struct platform_device *pdev)
     91 {
     92     return 0;
     93 }
     94 
     95 struct platform_driver pdrv = {
     96     .driver = {
     97         .name = "adc",
     98         .of_match_table = fs4412_adc_match_tbl,
     99     },
    100 
    101     .probe = fs4412_adc_probe,
    102     .remove = fs4412_adc_remove,
    103 };
    104 module_platform_driver(pdrv);
    105 MODULE_LICENSE("GPL");
    ADC.c
     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/stat.h>
     4 #include <fcntl.h>
     5 
     6 int main(int argc, const char *argv[])
     7 {
     8     int fd;
     9 
    10     fd = open("/dev/adc",O_RDWR);
    11 
    12     int data;
    13     while(1)
    14     {
    15         read(fd,&data,sizeof(data));
    16         printf("data = %d
    ",data);
    17         sleep(1);
    18     }
    19     close(fd);
    20     return 0;
    21 }
    app.c

    总结:

     1 驱动使用设备树时可以通过platform总线来和设备树匹配。
     2 也可以不使用platform总线,需要查询节点名称,进而获取节点中的属性。
     3 
     4 of_find_node_by_path();//查询设备树中指定节点。
     5 
     6 引脚编号 of_get_named_gpio();//从设备树的属性中获取寄存器信息并且产生gpio引脚编号
     7 
     8 gpio_request();//注册引脚编号
     9 
    10 gpio_direction_output();//设置为输出模式
    11 gpio_direction_input();//设置为输入模式
    12 
    13 gpio_set_value();//设置寄存器的值
    14 gpio_get_value();//获取寄存器的值
    15 
    16 gpio_to_irq();//从设备树中获取虚拟中断号
    17 
    18 adc设备树添加:
    19 fs4412-adc{
    20     compatible = ",";
    21     interrupt-parent = <&combiner>;
    22     interrupts = <10 3>;
    23     reg = <0x126c0000 0x20>;
    24 };
    25 
    26 ADCCON:设置预分频值、使能预分频值、设置转换精度
    27        [0]控制是否开始进行AD转换,当AD转换成功后会产生一次中断。
    28 ADCDAT:存放转化后的数据
    29 CLRINTADC:清除中断      
    30 ADCMUX:设置转换通道 
    总结
  • 相关阅读:
    python2.7 使用super关键词 报错 TypeError: must be type, not classobj 解决办法
    ACM_高次同余方程
    既然选择了、再怎么艰难也要走下去
    ACM_扩展欧几里德算法
    Codeforces Round #328 (Div. 2)_B. The Monster and the Squirrel
    Codeforces Round #328 (Div. 2)_A. PawnChess
    HDU_5523Game
    POJ_2769同余问题
    poj1258prim算法
    最小生成树—prim算法
  • 原文地址:https://www.cnblogs.com/hslixiqian/p/9676526.html
Copyright © 2011-2022 走看看