From patchwork Thu Apr 2 09:38:14 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ludovic Desroches X-Patchwork-Id: 6145981 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 20ECF9F499 for ; Thu, 2 Apr 2015 09:51:55 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 1EADD20263 for ; Thu, 2 Apr 2015 09:51:54 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 04E212035B for ; Thu, 2 Apr 2015 09:51:53 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Ydbjr-0003MZ-RI; Thu, 02 Apr 2015 09:48:40 +0000 Received: from eusmtp01.atmel.com ([212.144.249.243]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Ydbas-0003im-O1 for linux-arm-kernel@lists.infradead.org; Thu, 02 Apr 2015 09:39:24 +0000 Received: from ibiza.corp.atmel.com (10.161.101.13) by eusmtp01.atmel.com (10.161.101.31) with Microsoft SMTP Server id 14.2.347.0; Thu, 2 Apr 2015 11:38:54 +0200 From: Ludovic Desroches To: , , Subject: [RFC PATCH 2/4] pinctrl: introduce complex pin description Date: Thu, 2 Apr 2015 11:38:14 +0200 Message-ID: <1427967496-22533-3-git-send-email-ludovic.desroches@atmel.com> X-Mailer: git-send-email 2.2.0 In-Reply-To: <1427967496-22533-1-git-send-email-ludovic.desroches@atmel.com> References: <1427967496-22533-1-git-send-email-ludovic.desroches@atmel.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150402_023923_258063_3803AF39 X-CRM114-Status: GOOD ( 18.30 ) X-Spam-Score: -2.3 (--) Cc: swarren@wwwdotorg.org, tony@atomide.com, linus.walleij@linaro.org, nicolas.ferre@atmel.com, Ludovic Desroches , laurent.pinchart@ideasonboard.com, s.hauer@pengutronix.de X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Some extra information may be needed to describe a pin, mainly for controllers support per pin muxing where groups are an abstract concept. Instead of using its name, use a 32 bit value whose 16 lowest bits are used for the pin number and the 16 highest ones can be used for extra information. Signed-off-by: Ludovic Desroches --- drivers/pinctrl/pinconf-generic.c | 115 +++++++++++++++++++++++++++----------- include/linux/pinctrl/pinctrl.h | 5 ++ 2 files changed, 86 insertions(+), 34 deletions(-) diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index e088666..11f9d1b 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -268,28 +268,53 @@ out: return ret; } -int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, +int pinconf_generic_dt_subnode_to_mux_map(struct pinctrl_dev *pctldev, struct device_node *np, struct pinctrl_map **map, unsigned *reserved_maps, unsigned *num_maps, - enum pinctrl_map_type type) + const char *function) { int ret; - const char *function; - struct device *dev = pctldev->dev; - unsigned long *configs = NULL; - unsigned num_configs = 0; - unsigned reserve; - struct property *prop; const char *group; - const char *subnode_target_type = "pins"; + struct property *prop; + struct device *dev = pctldev->dev; ret = of_property_read_string(np, "function", &function); - if (ret < 0) { - /* EINVAL=missing, which is fine since it's optional */ - if (ret != -EINVAL) - dev_err(dev, "could not parse property function\n"); - function = NULL; + + of_property_for_each_string(np, "groups", prop, group) { + + ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, + num_maps, 1); + if (ret < 0) + goto exit; + + ret = pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, + num_maps, group, function); + if (ret < 0) + goto exit; } + ret = 0; + +exit: + return ret; +} + +int pinconf_generic_dt_subnode_to_conf_map(struct pinctrl_dev *pctldev, + struct device_node *np, struct pinctrl_map **map, + unsigned *reserved_maps, unsigned *num_maps, + enum pinctrl_map_type type) +{ + const struct pinctrl_desc *pctldesc = pctldev->desc; + int ret; + unsigned reserve, pin_id; + unsigned long *configs = NULL; + const char *pin; + const char *group; + const char *subnode_target_type = "pins"; + struct property *prop; + const __be32 *cur; + u32 val; + unsigned num_configs = 0; + struct device *dev = pctldev->dev; ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, &num_configs); @@ -298,14 +323,7 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, return ret; } - reserve = 0; - if (function != NULL) - reserve++; - if (num_configs) - reserve++; - - ret = of_property_count_strings(np, "pins"); - if (ret < 0) { + if (!of_property_read_bool(np, "pins")) { ret = of_property_count_strings(np, "groups"); if (ret < 0) { dev_err(dev, "could not parse property pins/groups\n"); @@ -315,26 +333,35 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, type = PIN_MAP_TYPE_CONFIGS_GROUP; subnode_target_type = "groups"; } else { + if (pctldesc->complex_pin_desc) + ret = of_property_count_u32_elems(np, "pins"); + else + ret = of_property_count_strings(np, "pins"); + + if (ret < 0) { + dev_err(dev, "could not parse property pins\n"); + goto exit; + } if (type == PIN_MAP_TYPE_INVALID) type = PIN_MAP_TYPE_CONFIGS_PIN; } - reserve *= ret; + reserve = ret; ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, reserve); if (ret < 0) goto exit; - of_property_for_each_string(np, subnode_target_type, prop, group) { - if (function) { - ret = pinctrl_utils_add_map_mux(pctldev, map, - reserved_maps, num_maps, group, - function); - if (ret < 0) - goto exit; + if (pctldesc->complex_pin_desc) { + of_property_for_each_u32(np, subnode_target_type, prop, cur, val) { + pin_id = val & PINCTRL_PIN_MASK; + pin = pctldesc->pins[pin_id].name; + ret = pinctrl_utils_add_map_configs(pctldev, map, + reserved_maps, num_maps, pin, configs, + num_configs, type); } - - if (num_configs) { + } else { + of_property_for_each_string(np, subnode_target_type, prop, group) { ret = pinctrl_utils_add_map_configs(pctldev, map, reserved_maps, num_maps, group, configs, num_configs, type); @@ -342,12 +369,32 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, goto exit; } } - ret = 0; - exit: kfree(configs); return ret; } + +int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, struct pinctrl_map **map, + unsigned *reserved_maps, unsigned *num_maps, + enum pinctrl_map_type type) +{ + int ret; + const char *function; + struct device *dev = pctldev->dev; + + ret = of_property_read_string(np, "function", &function); + if (ret < 0) { + /* EINVAL=missing, which is fine since it's optional */ + if (ret != -EINVAL) + dev_err(dev, "could not parse property function\n"); + return pinconf_generic_dt_subnode_to_conf_map(pctldev, + np, map, reserved_maps, num_maps, type); + } else { + return pinconf_generic_dt_subnode_to_mux_map(pctldev, + np, map, reserved_maps, num_maps, function); + } +} EXPORT_SYMBOL_GPL(pinconf_generic_dt_subnode_to_map); int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev, diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h index c58b3e1..06a070a 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -45,6 +45,8 @@ struct pinctrl_pin_desc { #define PINCTRL_PIN(a, b) { .number = a, .name = b } #define PINCTRL_PIN_ANON(a) { .number = a } +#define PINCTRL_PIN_MASK 0xffff + /** * struct pinctrl_gpio_range - each pin controller can provide subranges of * the GPIO number space to be handled by the controller @@ -112,6 +114,8 @@ struct pinctrl_ops { * this pin controller * @npins: number of descriptors in the array, usually just ARRAY_SIZE() * of the pins field above + * @complex_pin_desc: some pin controller needs more information than the pin + * name. In this case pins property uses u32 elements instead of strings * @pctlops: pin control operation vtable, to support global concepts like * grouping of pins, this is optional. * @pmxops: pinmux operations vtable, if you support pinmuxing in your driver @@ -126,6 +130,7 @@ struct pinctrl_desc { const char *name; struct pinctrl_pin_desc const *pins; unsigned int npins; + bool complex_pin_desc; const struct pinctrl_ops *pctlops; const struct pinmux_ops *pmxops; const struct pinconf_ops *confops;