概述
/** * 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 linesn"); 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 registern", __func__, gdev->base, gdev->base + gdev->ngpio - 1, chip->label ? : "generic"); kfree(gdev); return status; }
最后
以上就是自由香菇为你收集整理的Linux 内核设备驱动之GPIO驱动之GPIO gpiochip注册的全部内容,希望文章能够帮你解决Linux 内核设备驱动之GPIO驱动之GPIO gpiochip注册所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复