From patchwork Mon Apr 13 11:05:20 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Fuzzey X-Patchwork-Id: 460758 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id EE2CD1402F5 for ; Mon, 13 Apr 2015 21:48:54 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753887AbbDMLsx (ORCPT ); Mon, 13 Apr 2015 07:48:53 -0400 Received: from ip83.parkeon.com ([213.152.31.83]:42735 "EHLO mta2.parkeon.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752553AbbDMLsw (ORCPT ); Mon, 13 Apr 2015 07:48:52 -0400 Received: from time001.besancon.parkeon.com ([10.32.16.23] helo=mail.besancon.parkeon.com) by mta2.parkeon.com with esmtp (Exim 4.82) (envelope-from ) id 1YhcB4-0005BG-4m; Mon, 13 Apr 2015 13:05:18 +0200 Received: from [10.32.51.184] (port=59607 helo=[127.0.0.1]) by mail.besancon.parkeon.com with esmtp (Exim 4.71) (envelope-from ) id 1YhcB6-0000Pi-16; Mon, 13 Apr 2015 13:05:20 +0200 Subject: [PATCH 2/2] gpio: add driver to export DT configured GPIOs to userspace To: Alexandre Courbot , Linus Walleij , Rob Herring From: Martin Fuzzey Cc: linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org Date: Mon, 13 Apr 2015 13:05:20 +0200 Message-ID: <20150413110519.9681.95469.stgit@localhost> In-Reply-To: <20150413110515.9681.58848.stgit@localhost> References: <20150413110515.9681.58848.stgit@localhost> User-Agent: StGit/0.16 MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "srv025-bes.parkeon.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Selected GPIOs (defined as child nodes in DT) may be exported as symlinks to user space (using gpiod_export_link()) The advantages of this are: * Userspace no longer needs to know the GPIO number (which may vary with other hardware and with kernel version due to dynamic allocation) * Userspace can be prevented from changing the direction if that does not make sense from a hardware perspective. [...] Content analysis details: (-2.0 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 URIBL_BLOCKED ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [URIs: parkeon.com] -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP -1.0 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain X-Spam-Score: -2.0 (--) Sender: linux-gpio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org Selected GPIOs (defined as child nodes in DT) may be exported as symlinks to user space (using gpiod_export_link()) The advantages of this are: * Userspace no longer needs to know the GPIO number (which may vary with other hardware and with kernel version due to dynamic allocation) * Userspace can be prevented from changing the direction if that does not make sense from a hardware perspective. Signed-off-by: Martin Fuzzey --- drivers/gpio/Kconfig | 9 ++ drivers/gpio/Makefile | 1 drivers/gpio/gpio-exporter.c | 171 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 drivers/gpio/gpio-exporter.c -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 633ec21..682fce2 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -110,6 +110,15 @@ config GPIO_DA9055 config GPIO_MAX730X tristate +config GPIO_EXPORTER + tristate "Userspace exporter driver" + depends on OF_GPIO && GPIO_SYSFS + help + This enables a GPIO consumer which exports some GPIOs to userspace. + The GPIOs to be exported are defined in the device tree. + The exported GPIOs are represented as symbolic links in sysfs, + relieving usespace of the burden of knowing the GPIO number to export + comment "Memory mapped GPIO drivers:" config GPIO_74XX_MMIO diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 81755f1..bb665c5 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o # Device drivers. Generally keep list sorted alphabetically +obj-$(CONFIG_GPIO_EXPORTER) += gpio-exporter.o obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o diff --git a/drivers/gpio/gpio-exporter.c b/drivers/gpio/gpio-exporter.c new file mode 100644 index 0000000..72cdcf0 --- /dev/null +++ b/drivers/gpio/gpio-exporter.c @@ -0,0 +1,171 @@ +/* + * A driver that allows some gpios to be exported to userspace + * using friendly names. + * + * This allows the gpios to be exported to be configured in the device tree + * and frees userspace from having to know unstable gpio numbers. + * + * Copyright 2015 Parkeon + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +struct gpio_exporter_gpio { + const char *name; + struct gpio_desc *desc; +}; + +struct gpio_exporter_data { + struct device *dev; + int num_gpios; + struct gpio_exporter_gpio *gpios; +}; + +static int gpio_exporter_do_one(struct gpio_exporter_data *data, + struct fwnode_handle *child) +{ + struct device_node *np = of_node(child); + const char *name = np->name; + const char *config; + struct gpio_desc *desc; + int ret; + + desc = devm_get_gpiod_from_child(data->dev, child); + if (IS_ERR(desc)) { + ret = PTR_ERR(desc); + goto failed_get; + } + + if (of_property_read_bool(np, "output")) { + u32 state = 0; + + of_property_read_u32(np, "initial-state", &state); + ret = gpiod_direction_output(desc, state); + } else { + ret = gpiod_direction_input(desc); + } + if (ret) + goto failed_setdir; + + ret = gpiod_export(desc, + of_property_read_bool(np, "allow-direction-change")); + if (ret) + goto failed_export; + + ret = gpiod_export_link(data->dev, name, desc); + if (ret) + goto failed_link; + + data->gpios[data->num_gpios].name = name; + data->gpios[data->num_gpios].desc = desc; + data->num_gpios++; + + dev_info(data->dev, + "Exported gpio%d as '%s'\n", desc_to_gpio(desc), name); + + return 0; + +failed_link: + gpiod_unexport(desc); + +failed_export: +failed_setdir: +failed_get: + dev_err(data->dev, "Failed to export gpio '%s': %d\n", name, ret); + + return ret; +} + +static void gpio_exporter_cleanup(struct gpio_exporter_data *data) +{ + int i; + + for (i = 0; i < data->num_gpios; i++) { + sysfs_remove_link(&data->dev->kobj, data->gpios[i].name); + gpiod_unexport(data->gpios[i].desc); + } +} + +static int gpio_exporter_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct fwnode_handle *child; + int num_gpios; + int ret; + struct gpio_exporter_data *data; + + if (!dev->of_node) + return -ENODEV; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = dev; + dev_set_drvdata(dev, data); + + num_gpios = device_get_child_node_count(dev); + data->gpios = devm_kzalloc(dev, num_gpios * sizeof(*data->gpios), + GFP_KERNEL); + if (!data->gpios) + return -ENOMEM; + + device_for_each_child_node(dev, child) { + ret = gpio_exporter_do_one(data, child); + if (ret) + goto out_cleanup; + } + + dev_info(dev, "exported %d gpios\n", data->num_gpios); + + return 0; + +out_cleanup: + gpio_exporter_cleanup(data); + + return ret; +} + +static int gpio_exporter_remove(struct platform_device *pdev) +{ + struct gpio_exporter_data *data = platform_get_drvdata(pdev); + + gpio_exporter_cleanup(data); + + return 0; +} + +static const struct of_device_id gpio_exporter_dt_ids[] = { + { .compatible = "linux,gpio-exporter", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, gpio_exporter_dt_ids); + +static struct platform_driver gpio_exporter_driver = { + .driver = { + .name = "gpio-exporter", + .of_match_table = gpio_exporter_dt_ids, + }, + .probe = gpio_exporter_probe, + .remove = gpio_exporter_remove, +}; + +module_platform_driver(gpio_exporter_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Martin Fuzzey "); +MODULE_DESCRIPTION("Userspace GPIO exporter"); +MODULE_ALIAS("platform:gpio-exporter");