kernel - gpio子系统

Posted qzhang1535

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kernel - gpio子系统相关的知识,希望对你有一定的参考价值。

gpio_chip注册

int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *chip,
               void *data)              

    ... 
    ret = gpiochip_add_data(chip, data);
    if (ret < 0) 
        devres_free(ptr);
        return ret;
     
    ...

EXPORT_SYMBOL_GPL(devm_gpiochip_add_data);
  • 实际调用gpiochip_add_data
int gpiochip_add_data(struct gpio_chip *chip, void *data)

    ......

    /*
     * First: allocate and populate the internal stat container, and
     * set up the struct device.
     */
    gdev = kzalloc(sizeof(*gdev), GFP_KERNEL);
    if (!gdev)
        return -ENOMEM;
    gdev->dev.bus = &gpio_bus_type;
    gdev->chip = chip;
    chip->gpiodev = gdev;
    if (chip->parent) 
        gdev->dev.parent = chip->parent;
        gdev->dev.of_node = chip->parent->of_node;
    

    ......
    
    status = gpiodev_add_to_list(gdev);
    if (status) 
        spin_unlock_irqrestore(&gpio_lock, flags);
        goto err_free_label;
    

    ......

    status = of_gpiochip_add(chip);
   
    ......
  • 创建并初始化gdev,然后调用gpiodev_add_to_list注册到链表
  • 调用of_gpiochip_add,初始化设备树相关数据,比如of_xlate函数指针

通过设备树获取gpio流程

int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
                int index, enum of_gpio_flags *flags)                                                                                                           

    struct gpio_desc *desc;

    desc = of_get_named_gpiod_flags(np, list_name, index, flags);                                                                                               

    if (IS_ERR(desc))
        return PTR_ERR(desc);
    else
        return desc_to_gpio(desc);
  • 通过of_get_named_gpiod_flags得到gpio_desc
  • 调用desc_to_gpio得到gpio编号
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
             const char *propname, int index, enum of_gpio_flags *flags)

    struct of_phandle_args gpiospec;
    struct gpio_chip *chip;
    struct gpio_desc *desc;
    int ret;

    ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
                     &gpiospec);
    if (ret) 
        pr_debug("%s: can't parse '%s' property of node '%pOF[%d]'\n",
            __func__, propname, np, index);
        return ERR_PTR(ret);
      

    chip = of_find_gpiochip_by_xlate(&gpiospec);
    if (!chip) 
        desc = ERR_PTR(-EPROBE_DEFER);
        goto out;
      

    desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, flags);                                                                                                
    if (IS_ERR(desc))
        goto out;

    pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n",
         __func__, propname, np, index,
         PTR_ERR_OR_ZERO(desc));

out:   
    of_node_put(gpiospec.np);

    return desc;
  • 调用of_parse_phandle_with_args获取gpio相关参数gpiospec
  • 根据gpiospec,调用of_find_gpiochip_by_xlate得到gpiochip
  • 能过调用of_xlate_and_get_gpiod_flags得到gpio_desc
static int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, void *data)

    struct of_phandle_args *gpiospec = data;

    return chip->gpiodev->dev.of_node == gpiospec->np &&
                chip->of_xlate &&
                chip->of_xlate(chip, gpiospec, NULL) >= 0;


static struct gpio_chip *of_find_gpiochip_by_xlate(
                    struct of_phandle_args *gpiospec)

    return gpiochip_find(gpiospec, of_gpiochip_match_node_and_xlate);


struct gpio_chip *gpiochip_find(void *data,
                int (*match)(struct gpio_chip *chip,
                         void *data))

    struct gpio_device *gdev;
    struct gpio_chip *chip = NULL;
    unsigned long flags;

    spin_lock_irqsave(&gpio_lock, flags);
    list_for_each_entry(gdev, &gpio_devices, list)
        if (gdev->chip && match(gdev->chip, data)) 
            chip = gdev->chip;
            break;
        

    spin_unlock_irqrestore(&gpio_lock, flags);

    return chip;
  • of_find_gpiochip_by_xlate调用gpiochip_find,传入参数of_gpiochip_match_node_and_xlate
  • gpiochip_find函数中遍历gpio_devices,根据传入的匹配配置of_gpiochip_match_node_and_xlate,得到对应的chip
  • of_gpiochip_match_node_and_xlate函数中调用chip->of_xlate函数指针,该指针在of_gpiochip_add赋值为of_gpio_simple_xlate
int of_gpio_simple_xlate(struct gpio_chip *gc,        
             const struct of_phandle_args *gpiospec, u32 *flags)                                                                                                

    ......

    if (flags)
        *flags = gpiospec->args[1];

    return gpiospec->args[0];
  • 该函数会得到设备树中指定的gpio flag
  • 函数返回值为gpio的编号
static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
                    struct of_phandle_args *gpiospec,
                    enum of_gpio_flags *flags)

    int ret;

    if (chip->of_gpio_n_cells != gpiospec->args_count)
        return ERR_PTR(-EINVAL);

    ret = chip->of_xlate(chip, gpiospec, flags);
    if (ret < 0)
        return ERR_PTR(ret);

    return gpiochip_get_desc(chip, ret);
  • 通过调用chip->of_xlate得到硬件编号
  • 调用函数gpiochip_get_desc根据chip和硬件编号得到gpio管脚号

以上是关于kernel - gpio子系统的主要内容,如果未能解决你的问题,请参考以下文章

sys目录下常用文件汇总

i.MX6ULL驱动开发 | 08 -基于pinctrl子系统和gpio子系统点亮LED

i.MX6ULL驱动开发 | 08 -基于pinctrl子系统和gpio子系统点亮LED

Linux下查看GPIO状态——/sys/kernel/debug/gpio

全志 Linux 系统启动优化 启动优化速度方式 优化启动流程 优化uboot 优化kernel等

全志 Linux 系统启动优化 启动优化速度方式 优化启动流程 优化uboot 优化kernel等