Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/435602/?format=api
{ "id": 435602, "url": "http://patchwork.ozlabs.org/api/patches/435602/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-gpio/patch/1422899085-678-2-git-send-email-bparrot@ti.com/", "project": { "id": 42, "url": "http://patchwork.ozlabs.org/api/projects/42/?format=api", "name": "Linux GPIO development", "link_name": "linux-gpio", "list_id": "linux-gpio.vger.kernel.org", "list_email": "linux-gpio@vger.kernel.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<1422899085-678-2-git-send-email-bparrot@ti.com>", "list_archive_url": null, "date": "2015-02-02T17:44:44", "name": "[v6,1/2] gpio: add GPIO hogging mechanism", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "1249a8ccff0523a53fe10adb7929134b9368a85e", "submitter": { "id": 64914, "url": "http://patchwork.ozlabs.org/api/people/64914/?format=api", "name": "Benoit Parrot", "email": "bparrot@ti.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-gpio/patch/1422899085-678-2-git-send-email-bparrot@ti.com/mbox/", "series": [], "comments": "http://patchwork.ozlabs.org/api/patches/435602/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/435602/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<linux-gpio-owner@vger.kernel.org>", "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])\n\tby ozlabs.org (Postfix) with ESMTP id B9F51140272\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 3 Feb 2015 04:45:52 +1100 (AEDT)", "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S932494AbbBBRpR (ORCPT <rfc822;incoming@patchwork.ozlabs.org>);\n\tMon, 2 Feb 2015 12:45:17 -0500", "from comal.ext.ti.com ([198.47.26.152]:46026 \"EHLO\n\tcomal.ext.ti.com\"\n\trhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP\n\tid S932452AbbBBRpN (ORCPT <rfc822;linux-gpio@vger.kernel.org>);\n\tMon, 2 Feb 2015 12:45:13 -0500", "from dflxv15.itg.ti.com ([128.247.5.124])\n\tby comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id t12Hj53N022177;\n\tMon, 2 Feb 2015 11:45:05 -0600", "from DFLE72.ent.ti.com (dfle72.ent.ti.com [128.247.5.109])\n\tby dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id t12Hj4YO009272;\n\tMon, 2 Feb 2015 11:45:04 -0600", "from dlep32.itg.ti.com (157.170.170.100) by DFLE72.ent.ti.com\n\t(128.247.5.109) with Microsoft SMTP Server id 14.3.224.2;\n\tMon, 2 Feb 2015 11:45:03 -0600", "from tct7400.am.dhcp.ti.com (ileax41-snat.itg.ti.com\n\t[10.172.224.153])\tby dlep32.itg.ti.com (8.14.3/8.13.8) with ESMTP id\n\tt12HisDB009148;\tMon, 2 Feb 2015 11:45:03 -0600" ], "From": "Benoit Parrot <bparrot@ti.com>", "To": "Linus Walleij <linus.walleij@linaro.org>", "CC": "<linux-gpio@vger.kernel.org>, <linux-kernel@vger.kernel.org>,\n\t<devicetree@vger.kernel.org>, Alexandre Courbot <gnurou@gmail.com>,\n\tMaxime Ripard <maxime.ripard@free-electrons.com>,\n\tJiri Prchal <jiri.prchal@aksignal.cz>,\n\tPantelis Antoniou <panto@antoniou-consulting.com>,\n\tBenoit Parrot <bparrot@ti.com>", "Subject": "[Patch v6 1/2] gpio: add GPIO hogging mechanism", "Date": "Mon, 2 Feb 2015 11:44:44 -0600", "Message-ID": "<1422899085-678-2-git-send-email-bparrot@ti.com>", "X-Mailer": "git-send-email 1.8.5.1", "In-Reply-To": "<1422899085-678-1-git-send-email-bparrot@ti.com>", "References": "<1422899085-678-1-git-send-email-bparrot@ti.com>", "MIME-Version": "1.0", "Content-Type": "text/plain", "Sender": "linux-gpio-owner@vger.kernel.org", "Precedence": "bulk", "List-ID": "<linux-gpio.vger.kernel.org>", "X-Mailing-List": "linux-gpio@vger.kernel.org" }, "content": "Based on Boris Brezillion's work this is a reworked patch\nof his initial GPIO hogging mechanism.\nThis patch provides a way to initially configure specific GPIO\nwhen the GPIO controller is probed.\n\nThe actual DT scanning to collect the GPIO specific data is performed\nas part of gpiochip_add().\n\nThe purpose of this is to allow specific GPIOs to be configured\nwithout any driver specific code.\nThis is particularly useful because board design are getting\nincreasingly complex and given SoC pins can now have more\nthan 10 mux values, a lot of connections are now dependent on\nexternal IO muxes to switch various modes.\n\nSpecific drivers should not necessarily need to be aware of\nwhat accounts to a specific board implementation. This board level\n\"description\" should be best kept as part of the dts file.\n\nSigned-off-by: Benoit Parrot <bparrot@ti.com>\nReviewed-by: Alexandre Courbot <acourbot@nvidia.com>\n---\n drivers/gpio/gpiolib-of.c | 111 +++++++++++++++++++++++++++++++++++++++++\n drivers/gpio/gpiolib.c | 124 +++++++++++++++++++++++++++++++++++++++-------\n drivers/gpio/gpiolib.h | 3 ++\n 3 files changed, 219 insertions(+), 19 deletions(-)", "diff": "diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c\nindex 08261f2..cfb50b4 100644\n--- a/drivers/gpio/gpiolib-of.c\n+++ b/drivers/gpio/gpiolib-of.c\n@@ -22,6 +22,7 @@\n #include <linux/of_gpio.h>\n #include <linux/pinctrl/pinctrl.h>\n #include <linux/slab.h>\n+#include <linux/gpio/machine.h>\n \n #include \"gpiolib.h\"\n \n@@ -117,6 +118,114 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name,\n EXPORT_SYMBOL(of_get_named_gpio_flags);\n \n /**\n+ * of_get_gpio_hog() - Get a GPIO hog descriptor, names and flags for GPIO API\n+ * @np:\t\tdevice node to get GPIO from\n+ * @name:\tGPIO line name\n+ * @lflags:\tgpio_lookup_flags - returned from of_find_gpio() or\n+ *\t\tof_get_gpio_hog()\n+ * @dflags:\tgpiod_flags - optional GPIO initialization flags\n+ *\n+ * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno\n+ * value on the error condition.\n+ */\n+static struct gpio_desc *of_get_gpio_hog(struct device_node *np,\n+\t\t\t\t const char **name,\n+\t\t\t\t enum gpio_lookup_flags *lflags,\n+\t\t\t\t enum gpiod_flags *dflags)\n+{\n+\tstruct device_node *chip_np;\n+\tenum of_gpio_flags xlate_flags;\n+\tstruct gpio_desc *desc;\n+\tstruct gg_data gg_data = {\n+\t\t.flags = &xlate_flags,\n+\t};\n+\tu32 tmp;\n+\tint i, ret;\n+\n+\tchip_np = np->parent;\n+\tif (!chip_np)\n+\t\treturn ERR_PTR(-EINVAL);\n+\n+\txlate_flags = 0;\n+\t*lflags = 0;\n+\t*dflags = 0;\n+\n+\tret = of_property_read_u32(chip_np, \"#gpio-cells\", &tmp);\n+\tif (ret)\n+\t\treturn ERR_PTR(ret);\n+\n+\tif (tmp > MAX_PHANDLE_ARGS)\n+\t\treturn ERR_PTR(-EINVAL);\n+\n+\tgg_data.gpiospec.args_count = tmp;\n+\tgg_data.gpiospec.np = chip_np;\n+\tfor (i = 0; i < tmp; i++) {\n+\t\tret = of_property_read_u32_index(np, \"gpios\", i,\n+\t\t\t\t\t &gg_data.gpiospec.args[i]);\n+\t\tif (ret)\n+\t\t\treturn ERR_PTR(ret);\n+\t}\n+\n+\tgpiochip_find(&gg_data, of_gpiochip_find_and_xlate);\n+\tif (!gg_data.out_gpio) {\n+\t\tif (np->parent == np)\n+\t\t\treturn ERR_PTR(-ENXIO);\n+\t\telse\n+\t\t\treturn ERR_PTR(-EINVAL);\n+\t}\n+\n+\tif (xlate_flags & OF_GPIO_ACTIVE_LOW)\n+\t\t*lflags |= GPIO_ACTIVE_LOW;\n+\n+\tif (of_property_read_bool(np, \"input\"))\n+\t\t*dflags |= GPIOD_IN;\n+\telse if (of_property_read_bool(np, \"output-low\"))\n+\t\t*dflags |= GPIOD_OUT_LOW;\n+\telse if (of_property_read_bool(np, \"output-high\"))\n+\t\t*dflags |= GPIOD_OUT_HIGH;\n+\telse {\n+\t\tpr_warn(\"GPIO line %d (%s): no hogging state specified, bailing out\\n\",\n+\t\t\tdesc_to_gpio(gg_data.out_gpio), np->name);\n+\t\treturn ERR_PTR(-EINVAL);\n+\t}\n+\n+\tif (name && of_property_read_string(np, \"line-name\", name))\n+\t\t*name = np->name;\n+\n+\tdesc = gg_data.out_gpio;\n+\n+\treturn desc;\n+}\n+\n+/**\n+ * of_gpiochip_scan_hogs - Scan gpio-controller and apply GPIO hog as requested\n+ * @chip:\tgpio chip to act on\n+ *\n+ * This is only used by of_gpiochip_add to request/set GPIO initial\n+ * configuration.\n+ */\n+static void of_gpiochip_scan_hogs(struct gpio_chip *chip)\n+{\n+\tstruct gpio_desc *desc = NULL;\n+\tstruct device_node *np;\n+\tconst char *name;\n+\tenum gpio_lookup_flags lflags;\n+\tenum gpiod_flags dflags;\n+\n+\tfor_each_child_of_node(chip->of_node, np) {\n+\t\tif (!of_property_read_bool(np, \"gpio-hog\"))\n+\t\t\tcontinue;\n+\n+\t\tdesc = of_get_gpio_hog(np, &name, &lflags, &dflags);\n+\t\tif (IS_ERR(desc))\n+\t\t\tcontinue;\n+\n+\t\tif (gpiod_hog(desc, name, lflags, dflags))\n+\t\t\tcontinue;\n+\t}\n+}\n+\n+/**\n * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags\n * @gc:\t\tpointer to the gpio_chip structure\n * @np:\t\tdevice node of the GPIO chip\n@@ -308,6 +417,8 @@ void of_gpiochip_add(struct gpio_chip *chip)\n \n \tof_gpiochip_add_pin_range(chip);\n \tof_node_get(chip->of_node);\n+\n+\tof_gpiochip_scan_hogs(chip);\n }\n \n void of_gpiochip_remove(struct gpio_chip *chip)\ndiff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c\nindex 568aa2b..410b86d 100644\n--- a/drivers/gpio/gpiolib.c\n+++ b/drivers/gpio/gpiolib.c\n@@ -315,6 +315,7 @@ EXPORT_SYMBOL_GPL(gpiochip_add);\n \n /* Forward-declaration */\n static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);\n+static void gpiochip_free_hogs(struct gpio_chip *chip);\n \n /**\n * gpiochip_remove() - unregister a gpio_chip\n@@ -333,6 +334,7 @@ void gpiochip_remove(struct gpio_chip *chip)\n \n \tacpi_gpiochip_remove(chip);\n \tgpiochip_remove_pin_ranges(chip);\n+\tgpiochip_free_hogs(chip);\n \tof_gpiochip_remove(chip);\n \n \tspin_lock_irqsave(&gpio_lock, flags);\n@@ -866,6 +868,7 @@ static bool __gpiod_free(struct gpio_desc *desc)\n \t\tclear_bit(FLAG_REQUESTED, &desc->flags);\n \t\tclear_bit(FLAG_OPEN_DRAIN, &desc->flags);\n \t\tclear_bit(FLAG_OPEN_SOURCE, &desc->flags);\n+\t\tclear_bit(FLAG_IS_HOGGED, &desc->flags);\n \t\tret = true;\n \t}\n \n@@ -1838,6 +1841,47 @@ struct gpio_desc *__must_check __gpiod_get_optional(struct device *dev,\n }\n EXPORT_SYMBOL_GPL(__gpiod_get_optional);\n \n+\n+/**\n+ * gpiod_configure_flags - helper function to configure a given GPIO\n+ * @desc:\tgpio whose value will be assigned\n+ * @con_id:\tfunction within the GPIO consumer\n+ * @lflags:\tgpio_lookup_flags - returned from of_find_gpio() or\n+ *\t\tof_get_gpio_hog()\n+ * @dflags:\tgpiod_flags - optional GPIO initialization flags\n+ *\n+ * Return 0 on success, -ENOENT if no GPIO has been assigned to the\n+ * requested function and/or index, or another IS_ERR() code if an error\n+ * occurred while trying to acquire the GPIO.\n+ */\n+static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,\n+\t\tunsigned long lflags, enum gpiod_flags dflags)\n+{\n+\tint status;\n+\n+\tif (lflags & GPIO_ACTIVE_LOW)\n+\t\tset_bit(FLAG_ACTIVE_LOW, &desc->flags);\n+\tif (lflags & GPIO_OPEN_DRAIN)\n+\t\tset_bit(FLAG_OPEN_DRAIN, &desc->flags);\n+\tif (lflags & GPIO_OPEN_SOURCE)\n+\t\tset_bit(FLAG_OPEN_SOURCE, &desc->flags);\n+\n+\t/* No particular flag request, return here... */\n+\tif (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) {\n+\t\tpr_debug(\"no flags found for %s\\n\", con_id);\n+\t\treturn 0;\n+\t}\n+\n+\t/* Process flags */\n+\tif (dflags & GPIOD_FLAGS_BIT_DIR_OUT)\n+\t\tstatus = gpiod_direction_output(desc,\n+\t\t\t\t\t dflags & GPIOD_FLAGS_BIT_DIR_VAL);\n+\telse\n+\t\tstatus = gpiod_direction_input(desc);\n+\n+\treturn status;\n+}\n+\n /**\n * gpiod_get_index - obtain a GPIO from a multi-index GPIO function\n * @dev:\tGPIO consumer, can be NULL for system-global GPIOs\n@@ -1887,28 +1931,10 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,\n \t}\n \n \tstatus = gpiod_request(desc, con_id);\n-\n \tif (status < 0)\n \t\treturn ERR_PTR(status);\n \n-\tif (lookupflags & GPIO_ACTIVE_LOW)\n-\t\tset_bit(FLAG_ACTIVE_LOW, &desc->flags);\n-\tif (lookupflags & GPIO_OPEN_DRAIN)\n-\t\tset_bit(FLAG_OPEN_DRAIN, &desc->flags);\n-\tif (lookupflags & GPIO_OPEN_SOURCE)\n-\t\tset_bit(FLAG_OPEN_SOURCE, &desc->flags);\n-\n-\t/* No particular flag request, return here... */\n-\tif (!(flags & GPIOD_FLAGS_BIT_DIR_SET))\n-\t\treturn desc;\n-\n-\t/* Process flags */\n-\tif (flags & GPIOD_FLAGS_BIT_DIR_OUT)\n-\t\tstatus = gpiod_direction_output(desc,\n-\t\t\t\t\t flags & GPIOD_FLAGS_BIT_DIR_VAL);\n-\telse\n-\t\tstatus = gpiod_direction_input(desc);\n-\n+\tstatus = gpiod_configure_flags(desc, con_id, lookupflags, flags);\n \tif (status < 0) {\n \t\tdev_dbg(dev, \"setup of GPIO %s failed\\n\", con_id);\n \t\tgpiod_put(desc);\n@@ -2004,6 +2030,66 @@ struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev,\n EXPORT_SYMBOL_GPL(__gpiod_get_index_optional);\n \n /**\n+ * gpiod_hog - Hog the specified GPIO desc given the provided flags\n+ * @desc:\tgpio whose value will be assigned\n+ * @name:\tgpio line name\n+ * @lflags:\tgpio_lookup_flags - returned from of_find_gpio() or\n+ *\t\tof_get_gpio_hog()\n+ * @dflags:\tgpiod_flags - optional GPIO initialization flags\n+ */\n+int gpiod_hog(struct gpio_desc *desc, const char *name,\n+\t unsigned long lflags, enum gpiod_flags dflags)\n+{\n+\tstruct gpio_chip *chip;\n+\tstruct gpio_desc *local_desc;\n+\tint hwnum;\n+\tint status;\n+\n+\tchip = gpiod_to_chip(desc);\n+\thwnum = gpio_chip_hwgpio(desc);\n+\n+\tlocal_desc = gpiochip_request_own_desc(chip, hwnum, name);\n+\tif (IS_ERR(local_desc)) {\n+\t\tpr_debug(\"requesting own GPIO %s failed\\n\", name);\n+\t\treturn PTR_ERR(local_desc);\n+\t}\n+\n+\tstatus = gpiod_configure_flags(desc, name, lflags, dflags);\n+\tif (status < 0) {\n+\t\tpr_debug(\"setup of GPIO %s failed\\n\", name);\n+\t\tgpiochip_free_own_desc(desc);\n+\t\treturn status;\n+\t}\n+\n+\t/* Mark GPIO as hogged so it can be identified and removed later */\n+\tset_bit(FLAG_IS_HOGGED, &desc->flags);\n+\n+\tpr_info(\"GPIO line %d (%s) hogged as %s%s\\n\",\n+\t\tdesc_to_gpio(desc), name,\n+\t\t(dflags&GPIOD_FLAGS_BIT_DIR_OUT) ? \"output\" : \"input\",\n+\t\t(dflags&GPIOD_FLAGS_BIT_DIR_OUT) ?\n+\t\t (dflags&GPIOD_FLAGS_BIT_DIR_VAL) ? \"/high\" : \"/low\":\"\");\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * gpiochip_free_hogs - Scan gpio-controller chip and release GPIO hog\n+ * @chip:\tgpio chip to act on\n+ *\n+ * This is only used by of_gpiochip_remove to free hogged gpios\n+ */\n+static void gpiochip_free_hogs(struct gpio_chip *chip)\n+{\n+\tint id;\n+\n+\tfor (id = 0; id < chip->ngpio; id++) {\n+\t\tif (test_bit(FLAG_IS_HOGGED, &chip->desc[id].flags))\n+\t\t\tgpiochip_free_own_desc(&chip->desc[id]);\n+\t}\n+}\n+\n+/**\n * gpiod_put - dispose of a GPIO descriptor\n * @desc:\tGPIO descriptor to dispose of\n *\ndiff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h\nindex 550a5ea..cadba26 100644\n--- a/drivers/gpio/gpiolib.h\n+++ b/drivers/gpio/gpiolib.h\n@@ -78,6 +78,7 @@ struct gpio_desc {\n #define FLAG_OPEN_SOURCE 8\t/* Gpio is open source type */\n #define FLAG_USED_AS_IRQ 9\t/* GPIO is connected to an IRQ */\n #define FLAG_SYSFS_DIR\t10\t/* show sysfs direction attribute */\n+#define FLAG_IS_HOGGED\t11\t/* GPIO is hogged */\n \n #define ID_SHIFT\t16\t/* add new flags before this one */\n \n@@ -89,6 +90,8 @@ struct gpio_desc {\n \n int gpiod_request(struct gpio_desc *desc, const char *label);\n void gpiod_free(struct gpio_desc *desc);\n+int gpiod_hog(struct gpio_desc *desc, const char *name,\n+\t\tunsigned long lflags, enum gpiod_flags dflags);\n \n /*\n * Return the GPIO number of the passed descriptor relative to its chip\n", "prefixes": [ "v6", "1/2" ] }