Linux 内核设备驱动之GPIO驱动之GPIO gpiochip注册

 

/**  * 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; }

 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值