博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux 内核设备驱动之GPIO驱动之GPIO gpiochip注册
阅读量:4153 次
发布时间:2019-05-25

本文共 5502 字,大约阅读时间需要 18 分钟。

 
/** * gpiochip_add_data() - register a gpio_chip * @chip: the chip to register, with chip->base initialized * Context: potentially before irqs will work * * Returns a negative errno if the chip can't be registered, such as * because the chip->base is invalid or already associated with a * different chip.  Otherwise it returns zero as a success code. * * When gpiochip_add_data() is called very early during boot, so that GPIOs * can be freely used, the chip->parent device must be registered before * the gpio framework's arch_initcall().  Otherwise sysfs initialization * for GPIOs will fail rudely. * * gpiochip_add_data() must only be called after gpiolib initialization, * ie after core_initcall(). * * If chip->base is negative, this requests dynamic assignment of * a range of valid GPIOs. */int gpiochip_add_data(struct gpio_chip *chip, void *data){ unsigned long flags; int  status = 0; unsigned i; int  base = chip->base; struct gpio_device *gdev;  /*  * 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; } #ifdef CONFIG_OF_GPIO /* If the gpiochip has an assigned OF node this takes precedence */ if (chip->of_node)  gdev->dev.of_node = chip->of_node;#endif  gdev->id = ida_simple_get(&gpio_ida, 0, 0, GFP_KERNEL); if (gdev->id < 0) {  status = gdev->id;  goto err_free_gdev; } dev_set_name(&gdev->dev, "gpiochip%d", gdev->id); device_initialize(&gdev->dev); dev_set_drvdata(&gdev->dev, gdev); if (chip->parent && chip->parent->driver)  gdev->owner = chip->parent->driver->owner; else if (chip->owner)  /* TODO: remove chip->owner */  gdev->owner = chip->owner; else  gdev->owner = THIS_MODULE;  gdev->descs = kcalloc(chip->ngpio, sizeof(gdev->descs[0]), GFP_KERNEL); if (!gdev->descs) {  status = -ENOMEM;  goto err_free_gdev; }  if (chip->ngpio == 0) {  chip_err(chip, "tried to insert a GPIO chip with zero lines\n");  status = -EINVAL;  goto err_free_descs; }  if (chip->label)  gdev->label = kstrdup(chip->label, GFP_KERNEL); else  gdev->label = kstrdup("unknown", GFP_KERNEL); if (!gdev->label) {  status = -ENOMEM;  goto err_free_descs; }  gdev->ngpio = chip->ngpio; gdev->data = data;  spin_lock_irqsave(&gpio_lock, flags);  /*  * TODO: this allocates a Linux GPIO number base in the global  * GPIO numberspace for this chip. In the long run we want to  * get *rid* of this numberspace and use only descriptors, but  * it may be a pipe dream. It will not happen before we get rid  * of the sysfs interface anyways.  */ if (base < 0) {  base = gpiochip_find_base(chip->ngpio);  if (base < 0) {   status = base;   spin_unlock_irqrestore(&gpio_lock, flags);   goto err_free_label;  }  /*   * TODO: it should not be necessary to reflect the assigned   * base outside of the GPIO subsystem. Go over drivers and   * see if anyone makes use of this, else drop this and assign   * a poison instead.   */  chip->base = base; } gdev->base = base;  status = gpiodev_add_to_list(gdev); if (status) {  spin_unlock_irqrestore(&gpio_lock, flags);  goto err_free_label; }  spin_unlock_irqrestore(&gpio_lock, flags);  for (i = 0; i < chip->ngpio; i++) {  struct gpio_desc *desc = &gdev->descs[i];   desc->gdev = gdev;  /*   * REVISIT: most hardware initializes GPIOs as inputs   * (often with pullups enabled) so power usage is   * minimized. Linux code should set the gpio direction   * first thing; but until it does, and in case   * chip->get_direction is not set, we may expose the   * wrong direction in sysfs.   */   if (chip->get_direction) {   /*    * If we have .get_direction, set up the initial    * direction flag from the hardware.    */   int dir = chip->get_direction(chip, i);    if (!dir)    set_bit(FLAG_IS_OUT, &desc->flags);  } else if (!chip->direction_input) {   /*    * If the chip lacks the .direction_input callback    * we logically assume all lines are outputs.    */   set_bit(FLAG_IS_OUT, &desc->flags);  } } #ifdef CONFIG_PINCTRL INIT_LIST_HEAD(&gdev->pin_ranges);#endif  status = gpiochip_set_desc_names(chip); if (status)  goto err_remove_from_list;  status = gpiochip_irqchip_init_valid_mask(chip); if (status)  goto err_remove_from_list;  status = of_gpiochip_add(chip); if (status)  goto err_remove_chip;  acpi_gpiochip_add(chip);  /*  * By first adding the chardev, and then adding the device,  * we get a device node entry in sysfs under  * /sys/bus/gpio/devices/gpiochipN/dev that can be used for  * coldplug of device nodes and other udev business.  * We can do this only if gpiolib has been initialized.  * Otherwise, defer until later.  */ if (gpiolib_initialized) {  status = gpiochip_setup_dev(gdev);  if (status)   goto err_remove_chip; } return 0; err_remove_chip: acpi_gpiochip_remove(chip); gpiochip_free_hogs(chip); of_gpiochip_remove(chip); gpiochip_irqchip_free_valid_mask(chip);err_remove_from_list: spin_lock_irqsave(&gpio_lock, flags); list_del(&gdev->list); spin_unlock_irqrestore(&gpio_lock, flags);err_free_label: kfree(gdev->label);err_free_descs: kfree(gdev->descs);err_free_gdev: ida_simple_remove(&gpio_ida, gdev->id); /* failures here can mean systems won't boot... */ pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__,        gdev->base, gdev->base + gdev->ngpio - 1,        chip->label ? : "generic"); kfree(gdev); return status;}
 
 
 

转载地址:http://cgqti.baihongyu.com/

你可能感兴趣的文章
Pentaho 开发: 在eclipse中构建Pentaho BI Server工程
查看>>
JSP的内置对象及方法
查看>>
android中SharedPreferences的简单例子
查看>>
android中使用TextView来显示某个网址的内容,使用<ScrollView>来生成下拉列表框
查看>>
andorid里关于wifi的分析
查看>>
Spring MVC和Struts2的比较
查看>>
Hibernate和IBatis对比
查看>>
Spring MVC 教程,快速入门,深入分析
查看>>
Android 的source (需安装 git repo)
查看>>
Commit our mod to our own repo server
查看>>
LOCAL_PRELINK_MODULE和prelink-linux-arm.map
查看>>
Simple Guide to use the gdb tool in Android environment
查看>>
Netconsole to capture the log
查看>>
Build GingerBread on 32 bit machine.
查看>>
How to make SD Card world wide writable
查看>>
Detecting Memory Leaks in Kernel
查看>>
Linux initial RAM disk (initrd) overview
查看>>
Timestamping Linux kernel printk output in dmesg for fun and profit
查看>>
There's Much More than Intel/AMD Inside
查看>>
CentOS7 安装MySQL 5.6.43
查看>>