基于tiny4412的Linux內核移植 --- 实例学习中断背后的知识(2)

发布者:紫色小猫最新更新时间:2023-06-20 来源: elecfans关键字:tiny4412  Linux  內核移植  中断 手机看文章 扫描二维码
随时随地手机看文章

平台

tiny4412 ADK

Linux-4.9

 

概述

前面一篇博文基於tiny4412的Linux內核移植 --- 实例学习中断背后的知识(1)结合示例分析了一下新版kernel引入设备树和irq domain后中断幕后的一些知识,其中的示例只是使用gpio中断的一种方式,此外,还有一种,就像博文

基於tiny4412的Linux內核移植--- 中斷和GPIO學習(1)中描述的那样,这种实现方式又是如何进行的呢?下面还是结合示例的方式分析。


正文

框图可以参考前一篇博文。

在前一篇博文的第三部分 GPIO控制器驱动中有一个函数我们没有分析,就是samsung_gpiolib_register,把这函数看懂了,后面的分析就顺了,下面的分析最好结合前一篇博文的第三部分 GPIO控制器驱动一块看。

这里还是以pinctrl@11000000这个节点为例分析。

samsung_gpiolib_register

 1 static int samsung_gpiolib_register(struct platform_device *pdev,

 2                     struct samsung_pinctrl_drv_data *drvdata)

 3 {

 4     struct samsung_pin_bank *bank = drvdata->pin_banks;

 5     struct gpio_chip *gc;

 6     int ret;

 7     int i;

 8     for (i = 0; i < drvdata->nr_banks; ++i, ++bank) {  // 遍历pinctrl@11000000下的所有bank,我们关心的是gpx3这个bank

 9         bank->gpio_chip = samsung_gpiolib_chip;   // gpio_chip

10         gc = &bank->gpio_chip;

11  // 这个bank的gpio在系统中的逻辑起始号, 其中drvdata->pin_base是pinctrl@11000000的在系统中的逻辑gpio起始号,

12  // 而bank->pin_base是这个bank在pinctrl@11000000中的逻辑起始号(从0开始)

13         gc->base = drvdata->pin_base + bank->pin_base; 

14         gc->ngpio = bank->nr_pins;  // 这个bank中含有的gpio的个数

15         gc->parent = &pdev->dev;

16         gc->of_node = bank->of_node;  //对于gpx3来说,就是gpx3那个节点的node

17         gc->label = bank->name;

18         ret = gpiochip_add_data(gc, bank);

19 ...

20     }

21     return 0;

22 ...

23 }


    ---> gpiochip_add_data(struct gpio_chip *chip, void *data)


 1 int gpiochip_add_data(struct gpio_chip *chip, void *data)

 2 {

 3     unsigned long    flags;

 4     int        status = 0;

 5     unsigned    i;

 6     int        base = chip->base;

 7     struct gpio_device *gdev;

 8  // 每一个bank都都应一个唯一的gpio_device和gpio_chip

 9     gdev = kzalloc(sizeof(*gdev), GFP_KERNEL);

10     gdev->dev.bus = &gpio_bus_type;

11     gdev->chip = chip;

12     chip->gpiodev = gdev;

13  ... ...

14     if (chip->of_node)

15         gdev->dev.of_node = chip->of_node;

16  

17  // 分配一个唯一的id

18     gdev->id = ida_simple_get(&gpio_ida, 0, 0, GFP_KERNEL);

19     dev_set_name(&gdev->dev, "gpiochip%d", gdev->id);

20  ... ...

21  // 为这个chip下的每一个gpio都要分配一个gpio_desc结构体

22     gdev->descs = kcalloc(chip->ngpio, sizeof(gdev->descs[0]), GFP_KERNEL);

23  ... ...

24  // 这个chip中含有的gpio的个数

25     gdev->ngpio = chip->ngpio;

26  // gpx3 这个bank

27     gdev->data = data;

28  ... ...

29  // base表示的是这个bank在系统中的逻辑gpio号

30     gdev->base = base;

31  // 将这个bank对应的gpio_device添加到全局链表gpio_devices中

32  // 在添加的时候会根据gdev->base和ngpio在gpio_devices链表中找到合适的位置

33     status = gpiodev_add_to_list(gdev);

34  ... ...

35     for (i = 0; i < chip->ngpio; i++) {

36         struct gpio_desc *desc = &gdev->descs[i];

37         desc->gdev = gdev;

38   ... ...

39     }

40  ... ...

41  // 默认这个chip下的所有gpio都是可以产生中断

42     status = gpiochip_irqchip_init_valid_mask(chip);

43     status = of_gpiochip_add(chip);

44  ... ...

45     return 0;

46  ... ...

47 }


        ---> of_gpiochip_add(struct gpio_chip *chip)


 1 int of_gpiochip_add(struct gpio_chip *chip)

 2 {

 3     int status;

 4 ... ...

 5     if (!chip->of_xlate) {

 6         chip->of_gpio_n_cells = 2;

 7         chip->of_xlate = of_gpio_simple_xlate;

 8     }

 9 ... ...

10 }


这里需要看一下of_gpio_simple_xlate的实现,这个在下面的分析中会被回调


1 int of_gpio_simple_xlate(struct gpio_chip *gc,

2              const struct of_phandle_args *gpiospec, u32 *flags)

3 {

4 .. ...

5     if (flags)  // 第二个参数表示的是flag

6         *flags = gpiospec->args[1];

7  // 第一个参数表示的是gpio号

8     return gpiospec->args[0];

9 }


从上面的分析中我们知道了如下几点:


1. 每一个bank(如gpx3)都对应一个gpio_chip和gpio_device


2. 这个bank下的每一个gpio都会对应一个唯一的gpio_desc结构体,这些结构提的首地址存放在gpio_device的desc中


3. 上面的gpio_device会加入到全局gpio_devices链表中


4. gpio_chip的of_gpio_n_cells被赋值为2,表示引用一个gpio资源需要两个参数,负责解析这两个参数函数以的of_xlate函数为of_gpio_simple_xlate,其中第一个参数表示gpio号(在对应的bank中),第二个表示flag


这里还是先把设备树中涉及到的节点列在这里:


 1 / {

 2     interrupt-parent = <&gic>;

 3     #address-cells = <0x1>;

 4     #size-cells = <0x1>;

 5     compatible = "friendlyarm,tiny4412", "samsung,exynos4412", "samsung,exynos4";

 6     model = "FriendlyARM TINY4412 board based on Exynos4412";

 7     aliases {

 8         pinctrl1 = "/pinctrl@11000000";

 9     };

10     gic: interrupt-controller@10490000 {

11         compatible = "arm,cortex-a9-gic";

12         #interrupt-cells = <0x3>;

13         interrupt-controller;

14         reg = <0x10490000 0x10000>, <0x10480000 0x10000>;

15         cpu-offset = <0x4000>;

16     };

17     pinctrl@11000000 {

18         compatible = "samsung,exynos4x12-pinctrl";

19         reg = <0x11000000 0x1000>;

20         interrupts = <0x0 0x2e 0x0>;

21         gpx3: gpx3 {

22             gpio-controller;

23             #gpio-cells = <0x2>;

24             interrupt-controller;

25             #interrupt-cells = <0x2>;

26         };

27         wakeup-interrupt-controller {

28             compatible = "samsung,exynos4210-wakeup-eint";

29             interrupt-parent = <0x1>;

30             interrupts = <0x0 0x20 0x0>;

31         };

32     };

33     interrupt_xeint26: interrupt_xeint26 {

34             compatible = "tiny4412,interrupt_xeint26";

35             int-gpio = <&gpx3 2 GPIO_ACTIVE_HIGH>;

36     };

37 };


上面的节点interrupt_xeint26中引用了gpx3_2,而且在驱动中打算将这个gpio当作中断引脚来使用。


下面是对应的驱动程序:


  1 #include

  2 #include

  3 #include

  4 #include

  5 #include

  6 #include

  7 #include

  8 typedef struct 

  9 {

 10     int gpio;

 11     int irq;

 12     char name[20];

 13 }xeint26_data_t;

 14 static irqreturn_t xeint26_isr(int irq, void *dev_id)

 15 {

 16     xeint26_data_t *data = dev_id;

 17     printk("%s enter, %s: gpio:%d, irq: %dn", __func__, data->name, data->gpio, data->irq);

 18     return IRQ_HANDLED;

 19 }

 20 static int xeint26_probe(struct platform_device *pdev) {

 21     struct device *dev = &pdev->dev;

 22     int irq_gpio = -1;

 23     int irq = -1;

 24     int ret = 0;

 25     int i = 0;

 26     xeint26_data_t *data = NULL;

 27     printk("%s enter.n", __func__);

 28     if (!dev->of_node) {

 29         dev_err(dev, "no platform data.n");

 30         goto err1;

 31     }

 32     data = devm_kmalloc(dev, sizeof(*data)*1, GFP_KERNEL);

 33     if (!data) {

 34         dev_err(dev, "no memory.n");

 35         goto err0;

 36     }

 37     for (i = 0; i < 1; i++) {

 38         sprintf(data[i].name, "int-gpio");

 39         irq_gpio = of_get_named_gpio(dev->of_node,

 40             data[i].name, 0);

 41         if (irq_gpio < 0) {

 42             dev_err(dev, "Looking up %s property in node %s failed %dn",

 43                 data[i].name, dev->of_node->full_name, irq_gpio);

 44             goto err1;

 45         }

[1] [2] [3]
关键字:tiny4412  Linux  內核移植  中断 引用地址:基于tiny4412的Linux內核移植 --- 实例学习中断背后的知识(2)

上一篇:Linux内存管理学习1 —— head.S中的段页表的建立
下一篇:基于tiny4412的Linux内核移植(支持device tree)(一)

小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved