Chinaunix首页 | 论坛 | 博客
  • 博客访问: 62399
  • 博文数量: 14
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2016-12-09 09:36
个人简介

人生最精彩的不是实现梦想的瞬间,而是坚持梦想的过程!

文章分类
文章存档

2018年(4)

2017年(7)

2016年(3)

我的朋友

分类: LINUX

2017-05-26 17:29:00

原文地址:Linux GPIO内核驱动框架 作者:芸锺鹤

    GPIO开发是Linux开发不可或缺的重要部分,它是ARM开发中最普遍也是最基础的知识。
    在ARM开发过程中,引脚复用严重,导致问题的原因软硬件并存,因此在实际的开发中常常需要使用GPIO来探测所配置的路径或设备是否畅通,可用,以此来判定是设备的问题,还是驱动的问题或是程序的问题。
    在Linux内核中提供一个标准的GPIO LIB框架,它位于:
    --<*>Device Drivers
        --<*>GPIO Support
            --
    GPIO Support选项的选入,内核会将标准GPIO库进行编译。标准GPIO库的源码位于内核中的如下位置:
    /driver/gpio/gpiolib.c

    在该文件中,提供如下的接口函数用于配置和操作GPIO:
    int gpio_request(unsigned gpio, const char *label); //获取GPIO Pin的使用权,并为该Pin命名为label。

    void gpio_free(unsigned gpio);                     //释放GPIO Pin的使用权。

    int gpio_direction_input(unsigned gpio);            //设置GPIO Pin为输入模式。

    int gpio_direction_output(unsigned gpio, int value);//设置GPIO Pin为输出模式,并指定输出值value。

    int gpio_get_value(unsigned gpio);                  //获得 GPIO Pin 上的电平。

    void gpio_set_value(unsigned gpio, int value);      //设置 GPIO Pin 上的电平。

    int gpio_to_irq(unsigned gpio);                     //通过获得GPIO Pin 对应的 irq number。


    对于上述函数的gpio参数的计算方式为: GPIOx_n-->gpio=x*32+n

上面主要是对接口的介绍,下面我们来对源码进行分析,分析源码从什么地方开始呢?就从第一个调用的函数开始吧!
Function1:int gpio_request(unsigned gpio,const char *label):
Note: 该函数调用可能会失败,因此必须检测其返回值。

点击(此处)折叠或打开

  1. int gpio_request(unsigned gpio, const char *label)
  2. {
  3.     struct gpio_desc    *desc;       //gpio pin结构体指针,参见下面相关数据结构描述
  4.     struct gpio_chip    *chip;       //gpio pin controler结构体指针,参见下面相关数据结构描述
  5.     int   status = -EINVAL;
  6.     unsigned long        flags;

  7.     spin_lock_irqsave(&gpio_lock, flags);

  8.     if (!gpio_is_valid(gpio))            //检测argument gpio的合法性。
  9.         goto done;
  10.     desc = &gpio_desc[gpio];             //从gpio数组gpio_desc从获取对应的Pin结构体。
  11.     chip = desc->chip;                   //获取gpio pin的控制器
  12.     if (chip == NULL)
  13.         goto done;

  14.     if (!try_module_get(chip->owner))
  15.         goto done;

  16.     /* NOTE: gpio_request() can be called in early boot,
  17.      * before IRQs are enabled, for non-sleeping (SOC) GPIOs.
  18.      */

  19.     if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
  20.         desc_set_label(desc, label ? : "?");
  21.         status = 0;
  22.     } else {
  23.         status = -EBUSY;
  24.         module_put(chip->owner);
  25.         goto done;
  26.     }

  27.     if (chip->request) {
  28.         /* chip->request may sleep */
  29.         spin_unlock_irqrestore(&gpio_lock, flags);
  30.         status = chip->request(chip, gpio - chip->base);
  31.         spin_lock_irqsave(&gpio_lock, flags);

  32.         if (status < 0) {
  33.             desc_set_label(desc, NULL);
  34.             module_put(chip->owner);
  35.             clear_bit(FLAG_REQUESTED, &desc->flags);
  36.         }
  37.     }

  38. done:
  39.     if (status)
  40.         pr_debug("gpio_request: gpio-%d (%s) status %d\n",gpio, label ? : "?", status);
  41.     spin_unlock_irqrestore(&gpio_lock, flags);
  42.     return status;
  43. }
  44. EXPORT_SYMBOL_GPL(gpio_request);
Function1相关数据结构:
struct gpio_desc    *desc (driver/gpio/gpiolib.c)        每一个GPIO Pin对应一个gpio_desc.

点击(此处)折叠或打开

  1. struct gpio_desc {
  2.     struct gpio_chip    *chip;     //控制器指针
  3.     unsigned long        flags;
  4. /* flag symbols are bit numbers */
  5. #define FLAG_REQUESTED    0
  6. #define FLAG_IS_OUT       1
  7. #define FLAG_RESERVED     2
  8. #define FLAG_EXPORT       3    /* protected by sysfs_lock */
  9. #define FLAG_SYSFS        4    /* exported via /sys/class/gpio/control */
  10. #define FLAG_TRIG_FALL    5    /* trigger on falling edge */
  11. #define FLAG_TRIG_RISE    6    /* trigger on rising edge */
  12. #define FLAG_ACTIVE_LOW   7    /* sysfs value has active low */

  13. #define ID_SHIFT         16    /* add new flags before this one */

  14. #define GPIO_FLAGS_MASK      ((1 << ID_SHIFT) - 1)
  15. #define GPIO_TRIGGER_MASK    (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))

  16. #ifdef CONFIG_DEBUG_FS
  17.     const char        *label;
  18. #endif
  19. };

  20. static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];       
  21. /*gpio pin数组,包含控制器所有的gpio pin,ARCH_NR_GPIOS通常定义在板级文件中(需要自己根据板子进行修改):
  22.  *  arch/arm/mach-***/include/**/gpio.h
  23.  *或
  24.  *  arch/arm/plat-**/include/**/gpio.h
  25.  * 若没有定义系统则会使用定义在include/asm-generic/gpio.h中的默认值:
  26.  *  #ifndef ARCH_NR_GPIOS
  27.  *  #define ARCH_NR_GPIOS        256
  28.  *  #endif
  29.  */
     
     
 struct gpio_chip    *chip(include/linux/gpio.h----->CONFIG_GENERIC_GPIO---->include/asm-generic/gpio.h)    gpio_chip代表GPIO控制器。

点击(此处)折叠或打开

  1. /*
  2.  * struct gpio_chip - abstract a GPIO controller
  3.  * A gpio_chip can help platforms abstract various sources of GPIOs so they can all be accessed through a common programing
  4.  * interface.Example sources would be SOC controllers, FPGAs, multifunctio chips, dedicated GPIO expanders, and so on.
  5.  *
  6.  * Each chip controls a number of signals, identified in method calls by "offset" values in the range 0..(@ngpio - 1). When
  7.  * those signals are referenced through calls like gpio_get_value(gpio), the offset is calculated by subtracting @base from
  8.  * the gpio number.
  9.  */
  10. struct gpio_chip {
  11.     const char        *label;                  //@label: for diagnostics
  12.     struct device     *dev;                    //@dev: optional device providing the GPIOs
  13.     struct module     *owner;                  //@owner: helps prevent removal of modules exporting active GPIOs

  14.    //@request: optional hook for chip-specific activation, such as enabling module power and clock; may sleep
  15.     int   (*request)(struct gpio_chip *chip, unsigned offset); 
  16.    
  17.     //@free: optional hook for chip-specific deactivation, such as  disabling module power and clock; may sleep
  18.     void  (*free)(struct gpio_chip *chip, unsigned offset);    

  19.     //@direction_input: configures signal "offset" as input, or returns error
  20.     int   (*direction_input)(struct gpio_chip *chip, unsigned offset); 

  21.     //@get: returns value for signal "offset"; for output signals this returns either the value actually sensed, or zero
  22.     int   (*get)(struct gpio_chip *chip, unsigned offset);   
  23.    
  24.     //@direction_output: configures signal "offset" as output, or returns error
  25.     int   (*direction_output)(struct gpio_chip *chip, unsigned offset, int value);

  26.     int   (*set_debounce)(struct gpio_chip *chip, unsigned offset, unsigned debounce);
  27.    
  28.     //@set: assigns output value for signal "offset"
  29.     void  (*set)(struct gpio_chip *chip, unsigned offset, int value);

  30.     // @to_irq: optional hook supporting non-static gpio_to_irq() mappings;implementation may not sleep
  31.     int   (*to_irq)(struct gpio_chip *chip,unsigned offset);

  32.     //@dbg_show: optional routine to show contents in debugfs; default code will be used when this is omitted, but custom code can
  33.     //           show extra state (such as pullup/pulldown configuration).
  34.     void  (*dbg_show)(struct seq_file *s,struct gpio_chip *chip);
  35.    
  36.     //@base: identifies the first GPIO number handled by this chip; or, if negative during registration, requests dynamic ID allocation.
  37.     int    base;
  38.     
  39.     //@ngpio: the number of GPIOs handled by this controller; the last GPIO handled is (base + ngpio - 1).
  40.     u16    ngpio;

  41.     //@names: if set, must be an array of strings to use as alternative names for the GPIOs in this chip. Any entry in the array may be
  42.     //        NULL if there is no alias for the GPIO, however the array must be @ngpio entries long. A name can include a single printk
  43.     //        format specifier for an unsigned int. It is substituted by the actual number of the gpio.
  44.     const char *const *names;
  45.    
  46.     //@can_sleep: flag must be set iff get()/set() methods sleep, as they must while accessing GPIO expander chips over I2C or SPI
  47.     unsigned      can_sleep:1;
  48.     unsigned      exported:1;

  49. #if defined(CONFIG_OF_GPIO)
  50.     /*
  51.      * If CONFIG_OF is enabled, then all GPIO controllers described in the
  52.      * device tree automatically may have an OF translation
  53.      */
  54.     struct device_node *of_node;
  55.     int of_gpio_n_cells;
  56.     int (*of_xlate)(struct gpio_chip *gc, struct device_node *np,
  57.     const void *gpio_spec, u32 *flags);
  58. #endif
  59. };

 上述探讨的过程中一直存在一个问题,那就是开发板上的gpio是如何通过gpio框架注册到内核中,供驱动调用的呢?
 一般在内核的板级目录中存在对应的gpio.c文件,里面完成了将板级gpio设备到内核的映射的初始化工作,对应文件位置通常如下:
/arch/arm/mach-***/gpio.c

这里以TI的am33xx系列的板子为例进行探究:

/arch/arm/mach-omap2/gpio.c

点击(此处)折叠或打开

  1. static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
  2. {
  3.     struct platform_device *pdev;
  4.     struct omap_gpio_platform_data *pdata;
  5.     struct omap_gpio_dev_attr *dev_attr;
  6.     char *name = "omap_gpio";
  7.     int id;

  8.     /*
  9.      * extract the device id from name field available in the hwmod database and use the same for constructing ids for gpio devices.
  10.      * CAUTION: Make sure the name in the hwmod database does not change. If changed, make corresponding change here or make use of
  11.      * static variable mechanism to handle this.
  12.      */
  13.     sscanf(oh->name, "gpio%d", &id);

  14.     pdata = kzalloc(sizeof(struct omap_gpio_platform_data), GFP_KERNEL);
  15.     if (!pdata) {
  16.         pr_err("gpio%d: Memory allocation failed\n", id);
  17.         return -ENOMEM;
  18.     }

  19.     dev_attr = (struct omap_gpio_dev_attr *)oh->dev_attr;
  20.     pdata->bank_width = dev_attr->bank_width;
  21.     pdata->dbck_flag = dev_attr->dbck_flag;
  22.     pdata->virtual_irq_start = IH_GPIO_BASE + 32 * (id - 1);

  23.     pdata->regs = kzalloc(sizeof(struct omap_gpio_reg_offs), GFP_KERNEL);
  24.     if (!pdata) {
  25.         pr_err("gpio%d: Memory allocation failed\n", id);
  26.         return -ENOMEM;
  27.     }

  28.     switch (oh->class->rev) {
  29.     case 0:
  30.     case 1:
  31.         pdata->bank_type = METHOD_GPIO_24XX;
  32.         pdata->regs->revision = OMAP24XX_GPIO_REVISION;
  33.         pdata->regs->direction = OMAP24XX_GPIO_OE;
  34.         pdata->regs->datain = OMAP24XX_GPIO_DATAIN;
  35.         pdata->regs->dataout = OMAP24XX_GPIO_DATAOUT;
  36.         pdata->regs->set_dataout = OMAP24XX_GPIO_SETDATAOUT;
  37.         pdata->regs->clr_dataout = OMAP24XX_GPIO_CLEARDATAOUT;
  38.         pdata->regs->irqstatus = OMAP24XX_GPIO_IRQSTATUS1;
  39.         pdata->regs->irqstatus2 = OMAP24XX_GPIO_IRQSTATUS2;
  40.         pdata->regs->irqenable = OMAP24XX_GPIO_IRQENABLE1;
  41.         pdata->regs->set_irqenable = OMAP24XX_GPIO_SETIRQENABLE1;
  42.         pdata->regs->clr_irqenable = OMAP24XX_GPIO_CLEARIRQENABLE1;
  43.         pdata->regs->debounce = OMAP24XX_GPIO_DEBOUNCE_VAL;
  44.         pdata->regs->debounce_en = OMAP24XX_GPIO_DEBOUNCE_EN;
  45.         break;
  46.     case 2:
  47.         pdata->bank_type = METHOD_GPIO_44XX;
  48.         pdata->regs->revision = OMAP4_GPIO_REVISION;
  49.         pdata->regs->direction = OMAP4_GPIO_OE;
  50.         pdata->regs->datain = OMAP4_GPIO_DATAIN;
  51.         pdata->regs->dataout = OMAP4_GPIO_DATAOUT;
  52.         pdata->regs->set_dataout = OMAP4_GPIO_SETDATAOUT;
  53.         pdata->regs->clr_dataout = OMAP4_GPIO_CLEARDATAOUT;
  54.         pdata->regs->irqstatus = OMAP4_GPIO_IRQSTATUS0;
  55.         pdata->regs->irqstatus2 = OMAP4_GPIO_IRQSTATUS1;
  56.         pdata->regs->irqenable = OMAP4_GPIO_IRQSTATUSSET0;
  57.         pdata->regs->set_irqenable = OMAP4_GPIO_IRQSTATUSSET0;
  58.         pdata->regs->clr_irqenable = OMAP4_GPIO_IRQSTATUSCLR0;
  59.         pdata->regs->debounce = OMAP4_GPIO_DEBOUNCINGTIME;
  60.         pdata->regs->debounce_en = OMAP4_GPIO_DEBOUNCENABLE;
  61.         break;
  62.     default:
  63.         WARN(1, "Invalid gpio bank_type\n");
  64.         kfree(pdata);
  65.         return -EINVAL;
  66.     }

  67.     pdev = omap_device_build(name, id - 1, oh, pdata,
  68.                 sizeof(*pdata),    NULL, 0, false);
  69.     kfree(pdata);

  70.     if (IS_ERR(pdev)) {
  71.         WARN(1, "Can't build omap_device for %s:%s.\n",
  72.                     name, oh->name);
  73.         return PTR_ERR(pdev);
  74.     }

  75.     omap_device_disable_idle_on_suspend(pdev);

  76.     gpio_bank_count++;
  77.     return 0;
  78. }

  79. /*
  80.  * gpio_init needs to be done before
  81.  * machine_init functions access gpio APIs.
  82.  * Hence gpio_init is a postcore_initcall.
  83.  */
  84. static int __init omap2_gpio_init(void)
  85. {
  86.     return omap_hwmod_for_each_by_class("gpio", omap2_gpio_dev_init,NULL);
  87. }
  88. postcore_initcall(omap2_gpio_init);

继续追踪代码:
arch/arm/mach-omap2/omap_hwmod.c

点击(此处)折叠或打开

  1. /**
  2.  * omap_hwmod_for_each_by_class - call @fn for each hwmod of class @classname
  3.  * @classname: struct omap_hwmod_class name to search for
  4.  * @fn: callback function pointer to call for each hwmod in class @classname
  5.  * @user: arbitrary context data to pass to the callback function
  6.  *
  7.  * For each omap_hwmod of class @classname, call @fn.
  8.  * If the callback function returns something other than
  9.  * zero, the iterator is terminated, and the callback function's return
  10.  * value is passed back to the caller. Returns 0 upon success, -EINVAL
  11.  * if @classname or @fn are NULL, or passes back the error code from @fn.
  12.  */
  13. int omap_hwmod_for_each_by_class(const char *classname,int (*fn)(struct omap_hwmod *oh,void *user), void *user)
  14. {
  15.     struct omap_hwmod *temp_oh;
  16.     int ret = 0;

  17.     if (!classname || !fn)
  18.         return -EINVAL;

  19.     pr_debug("omap_hwmod: %s: looking for modules of class %s\n",
  20.          __func__, classname);

  21.     list_for_each_entry(temp_oh, &omap_hwmod_list, node) {
  22.         if (!strcmp(temp_oh->class->name, classname)) {
  23.             pr_debug("omap_hwmod: %s: %s: calling callback fn\n",
  24.                  __func__, temp_oh->name);
  25.             ret = (*fn)(temp_oh, user);
  26.             if (ret)
  27.                 break;
  28.         }
  29.     }

  30.     if (ret)
  31.         pr_debug("omap_hwmod: %s: iterator terminated early: %d\n",
  32.              __func__, ret);

  33.     return ret;
  34. }
上面最终回归到对链表进行操作,那么链表上的这些节点又定义在哪里?链表又是何时建立的呢?
在板级目录下,还存在一个omap_hwmod_33xx_data.c文件,里面定义了该系列开发板的各个模块。
                                                                                                                             *****未完待续















阅读(2322) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~