From 65b606f92c3e26af787fa9fcd16a1da28429798a Mon Sep 17 00:00:00 2001 From: Sherman Yin Date: Fri, 20 Dec 2013 18:13:33 -0800 Subject: [PATCH 01/18] pinctrl: Add void * to pinctrl_pin_desc drv_data is added to the pinctrl_pin_desc for drivers to define additional driver-specific per-pin data. Signed-off-by: Sherman Yin Reviewed-by: Christian Daudt Reviewed-by: Matt Porter Signed-off-by: Linus Walleij (cherry picked from commit a30d54218e0306b3b7db7df34fe70d5e86fcbbe2) Signed-off-by: Mark Brown --- include/linux/pinctrl/pinctrl.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h index 2c2a9e8d8578..9adb1067af71 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -32,10 +32,12 @@ struct device_node; * pins, pads or other muxable units in this struct * @number: unique pin number from the global pin number space * @name: a name for this pin + * @drv_data: driver-defined per-pin data. pinctrl core does not touch this */ struct pinctrl_pin_desc { unsigned number; const char *name; + void *drv_data; }; /* Convenience macro to define a single named or anonymous pin descriptor */ From a11975a78b2652b1f15152ffda2d6de27f1a41cf Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 24 Jun 2013 15:06:19 +0200 Subject: [PATCH 02/18] pinctrl: rip out the direct pinconf API From the inception ot the pin config API there has been the possibility to get a handle at a pin directly and configure its electrical characteristics. For this reason we had: int pin_config_get(const char *dev_name, const char *name, unsigned long *config); int pin_config_set(const char *dev_name, const char *name, unsigned long config); int pin_config_group_get(const char *dev_name, const char *pin_group, unsigned long *config); int pin_config_group_set(const char *dev_name, const char *pin_group, unsigned long config); After the introduction of the pin control states that will control pins associated with devices, and its subsequent introduction to the device core, as well as the introduction of pin control hogs that can set up states on boot and optionally also at sleep, this direct pin control API is a thing of the past. As could be expected, it has zero in-kernel users. Let's delete this API and make our world simpler. Reported-by: Tony Lindgren Reviewed-by: Stephen Warren Acked-by: Tony Lindgren Signed-off-by: Linus Walleij (cherry picked from commit ad42fc6c84795d19972e7f7dee70fe74bec4c2d8) Signed-off-by: Mark Brown --- Documentation/pinctrl.txt | 11 +- drivers/pinctrl/pinconf.c | 174 ------------------------------- include/linux/pinctrl/consumer.h | 43 -------- 3 files changed, 2 insertions(+), 226 deletions(-) diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index 447fd4cd54ec..c8763806c65e 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -203,15 +203,8 @@ using a certain resistor value - pull up and pull down - so that the pin has a stable value when nothing is driving the rail it is connected to, or when it's unconnected. -Pin configuration can be programmed either using the explicit APIs described -immediately below, or by adding configuration entries into the mapping table; -see section "Board/machine configuration" below. - -For example, a platform may do the following to pull up a pin to VDD: - -#include - -ret = pin_config_set("foo-dev", "FOO_GPIO_PIN", PLATFORM_X_PULL_UP); +Pin configuration can be programmed by adding configuration entries into the +mapping table; see section "Board/machine configuration" below. The format and meaning of the configuration parameter, PLATFORM_X_PULL_UP above, is entirely defined by the pin controller driver. diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index 694c3ace4520..e875f21a5908 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -75,98 +75,6 @@ int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin, return ops->pin_config_get(pctldev, pin, config); } -/** - * pin_config_get() - get the configuration of a single pin parameter - * @dev_name: name of the pin controller device for this pin - * @name: name of the pin to get the config for - * @config: the config pointed to by this argument will be filled in with the - * current pin state, it can be used directly by drivers as a numeral, or - * it can be dereferenced to any struct. - */ -int pin_config_get(const char *dev_name, const char *name, - unsigned long *config) -{ - struct pinctrl_dev *pctldev; - int pin; - - pctldev = get_pinctrl_dev_from_devname(dev_name); - if (!pctldev) { - pin = -EINVAL; - return pin; - } - - mutex_lock(&pctldev->mutex); - - pin = pin_get_from_name(pctldev, name); - if (pin < 0) - goto unlock; - - pin = pin_config_get_for_pin(pctldev, pin, config); - -unlock: - mutex_unlock(&pctldev->mutex); - return pin; -} -EXPORT_SYMBOL(pin_config_get); - -static int pin_config_set_for_pin(struct pinctrl_dev *pctldev, unsigned pin, - unsigned long config) -{ - const struct pinconf_ops *ops = pctldev->desc->confops; - int ret; - - if (!ops || !ops->pin_config_set) { - dev_err(pctldev->dev, "cannot configure pin, missing " - "config function in driver\n"); - return -EINVAL; - } - - ret = ops->pin_config_set(pctldev, pin, config); - if (ret) { - dev_err(pctldev->dev, - "unable to set pin configuration on pin %d\n", pin); - return ret; - } - - return 0; -} - -/** - * pin_config_set() - set the configuration of a single pin parameter - * @dev_name: name of pin controller device for this pin - * @name: name of the pin to set the config for - * @config: the config in this argument will contain the desired pin state, it - * can be used directly by drivers as a numeral, or it can be dereferenced - * to any struct. - */ -int pin_config_set(const char *dev_name, const char *name, - unsigned long config) -{ - struct pinctrl_dev *pctldev; - int pin, ret; - - pctldev = get_pinctrl_dev_from_devname(dev_name); - if (!pctldev) { - ret = -EINVAL; - return ret; - } - - mutex_lock(&pctldev->mutex); - - pin = pin_get_from_name(pctldev, name); - if (pin < 0) { - ret = pin; - goto unlock; - } - - ret = pin_config_set_for_pin(pctldev, pin, config); - -unlock: - mutex_unlock(&pctldev->mutex); - return ret; -} -EXPORT_SYMBOL(pin_config_set); - int pin_config_group_get(const char *dev_name, const char *pin_group, unsigned long *config) { @@ -204,88 +112,6 @@ unlock: mutex_unlock(&pctldev->mutex); return ret; } -EXPORT_SYMBOL(pin_config_group_get); - -int pin_config_group_set(const char *dev_name, const char *pin_group, - unsigned long config) -{ - struct pinctrl_dev *pctldev; - const struct pinconf_ops *ops; - const struct pinctrl_ops *pctlops; - int selector; - const unsigned *pins; - unsigned num_pins; - int ret; - int i; - - pctldev = get_pinctrl_dev_from_devname(dev_name); - if (!pctldev) { - ret = -EINVAL; - return ret; - } - - mutex_lock(&pctldev->mutex); - - ops = pctldev->desc->confops; - pctlops = pctldev->desc->pctlops; - - if (!ops || (!ops->pin_config_group_set && !ops->pin_config_set)) { - dev_err(pctldev->dev, "cannot configure pin group, missing " - "config function in driver\n"); - ret = -EINVAL; - goto unlock; - } - - selector = pinctrl_get_group_selector(pctldev, pin_group); - if (selector < 0) { - ret = selector; - goto unlock; - } - - ret = pctlops->get_group_pins(pctldev, selector, &pins, &num_pins); - if (ret) { - dev_err(pctldev->dev, "cannot configure pin group, error " - "getting pins\n"); - goto unlock; - } - - /* - * If the pin controller supports handling entire groups we use that - * capability. - */ - if (ops->pin_config_group_set) { - ret = ops->pin_config_group_set(pctldev, selector, config); - /* - * If the pin controller prefer that a certain group be handled - * pin-by-pin as well, it returns -EAGAIN. - */ - if (ret != -EAGAIN) - goto unlock; - } - - /* - * If the controller cannot handle entire groups, we configure each pin - * individually. - */ - if (!ops->pin_config_set) { - ret = 0; - goto unlock; - } - - for (i = 0; i < num_pins; i++) { - ret = ops->pin_config_set(pctldev, pins[i], config); - if (ret < 0) - goto unlock; - } - - ret = 0; - -unlock: - mutex_unlock(&pctldev->mutex); - - return ret; -} -EXPORT_SYMBOL(pin_config_group_set); int pinconf_map_to_setting(struct pinctrl_map const *map, struct pinctrl_setting *setting) diff --git a/include/linux/pinctrl/consumer.h b/include/linux/pinctrl/consumer.h index 4aad3cea69ae..04c760d56bb8 100644 --- a/include/linux/pinctrl/consumer.h +++ b/include/linux/pinctrl/consumer.h @@ -158,47 +158,4 @@ static inline struct pinctrl * __must_check devm_pinctrl_get_select_default( return devm_pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT); } -#ifdef CONFIG_PINCONF - -extern int pin_config_get(const char *dev_name, const char *name, - unsigned long *config); -extern int pin_config_set(const char *dev_name, const char *name, - unsigned long config); -extern int pin_config_group_get(const char *dev_name, - const char *pin_group, - unsigned long *config); -extern int pin_config_group_set(const char *dev_name, - const char *pin_group, - unsigned long config); - -#else - -static inline int pin_config_get(const char *dev_name, const char *name, - unsigned long *config) -{ - return 0; -} - -static inline int pin_config_set(const char *dev_name, const char *name, - unsigned long config) -{ - return 0; -} - -static inline int pin_config_group_get(const char *dev_name, - const char *pin_group, - unsigned long *config) -{ - return 0; -} - -static inline int pin_config_group_set(const char *dev_name, - const char *pin_group, - unsigned long config) -{ - return 0; -} - -#endif - #endif /* __LINUX_PINCTRL_CONSUMER_H */ From 9ae6a79ed21c686aedbcef04cf76833f33ea1d2a Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 24 May 2013 17:21:11 +0100 Subject: [PATCH 03/18] pinconf-generic: add drive strength to debugfs output Add the drive strength pinconf to debugfs output (with the unit "mA"). Signed-off-by: James Hogan Cc: Linus Walleij Signed-off-by: Linus Walleij (cherry picked from commit 73ae368cd309dae277b66444d471ac62825ee407) Signed-off-by: Mark Brown --- drivers/pinctrl/pinconf-generic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 2ad5a8d337b5..33a5392cf40c 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -42,6 +42,7 @@ static struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL), + PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA"), PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL), PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL), PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "time units"), From 5a585d47f797d7e5f8a3f79842f9c50115b870c3 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 24 May 2013 17:21:12 +0100 Subject: [PATCH 04/18] pinconf-generic: add BIAS_BUS_HOLD pinconf Add a new PIN_CONFIG_BIAS_BUS_HOLD pin configuration for a bus holder pin mode (also known as bus keeper, or repeater). This is a weak latch which drives the last value on a tristate bus. Another device on the bus can drive the bus high or low before going tristate to change the value driven by the pin. Signed-off-by: James Hogan Cc: Linus Walleij Signed-off-by: Linus Walleij (cherry picked from commit a2df4269cad79635201587c5c5404f0b1cb0b05c) Signed-off-by: Mark Brown --- drivers/pinctrl/pinconf-generic.c | 1 + include/linux/pinctrl/pinconf-generic.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 33a5392cf40c..ba465b3e85ef 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -37,6 +37,7 @@ struct pin_config_item { static struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL), PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL), + PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL), PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL), PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", NULL), PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL), diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index 6aa238096622..ac05b3cfeacc 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -29,6 +29,11 @@ * if for example some other pin is going to drive the signal connected * to it for a while. Pins used for input are usually always high * impedance. + * @PIN_CONFIG_BIAS_BUS_HOLD: the pin will be set to weakly latch so that it + * weakly drives the last value on a tristate bus, also known as a "bus + * holder", "bus keeper" or "repeater". This allows another device on the + * bus to change the value by driving the bus high or low and switching to + * tristate. The argument is ignored. * @PIN_CONFIG_BIAS_PULL_UP: the pin will be pulled up (usually with high * impedance to VDD). If the argument is != 0 pull-up is enabled, * if it is 0, pull-up is disabled. @@ -78,6 +83,7 @@ enum pin_config_param { PIN_CONFIG_BIAS_DISABLE, PIN_CONFIG_BIAS_HIGH_IMPEDANCE, + PIN_CONFIG_BIAS_BUS_HOLD, PIN_CONFIG_BIAS_PULL_UP, PIN_CONFIG_BIAS_PULL_DOWN, PIN_CONFIG_DRIVE_PUSH_PULL, From fd08eab34aaf6f8ea441ee7c59c9e9771aa1e5e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Thu, 6 Jun 2013 16:44:25 +0200 Subject: [PATCH 05/18] pinctrl: add pinconf-generic define for a pin-default pull There exist controllers that don't support to set the pull to up or down separately but instead automatically set the pull direction based on embedded knowledge inside the controller, for example depending on the selected mux function of the pin. Therefore this patch adds another config option to use this default pull-state for a pin where it is not possible to know or decide if the pin will be pulled up or down. Signed-off-by: Heiko Stuebner Reviewed-by: Stephen Warren Signed-off-by: Linus Walleij (cherry picked from commit 7970cb770dffa23cb20a36f46602e688e075f5d9) Signed-off-by: Mark Brown --- drivers/pinctrl/pinconf-generic.c | 2 ++ include/linux/pinctrl/pinconf-generic.h | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index ba465b3e85ef..9a6812b50a32 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -40,6 +40,8 @@ static struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL), PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL), PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", NULL), + PCONFDUMP(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, + "input bias pull to pin specific state", NULL), PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL), diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index ac05b3cfeacc..d414a7729424 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -40,6 +40,10 @@ * @PIN_CONFIG_BIAS_PULL_DOWN: the pin will be pulled down (usually with high * impedance to GROUND). If the argument is != 0 pull-down is enabled, * if it is 0, pull-down is disabled. + * @PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: the pin will be pulled up or down based + * on embedded knowledge of the controller, like current mux function. + * If the argument is != 0 pull up/down is enabled, if it is 0, + * the pull is disabled. * @PIN_CONFIG_DRIVE_PUSH_PULL: the pin will be driven actively high and * low, this is the most typical case and is typically achieved with two * active transistors on the output. Setting this config will enable @@ -86,6 +90,7 @@ enum pin_config_param { PIN_CONFIG_BIAS_BUS_HOLD, PIN_CONFIG_BIAS_PULL_UP, PIN_CONFIG_BIAS_PULL_DOWN, + PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, PIN_CONFIG_DRIVE_PUSH_PULL, PIN_CONFIG_DRIVE_OPEN_DRAIN, PIN_CONFIG_DRIVE_OPEN_SOURCE, From a3aadc7709bc7659d5bfbaf57028a2463fcc4346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Mon, 10 Jun 2013 21:40:29 +0200 Subject: [PATCH 06/18] pinctrl: add function to parse generic pinconfig properties from a dt node pinconf_generic_parse_dt_config() takes a node as input and generates an array of generic pinconfig values from the properties of this node. As I couldn't find a mechanism to count the number of properties of a node the function uses internally an array to accept one of parameter and copies the real present options to a smaller variable at its end. Signed-off-by: Heiko Stuebner Signed-off-by: Linus Walleij (cherry picked from commit 7db9af4b6e41be599e0fcd50d687138a5add428c) Signed-off-by: Mark Brown --- .../bindings/pinctrl/pinctrl-bindings.txt | 38 +++++++++ drivers/pinctrl/pinconf-generic.c | 81 +++++++++++++++++++ drivers/pinctrl/pinconf.h | 6 ++ 3 files changed, 125 insertions(+) diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt index c95ea8278f87..ef7cd572214c 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt @@ -126,3 +126,41 @@ device; they may be grandchildren, for example. Whether this is legal, and whether there is any interaction between the child and intermediate parent nodes, is again defined entirely by the binding for the individual pin controller device. + +== Using generic pinconfig options == + +Generic pinconfig parameters can be used by defining a separate node containing +the applicable parameters (and optional values), like: + +pcfg_pull_up: pcfg_pull_up { + bias-pull-up; + drive-strength = <20>; +}; + +This node should then be referenced in the appropriate pinctrl node as a phandle +and parsed in the driver using the pinconf_generic_parse_dt_config function. + +Supported configuration parameters are: + +bias-disable - disable any pin bias +bias-high-impedance - high impedance mode ("third-state", "floating") +bias-bus-hold - latch weakly +bias-pull-up - pull up the pin +bias-pull-down - pull down the pin +bias-pull-pin-default - use pin-default pull state +drive-push-pull - drive actively high and low +drive-open-drain - drive with open drain +drive-open-source - drive with open source +drive-strength - sink or source at most X mA +input-schmitt-enable - enable schmitt-trigger mode +input-schmitt-disable - disable schmitt-trigger mode +input-schmitt - run in schmitt-trigger mode with hysteresis X +input-debounce - debounce mode with debound time X +power-source - select power source X +slew-rate - use slew-rate X +low-power-mode - low power mode +output-low - set the pin to output mode with low level +output-high - set the pin to output mode with high level + +More in-depth documentation on these parameters can be found in + diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 9a6812b50a32..d3c693c0c250 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "core.h" #include "pinconf.h" @@ -139,3 +140,83 @@ void pinconf_generic_dump_config(struct pinctrl_dev *pctldev, } EXPORT_SYMBOL_GPL(pinconf_generic_dump_config); #endif + +#ifdef CONFIG_OF +struct pinconf_generic_dt_params { + const char * const property; + enum pin_config_param param; + u32 default_value; +}; + +static struct pinconf_generic_dt_params dt_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 }, + { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 0 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 0 }, + { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 0 }, + { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 }, + { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 }, + { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 }, + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, + { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, + { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, + { "input-schmitt", PIN_CONFIG_INPUT_SCHMITT, 0 }, + { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 }, + { "power-source", PIN_CONFIG_POWER_SOURCE, 0 }, + { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 }, + { "low-power-mode", PIN_CONFIG_LOW_POWER_MODE, 0 }, + { "output-low", PIN_CONFIG_OUTPUT, 0, }, + { "output-high", PIN_CONFIG_OUTPUT, 1, }, +}; + +/** + * pinconf_generic_parse_dt_config() + * parse the config properties into generic pinconfig values. + * @np: node containing the pinconfig properties + * @configs: array with nconfigs entries containing the generic pinconf values + * @nconfigs: umber of configurations + */ +int pinconf_generic_parse_dt_config(struct device_node *np, + unsigned long **configs, + unsigned int *nconfigs) +{ + unsigned long cfg[ARRAY_SIZE(dt_params)]; + unsigned int ncfg = 0; + int ret; + int i; + u32 val; + + if (!np) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(dt_params); i++) { + struct pinconf_generic_dt_params *par = &dt_params[i]; + ret = of_property_read_u32(np, par->property, &val); + + /* property not found */ + if (ret == -EINVAL) + continue; + + /* use default value, when no value is specified */ + if (ret) + val = par->default_value; + + pr_debug("found %s with value %u\n", par->property, val); + cfg[ncfg] = pinconf_to_config_packed(par->param, val); + ncfg++; + } + + /* + * Now limit the number of configs to the real number of + * found properties. + */ + *configs = kzalloc(ncfg * sizeof(unsigned long), GFP_KERNEL); + if (!*configs) + return -ENOMEM; + + memcpy(*configs, &cfg, ncfg * sizeof(unsigned long)); + *nconfigs = ncfg; + return 0; +} +#endif diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h index 92c7267244d2..a4a5417e1413 100644 --- a/drivers/pinctrl/pinconf.h +++ b/drivers/pinctrl/pinconf.h @@ -123,3 +123,9 @@ static inline void pinconf_generic_dump_config(struct pinctrl_dev *pctldev, return; } #endif + +#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_OF) +int pinconf_generic_parse_dt_config(struct device_node *np, + unsigned long **configs, + unsigned int *nconfigs); +#endif From 255b8fa40a5d04f129acbde59d8c4d9b99bcc096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Fri, 14 Jun 2013 17:42:49 +0200 Subject: [PATCH 07/18] pinctrl: clarify some dt pinconfig options The bias-pull-* options use values > 0 to indicate that the pull should be activated and optionally also indicate the strength of the pull. Therefore use an default value of 1 for these options. Split the low-power-mode option into low-power-enable and -disable. Update the documentation to describe the param arguments better. Reported-by: James Hogan Signed-off-by: Heiko Stuebner Signed-off-by: Linus Walleij (cherry picked from commit 9ee1f7d266aa1e2bfeb20cb5d4ac299c8e8ef8c7) Signed-off-by: Mark Brown --- .../bindings/pinctrl/pinctrl-bindings.txt | 22 ++++++++++++++++++- drivers/pinctrl/pinconf-generic.c | 9 ++++---- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt index ef7cd572214c..2d730e3dd496 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt @@ -158,9 +158,29 @@ input-schmitt - run in schmitt-trigger mode with hysteresis X input-debounce - debounce mode with debound time X power-source - select power source X slew-rate - use slew-rate X -low-power-mode - low power mode +low-power-enable - enable low power mode +low-power-disable - disable low power mode output-low - set the pin to output mode with low level output-high - set the pin to output mode with high level +Arguments for parameters: + +- bias-pull-up, -down and -pin-default take as optional argument 0 to disable + the pull, on hardware supporting it the pull strength in Ohm. bias-disable + will also disable any active pull. + +- drive-strength takes as argument the target strength in mA. + +- input-schmitt takes as argument the adjustable hysteresis in a + driver-specific format + +- input-debounce takes the debounce time as argument or 0 to disable debouncing + +- power-source argument is the custom value describing the source to select + +- slew-rate takes as argument the target rate in a driver-specific format + +All parameters not listed here, do not take an argument. + More in-depth documentation on these parameters can be found in diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index d3c693c0c250..dcf03714de90 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -152,9 +152,9 @@ static struct pinconf_generic_dt_params dt_params[] = { { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 }, { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 }, - { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 0 }, - { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 0 }, - { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, + { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 }, { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 }, { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 }, { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 }, @@ -165,7 +165,8 @@ static struct pinconf_generic_dt_params dt_params[] = { { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 }, { "power-source", PIN_CONFIG_POWER_SOURCE, 0 }, { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 }, - { "low-power-mode", PIN_CONFIG_LOW_POWER_MODE, 0 }, + { "low-power-enable", PIN_CONFIG_LOW_POWER_MODE, 1 }, + { "low-power-disable", PIN_CONFIG_LOW_POWER_MODE, 0 }, { "output-low", PIN_CONFIG_OUTPUT, 0, }, { "output-high", PIN_CONFIG_OUTPUT, 1, }, }; From 374b02f771b24b9f4207d6b1c87564968c2615f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Fri, 14 Jun 2013 17:43:21 +0200 Subject: [PATCH 08/18] pinctrl: handle zero found dt pinconfig properties better This adds a shortcut when no valid pinconf properties are found in the parsed dt node, to set the values immediately and return. Suggested-by: Laurent Pinchart Signed-off-by: Heiko Stuebner Reviewed-by: James Hogan Signed-off-by: Linus Walleij (cherry picked from commit e4a8844c04c00a1a64c6779692e1baff3851c1f7) Signed-off-by: Mark Brown --- drivers/pinctrl/pinconf-generic.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index dcf03714de90..ea9da1752252 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -208,6 +208,13 @@ int pinconf_generic_parse_dt_config(struct device_node *np, ncfg++; } + /* no configs found at all */ + if (ncfg == 0) { + *configs = NULL; + *nconfigs = 0; + return 0; + } + /* * Now limit the number of configs to the real number of * found properties. From 2feed75860c8e11c5e36a062fe03f60d47b779df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Fri, 14 Jun 2013 17:43:55 +0200 Subject: [PATCH 09/18] pinctrl: dynamically alloc temp array when parsing dt pinconf options Allocating the temorary array in pinconf_generic_parse_dt_config on stack might cause problems later on, when the number of options grows over time. Therefore also allocate this array dynamically to be on the safe side. Suggested-by: Laurent Pinchart Signed-off-by: Heiko Stuebner Reviewed-by: James Hogan Signed-off-by: Linus Walleij (cherry picked from commit 6abab2d4bec982bcefbe99201ddee5f25227daf4) Signed-off-by: Mark Brown --- drivers/pinctrl/pinconf-generic.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index ea9da1752252..794dad7d68d8 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -182,7 +182,7 @@ int pinconf_generic_parse_dt_config(struct device_node *np, unsigned long **configs, unsigned int *nconfigs) { - unsigned long cfg[ARRAY_SIZE(dt_params)]; + unsigned long *cfg; unsigned int ncfg = 0; int ret; int i; @@ -191,6 +191,11 @@ int pinconf_generic_parse_dt_config(struct device_node *np, if (!np) return -EINVAL; + /* allocate a temporary array big enough to hold one of each option */ + cfg = kzalloc(sizeof(*cfg) * ARRAY_SIZE(dt_params), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + for (i = 0; i < ARRAY_SIZE(dt_params); i++) { struct pinconf_generic_dt_params *par = &dt_params[i]; ret = of_property_read_u32(np, par->property, &val); @@ -208,11 +213,13 @@ int pinconf_generic_parse_dt_config(struct device_node *np, ncfg++; } + ret = 0; + /* no configs found at all */ if (ncfg == 0) { *configs = NULL; *nconfigs = 0; - return 0; + goto out; } /* @@ -220,11 +227,16 @@ int pinconf_generic_parse_dt_config(struct device_node *np, * found properties. */ *configs = kzalloc(ncfg * sizeof(unsigned long), GFP_KERNEL); - if (!*configs) - return -ENOMEM; + if (!*configs) { + ret = -ENOMEM; + goto out; + } - memcpy(*configs, &cfg, ncfg * sizeof(unsigned long)); + memcpy(*configs, cfg, ncfg * sizeof(unsigned long)); *nconfigs = ncfg; - return 0; + +out: + kfree(cfg); + return ret; } #endif From 6d27cf9086952e6c563c5d4f912c549fe65812d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Tue, 25 Jun 2013 14:56:11 +0200 Subject: [PATCH 10/18] pinctrl: set unit for debounce time pinconfig to usec Currently the debounce time pinconfig option uses an unspecified "time units" unit. As pinconfig options should use SI units and a real unit is also necessary for generic dt bindings, change it to usec. Currently no driver is using the generic pinconfig option for this, so the unit change is safe to do. Signed-off-by: Heiko Stuebner Reviewed-by: James Hogan Signed-off-by: Linus Walleij (cherry picked from commit 256aeb648741bf095e884793862d3dfa6b1c1fb5) Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt | 3 ++- drivers/pinctrl/pinconf-generic.c | 2 +- include/linux/pinctrl/pinconf-generic.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt index 2d730e3dd496..b0cf4e672c80 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt @@ -174,7 +174,8 @@ Arguments for parameters: - input-schmitt takes as argument the adjustable hysteresis in a driver-specific format -- input-debounce takes the debounce time as argument or 0 to disable debouncing +- input-debounce takes the debounce time in usec as argument + or 0 to disable debouncing - power-source argument is the custom value describing the source to select diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 794dad7d68d8..2b271d5d90bf 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -49,7 +49,7 @@ static struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA"), PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL), PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL), - PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "time units"), + PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec"), PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector"), PCONFDUMP(PIN_CONFIG_SLEW_RATE, "slew rate", NULL), PCONFDUMP(PIN_CONFIG_LOW_POWER_MODE, "pin low power", "mode"), diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index d414a7729424..7f6c35bd1ccd 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -66,7 +66,7 @@ * setting pins to this mode. * @PIN_CONFIG_INPUT_DEBOUNCE: this will configure the pin to debounce mode, * which means it will wait for signals to settle when reading inputs. The - * argument gives the debounce time on a custom format. Setting the + * argument gives the debounce time in usecs. Setting the * argument to zero turns debouncing off. * @PIN_CONFIG_POWER_SOURCE: if the pin can select between different power * supplies, the argument to this parameter (on a custom format) tells From aaba68a91d559c7aa1d52037031878025b8cd48e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Tue, 25 Jun 2013 14:57:10 +0200 Subject: [PATCH 11/18] pinctrl: remove bindings for pinconf options needing more thought Some options currently take arguments in unspecified driver-specific units. As pointed out by Stephen Warren, driver specific values should not be part of generic devicetree bindings describing the hardware. Therefore remove the critical bindings again, before they become part of an official release. Signed-off-by: Heiko Stuebner Reviewed-by: James Hogan Signed-off-by: Linus Walleij (cherry picked from commit 5b81d55c4ccf23b9de398f819571dfc8941c7b04) Signed-off-by: Mark Brown --- .../devicetree/bindings/pinctrl/pinctrl-bindings.txt | 10 ---------- drivers/pinctrl/pinconf-generic.c | 3 --- 2 files changed, 13 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt index b0cf4e672c80..34155c2534e1 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt @@ -154,10 +154,7 @@ drive-open-source - drive with open source drive-strength - sink or source at most X mA input-schmitt-enable - enable schmitt-trigger mode input-schmitt-disable - disable schmitt-trigger mode -input-schmitt - run in schmitt-trigger mode with hysteresis X input-debounce - debounce mode with debound time X -power-source - select power source X -slew-rate - use slew-rate X low-power-enable - enable low power mode low-power-disable - disable low power mode output-low - set the pin to output mode with low level @@ -171,16 +168,9 @@ Arguments for parameters: - drive-strength takes as argument the target strength in mA. -- input-schmitt takes as argument the adjustable hysteresis in a - driver-specific format - - input-debounce takes the debounce time in usec as argument or 0 to disable debouncing -- power-source argument is the custom value describing the source to select - -- slew-rate takes as argument the target rate in a driver-specific format - All parameters not listed here, do not take an argument. More in-depth documentation on these parameters can be found in diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 2b271d5d90bf..8594f033ac21 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -161,10 +161,7 @@ static struct pinconf_generic_dt_params dt_params[] = { { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, - { "input-schmitt", PIN_CONFIG_INPUT_SCHMITT, 0 }, { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 }, - { "power-source", PIN_CONFIG_POWER_SOURCE, 0 }, - { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 }, { "low-power-enable", PIN_CONFIG_LOW_POWER_MODE, 1 }, { "low-power-disable", PIN_CONFIG_LOW_POWER_MODE, 0 }, { "output-low", PIN_CONFIG_OUTPUT, 0, }, From 9ce1c71276a05cd3849288b2df0a23baf49eec10 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 6 Aug 2013 18:42:34 +0530 Subject: [PATCH 12/18] pinctrl: pinconf-generic: add generic APIs for mapping pinctrl node Add generic APIs to map the DT node and its sub node in pinconf generic driver. These APIs can be used from driver to parse the DT node who uses the pinconf generic APIs for defining their nodes. Changes from V1: - Add generic property for pins and functions in pinconf-generic. - Add APIs to map the DT and subnode. - Move common utils APIs to the pinctrl-utils from this file. - Update the binding document accordingly. Changes from V2: - Rebased the pinctrl binding doc on top of Stephen's cleanup. - Rename properties "pinctrl-pins" and "pinctrl-function" to "pins" and "function". Signed-off-by: Laxman Dewangan Reviewed-by: Stephen Warren Signed-off-by: Linus Walleij (cherry picked from commit e81c8f18afc4fdd6e34d8c83814b8b5134dbb30f) Signed-off-by: Mark Brown --- drivers/pinctrl/pinconf-generic.c | 96 +++++++++++++++++++++++++ include/linux/pinctrl/pinconf-generic.h | 6 ++ 2 files changed, 102 insertions(+) diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 8594f033ac21..d9536caa9c41 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -24,6 +24,7 @@ #include #include "core.h" #include "pinconf.h" +#include "pinctrl-utils.h" #ifdef CONFIG_DEBUG_FS @@ -236,4 +237,99 @@ out: kfree(cfg); 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) +{ + 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; + + 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 ti,function\n"); + function = NULL; + } + + ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs); + if (ret < 0) { + dev_err(dev, "could not parse node property\n"); + return ret; + } + + reserve = 0; + if (function != NULL) + reserve++; + if (num_configs) + reserve++; + ret = of_property_count_strings(np, "pins"); + if (ret < 0) { + dev_err(dev, "could not parse property ti,pins\n"); + goto exit; + } + 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, "pins", prop, group) { + if (function) { + ret = pinctrl_utils_add_map_mux(pctldev, map, + reserved_maps, num_maps, group, + function); + if (ret < 0) + goto exit; + } + + if (num_configs) { + ret = pinctrl_utils_add_map_configs(pctldev, map, + reserved_maps, num_maps, group, configs, + num_configs, PIN_MAP_TYPE_CONFIGS_PIN); + if (ret < 0) + goto exit; + } + } + ret = 0; + +exit: + kfree(configs); + return ret; +} +EXPORT_SYMBOL_GPL(pinconf_generic_dt_subnode_to_map); + +int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, struct pinctrl_map **map, + unsigned *num_maps) +{ + unsigned reserved_maps; + struct device_node *np; + int ret; + + reserved_maps = 0; + *map = NULL; + *num_maps = 0; + + for_each_child_of_node(np_config, np) { + ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map, + &reserved_maps, num_maps); + if (ret < 0) { + pinctrl_utils_dt_free_map(pctldev, *map, *num_maps); + return ret; + } + } + return 0; +} +EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map); + #endif diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index 7f6c35bd1ccd..1980a880860e 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -133,6 +133,12 @@ static inline unsigned long pinconf_to_config_packed(enum pin_config_param param return PIN_CONF_PACKED(param, argument); } +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); +int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, struct pinctrl_map **map, + unsigned *num_maps); #endif /* CONFIG_GENERIC_PINCONF */ #endif /* __LINUX_PINCTRL_PINCONF_GENERIC_H */ From bede3529a47c8f7667a6bdd171a9548ea91a9af7 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 29 Aug 2013 10:05:06 +0800 Subject: [PATCH 13/18] pinctrl: pinconf-generic: Remove ti prefix in dev_err messages It does not make sense to show ti prefix in pinconf_generic_dt_subnode_to_map() dev_err messages. Signed-off-by: Axel Lin Signed-off-by: Linus Walleij (cherry picked from commit acf564a8f325566628a4ee2d9403cf1688cd0796) Signed-off-by: Mark Brown --- drivers/pinctrl/pinconf-generic.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index d9536caa9c41..94d66c60d9fc 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -255,8 +255,7 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, if (ret < 0) { /* EINVAL=missing, which is fine since it's optional */ if (ret != -EINVAL) - dev_err(dev, - "could not parse property ti,function\n"); + dev_err(dev, "could not parse property function\n"); function = NULL; } @@ -273,7 +272,7 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, reserve++; ret = of_property_count_strings(np, "pins"); if (ret < 0) { - dev_err(dev, "could not parse property ti,pins\n"); + dev_err(dev, "could not parse property pins\n"); goto exit; } reserve *= ret; From 150e48fdb38d78e9a317d6a7483de475b61d5d7f Mon Sep 17 00:00:00 2001 From: Sherman Yin Date: Wed, 11 Dec 2013 10:37:17 -0800 Subject: [PATCH 14/18] pinctrl: Adds slew-rate, input-enable/disable This commit adds slew-rate and input-enable/disable support for pinconf -generic. Signed-off-by: Sherman Yin Signed-off-by: Linus Walleij (cherry picked from commit 8ba3f4d00078e7a49c60c0bd6298f29402c3a0a0) Signed-off-by: Mark Brown --- .../devicetree/bindings/pinctrl/pinctrl-bindings.txt | 3 +++ drivers/pinctrl/pinconf-generic.c | 4 ++++ include/linux/pinctrl/pinconf-generic.h | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt index 34155c2534e1..b275be49a546 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt @@ -152,6 +152,8 @@ drive-push-pull - drive actively high and low drive-open-drain - drive with open drain drive-open-source - drive with open source drive-strength - sink or source at most X mA +input-enable - enable input on pin (no effect on output) +input-disable - disable input on pin (no effect on output) input-schmitt-enable - enable schmitt-trigger mode input-schmitt-disable - disable schmitt-trigger mode input-debounce - debounce mode with debound time X @@ -159,6 +161,7 @@ low-power-enable - enable low power mode low-power-disable - disable low power mode output-low - set the pin to output mode with low level output-high - set the pin to output mode with high level +slew-rate - set the slew rate Arguments for parameters: diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 94d66c60d9fc..d54b877cb704 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -48,6 +48,7 @@ static struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL), PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA"), + PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL), PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL), PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL), PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec"), @@ -160,6 +161,8 @@ static struct pinconf_generic_dt_params dt_params[] = { { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 }, { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 }, { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, + { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 }, + { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 }, { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 }, @@ -167,6 +170,7 @@ static struct pinconf_generic_dt_params dt_params[] = { { "low-power-disable", PIN_CONFIG_LOW_POWER_MODE, 0 }, { "output-low", PIN_CONFIG_OUTPUT, 0, }, { "output-high", PIN_CONFIG_OUTPUT, 1, }, + { "slew-rate", PIN_CONFIG_SLEW_RATE, 0}, }; /** diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index 1980a880860e..006e7bfe773d 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -57,6 +57,9 @@ * argument is ignored. * @PIN_CONFIG_DRIVE_STRENGTH: the pin will sink or source at most the current * passed as argument. The argument is in mA. + * @PIN_CONFIG_INPUT_ENABLE: enable the pin's input. Note that this does not + * affect the pin's ability to drive output. 1 enables input, 0 disables + * input. * @PIN_CONFIG_INPUT_SCHMITT_ENABLE: control schmitt-trigger mode on the pin. * If the argument != 0, schmitt-trigger mode is enabled. If it's 0, * schmitt-trigger mode is disabled. @@ -95,6 +98,7 @@ enum pin_config_param { PIN_CONFIG_DRIVE_OPEN_DRAIN, PIN_CONFIG_DRIVE_OPEN_SOURCE, PIN_CONFIG_DRIVE_STRENGTH, + PIN_CONFIG_INPUT_ENABLE, PIN_CONFIG_INPUT_SCHMITT_ENABLE, PIN_CONFIG_INPUT_SCHMITT, PIN_CONFIG_INPUT_DEBOUNCE, From 0f9f831b34c459e274134fdf9e9914c3abc4c854 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 6 Aug 2013 18:42:33 +0530 Subject: [PATCH 15/18] pinctrl: add utility functions for add map/configs Some of pincontrol driver needs the utility function to create map list. The utility function needed for adding mux, configs etc. In place of duplicating this in each driver, add the common utility function in common file and use from device specific driver. This will reduce the duplicating of code across drivers. Changes from V1: - Add this files in this patch and add common utility APIs to here. Changes from V2: - Nothing in code. - Added Reviewed by Stephen. Signed-off-by: Laxman Dewangan Reviewed-by: Stephen Warren Signed-off-by: Linus Walleij (cherry picked from commit 1eb207a9ecaafb980704d8bc055a9a0269f62f8e) Signed-off-by: Mark Brown --- drivers/pinctrl/Makefile | 2 +- drivers/pinctrl/pinctrl-utils.c | 135 ++++++++++++++++++++++++++++++++ drivers/pinctrl/pinctrl-utils.h | 43 ++++++++++ 3 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 drivers/pinctrl/pinctrl-utils.c create mode 100644 drivers/pinctrl/pinctrl-utils.h diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 9bdaeb8785ce..b32d6c798743 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -2,7 +2,7 @@ ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG -obj-$(CONFIG_PINCTRL) += core.o +obj-$(CONFIG_PINCTRL) += core.o pinctrl-utils.o obj-$(CONFIG_PINMUX) += pinmux.o obj-$(CONFIG_PINCONF) += pinconf.o ifeq ($(CONFIG_OF),y) diff --git a/drivers/pinctrl/pinctrl-utils.c b/drivers/pinctrl/pinctrl-utils.c new file mode 100644 index 000000000000..b7ac646c43ba --- /dev/null +++ b/drivers/pinctrl/pinctrl-utils.c @@ -0,0 +1,135 @@ +/* + * Utils functions to implement the pincontrol driver. + * + * Copyright (c) 2013, NVIDIA Corporation. + * + * Author: Laxman Dewangan + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ +#include +#include +#include +#include +#include +#include "core.h" +#include "pinctrl-utils.h" + +int pinctrl_utils_reserve_map(struct pinctrl_dev *pctldev, + struct pinctrl_map **map, unsigned *reserved_maps, + unsigned *num_maps, unsigned reserve) +{ + unsigned old_num = *reserved_maps; + unsigned new_num = *num_maps + reserve; + struct pinctrl_map *new_map; + + if (old_num >= new_num) + return 0; + + new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL); + if (!new_map) { + dev_err(pctldev->dev, "krealloc(map) failed\n"); + return -ENOMEM; + } + + memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map)); + + *map = new_map; + *reserved_maps = new_num; + return 0; +} +EXPORT_SYMBOL_GPL(pinctrl_utils_reserve_map); + +int pinctrl_utils_add_map_mux(struct pinctrl_dev *pctldev, + struct pinctrl_map **map, unsigned *reserved_maps, + unsigned *num_maps, const char *group, + const char *function) +{ + if (WARN_ON(*num_maps == *reserved_maps)) + return -ENOSPC; + + (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; + (*map)[*num_maps].data.mux.group = group; + (*map)[*num_maps].data.mux.function = function; + (*num_maps)++; + + return 0; +} +EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_mux); + +int pinctrl_utils_add_map_configs(struct pinctrl_dev *pctldev, + struct pinctrl_map **map, unsigned *reserved_maps, + unsigned *num_maps, const char *group, + unsigned long *configs, unsigned num_configs, + enum pinctrl_map_type type) +{ + unsigned long *dup_configs; + + if (WARN_ON(*num_maps == *reserved_maps)) + return -ENOSPC; + + dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs), + GFP_KERNEL); + if (!dup_configs) { + dev_err(pctldev->dev, "kmemdup(configs) failed\n"); + return -ENOMEM; + } + + (*map)[*num_maps].type = type; + (*map)[*num_maps].data.configs.group_or_pin = group; + (*map)[*num_maps].data.configs.configs = dup_configs; + (*map)[*num_maps].data.configs.num_configs = num_configs; + (*num_maps)++; + + return 0; +} +EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_configs); + +int pinctrl_utils_add_config(struct pinctrl_dev *pctldev, + unsigned long **configs, unsigned *num_configs, + unsigned long config) +{ + unsigned old_num = *num_configs; + unsigned new_num = old_num + 1; + unsigned long *new_configs; + + new_configs = krealloc(*configs, sizeof(*new_configs) * new_num, + GFP_KERNEL); + if (!new_configs) { + dev_err(pctldev->dev, "krealloc(configs) failed\n"); + return -ENOMEM; + } + + new_configs[old_num] = config; + + *configs = new_configs; + *num_configs = new_num; + + return 0; +} +EXPORT_SYMBOL_GPL(pinctrl_utils_add_config); + +void pinctrl_utils_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + int i; + + for (i = 0; i < num_maps; i++) + if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP) + kfree(map[i].data.configs.configs); + + kfree(map); +} +EXPORT_SYMBOL_GPL(pinctrl_utils_dt_free_map); diff --git a/drivers/pinctrl/pinctrl-utils.h b/drivers/pinctrl/pinctrl-utils.h new file mode 100644 index 000000000000..d0ffe1ce200f --- /dev/null +++ b/drivers/pinctrl/pinctrl-utils.h @@ -0,0 +1,43 @@ +/* + * Utils functions to implement the pincontrol driver. + * + * Copyright (c) 2013, NVIDIA Corporation. + * + * Author: Laxman Dewangan + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ +#ifndef __PINCTRL_UTILS_H__ +#define __PINCTRL_UTILS_H__ + +int pinctrl_utils_reserve_map(struct pinctrl_dev *pctldev, + struct pinctrl_map **map, unsigned *reserved_maps, + unsigned *num_maps, unsigned reserve); +int pinctrl_utils_add_map_mux(struct pinctrl_dev *pctldev, + struct pinctrl_map **map, unsigned *reserved_maps, + unsigned *num_maps, const char *group, + const char *function); +int pinctrl_utils_add_map_configs(struct pinctrl_dev *pctldev, + struct pinctrl_map **map, unsigned *reserved_maps, + unsigned *num_maps, const char *group, + unsigned long *configs, unsigned num_configs, + enum pinctrl_map_type type); +int pinctrl_utils_add_config(struct pinctrl_dev *pctldev, + unsigned long **configs, unsigned *num_configs, + unsigned long config); +void pinctrl_utils_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps); + +#endif /* __PINCTRL_UTILS_H__ */ From edfee6033b566c1985b1d56129140733a1c599d1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 15 Aug 2013 21:38:49 +0200 Subject: [PATCH 16/18] pinctrl: add includes and ifdefs for non-DT builds Commit e81c8f18afc4fdd6e34d8c83814b8b5134dbb30f "pinctrl: pinconf-generic: add generic APIs for mapping pinctrl node" Added function prototypes with implicit dependencies on other header files causing build warnings like this: In file included from arch/arm/mach-ux500/board-mop500-pins.c:12:0: include/linux/pinctrl/pinconf-generic.h:142:3: warning: 'struct device_node' declared inside parameter list [enabled by default] unsigned *reserved_maps, unsigned *num_maps); ^ include/linux/pinctrl/pinconf-generic.h:142:3: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default] include/linux/pinctrl/pinconf-generic.h:142:3: warning: 'struct pinctrl_dev' declared inside parameter list [enabled by default] include/linux/pinctrl/pinconf-generic.h:145:3: warning: 'struct device_node' declared inside parameter list [enabled by default] unsigned *num_maps); ^ Let's just add ifdefs for non-DT systems (the actual code is already ifdefed) and #include to get the most important structs and forward-declare the pinctrl core structs. Reported-by: Olof Johansson Cc: Laxman Dewangan Signed-off-by: Linus Walleij (cherry picked from commit 0d74d4a161c9f9870039af414b712552c0ed6dfb) Signed-off-by: Mark Brown --- include/linux/pinctrl/pinconf-generic.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index 006e7bfe773d..447269672e2c 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -137,12 +137,21 @@ static inline unsigned long pinconf_to_config_packed(enum pin_config_param param return PIN_CONF_PACKED(param, argument); } +#ifdef CONFIG_OF + +#include +struct pinctrl_dev; +struct pinctrl_map; + 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); int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, unsigned *num_maps); + +#endif + #endif /* CONFIG_GENERIC_PINCONF */ #endif /* __LINUX_PINCTRL_PINCONF_GENERIC_H */ From baeae2041e14d5b7a272b9941b88fb56d716f643 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 4 Apr 2014 17:16:57 +0100 Subject: [PATCH 17/18] pinctrl: Pass all configs to driver on pin_config_set() When setting pin configuration in the pinctrl framework, pin_config_set() or pin_config_group_set() is called in a loop to set one configuration at a time for the specified pin or group. This patch 1) removes the loop and 2) changes the API to pass the whole pin config array to the driver. It is now up to the driver to loop through the configs. This allows the driver to potentially combine configs and reduce the number of writes to pin config registers. All c files changed have been build-tested to verify the change compiles and that the corresponding .o is successfully generated. [For LSK this has been modified such that the old API is still present and instead a new pinconf_set_bulk() callback has been added in order to avoid breaking other users in the stable kernel -- broonie] Signed-off-by: Sherman Yin Reviewed-by: Christian Daudt Reviewed-by: Matt Porter Tested-by: Stephen Warren Acked-by: Laurent Pinchart Signed-off-by: Linus Walleij (cherry picked from commit 03b054e9696c3cbd3d5905ec96da15acd0a2fe8d) Signed-off-by: Mark Brown --- drivers/pinctrl/pinconf.c | 55 ++++++++++++++++++++++++--------- include/linux/pinctrl/pinconf.h | 8 +++++ 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index e875f21a5908..ad30263a7410 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -158,7 +158,7 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting) { struct pinctrl_dev *pctldev = setting->pctldev; const struct pinconf_ops *ops = pctldev->desc->confops; - int i, ret; + int ret, i; if (!ops) { dev_err(pctldev->dev, "missing confops\n"); @@ -167,39 +167,66 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting) switch (setting->type) { case PIN_MAP_TYPE_CONFIGS_PIN: - if (!ops->pin_config_set) { + if (!ops->pin_config_set && !ops->pin_config_set_bulk) { dev_err(pctldev->dev, "missing pin_config_set op\n"); return -EINVAL; } - for (i = 0; i < setting->data.configs.num_configs; i++) { - ret = ops->pin_config_set(pctldev, + if (ops->pin_config_group_set_bulk) { + ret = ops->pin_config_group_set_bulk(pctldev, setting->data.configs.group_or_pin, - setting->data.configs.configs[i]); + setting->data.configs.configs, + setting->data.configs.num_configs); if (ret < 0) { dev_err(pctldev->dev, - "pin_config_set op failed for pin %d config %08lx\n", - setting->data.configs.group_or_pin, - setting->data.configs.configs[i]); + "pin_config_set op failed for pin %d\n", + setting->data.configs.group_or_pin); return ret; } + } else if (ops->pin_config_set) { + for (i = 0; i < setting->data.configs.num_configs; i++) { + ret = ops->pin_config_set(pctldev, + setting->data.configs.group_or_pin, + setting->data.configs.configs[i]); + if (ret < 0) { + dev_err(pctldev->dev, + "pin_config_set op failed for pin %d config %08lx\n", + setting->data.configs.group_or_pin, + setting->data.configs.configs[i]); + return ret; + } + } } break; case PIN_MAP_TYPE_CONFIGS_GROUP: - if (!ops->pin_config_group_set) { + if (!ops->pin_config_group_set && + !ops->pin_config_group_set_bulk) { dev_err(pctldev->dev, "missing pin_config_group_set op\n"); return -EINVAL; } - for (i = 0; i < setting->data.configs.num_configs; i++) { - ret = ops->pin_config_group_set(pctldev, + if (ops->pin_config_group_set_bulk) { + ret = ops->pin_config_group_set_bulk(pctldev, setting->data.configs.group_or_pin, - setting->data.configs.configs[i]); + setting->data.configs.configs, + setting->data.configs.num_configs); if (ret < 0) { dev_err(pctldev->dev, - "pin_config_group_set op failed for group %d config %08lx\n", + "pin_config_group_set op failed for group %d\n", + setting->data.configs.group_or_pin); + return ret; + } + } else if (ops->pin_config_group_set) { + for (i = 0; i < setting->data.configs.num_configs; i++) { + ret = ops->pin_config_group_set(pctldev, setting->data.configs.group_or_pin, setting->data.configs.configs[i]); - return ret; + if (ret < 0) { + dev_err(pctldev->dev, + "pin_config_group_set op failed for group %d config %08lx\n", + setting->data.configs.group_or_pin, + setting->data.configs.configs[i]); + return ret; + } } } break; diff --git a/include/linux/pinctrl/pinconf.h b/include/linux/pinctrl/pinconf.h index 1ad4f31ef6b8..e6a68e476aef 100644 --- a/include/linux/pinctrl/pinconf.h +++ b/include/linux/pinctrl/pinconf.h @@ -48,12 +48,20 @@ struct pinconf_ops { int (*pin_config_set) (struct pinctrl_dev *pctldev, unsigned pin, unsigned long config); + int (*pin_config_set_bulk) (struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *configs, + unsigned num_configs); int (*pin_config_group_get) (struct pinctrl_dev *pctldev, unsigned selector, unsigned long *config); int (*pin_config_group_set) (struct pinctrl_dev *pctldev, unsigned selector, unsigned long config); + int (*pin_config_group_set_bulk) (struct pinctrl_dev *pctldev, + unsigned selector, + unsigned long *configs, + unsigned num_configs); int (*pin_config_dbg_parse_modify) (struct pinctrl_dev *pctldev, const char *arg, unsigned long *config); From 270cfc4788befe0e1a16bf1b3a7b80d9f4127c57 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 4 Apr 2014 21:39:02 +0100 Subject: [PATCH 18/18] pinctrl: utils : add support to pass config type in generic util APIs Add support to pass the config type like GROUP or PIN when using the utils or generic pin configuration APIs. This will make the APIs more generic. Added additional inline APIs such that it can be use directly as callback for the pinctrl_ops. Changes from V1: - Remove separate implementation for pins and group for pinctrl_utils_dt_free_map and improve this function to support both i.e. PINS and GROUPs. [For LSK restore the original API and add a _new() variant of the functions for external consumption instead, maintaining the existing API -- broonie] Signed-off-by: Laxman Dewangan Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Linus Walleij (cherry-picked from commit 3287c24088abded9f111ca797fdd36f86912d199) Signed-off-by: Mark Brown --- drivers/pinctrl/pinconf-generic.c | 19 ++++++----- drivers/pinctrl/pinctrl-utils.c | 12 +++++-- include/linux/pinctrl/pinconf-generic.h | 45 ++++++++++++++++++++++--- 3 files changed, 60 insertions(+), 16 deletions(-) diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index d54b877cb704..872e74a23788 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -242,9 +242,10 @@ out: return ret; } -int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, +int pinconf_generic_dt_subnode_to_map_new(struct pinctrl_dev *pctldev, struct device_node *np, struct pinctrl_map **map, - unsigned *reserved_maps, unsigned *num_maps) + unsigned *reserved_maps, unsigned *num_maps, + enum pinctrl_map_type type) { int ret; const char *function; @@ -298,7 +299,7 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, if (num_configs) { ret = pinctrl_utils_add_map_configs(pctldev, map, reserved_maps, num_maps, group, configs, - num_configs, PIN_MAP_TYPE_CONFIGS_PIN); + num_configs, type); if (ret < 0) goto exit; } @@ -309,11 +310,11 @@ exit: kfree(configs); return ret; } -EXPORT_SYMBOL_GPL(pinconf_generic_dt_subnode_to_map); +EXPORT_SYMBOL_GPL(pinconf_generic_dt_subnode_to_map_new); -int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev, +int pinconf_generic_dt_node_to_map_new(struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, - unsigned *num_maps) + unsigned *num_maps, enum pinctrl_map_type type) { unsigned reserved_maps; struct device_node *np; @@ -324,8 +325,8 @@ int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev, *num_maps = 0; for_each_child_of_node(np_config, np) { - ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map, - &reserved_maps, num_maps); + ret = pinconf_generic_dt_subnode_to_map_new(pctldev, np, map, + &reserved_maps, num_maps, type); if (ret < 0) { pinctrl_utils_dt_free_map(pctldev, *map, *num_maps); return ret; @@ -333,6 +334,6 @@ int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev, } return 0; } -EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map); +EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map_new); #endif diff --git a/drivers/pinctrl/pinctrl-utils.c b/drivers/pinctrl/pinctrl-utils.c index b7ac646c43ba..48277e025f84 100644 --- a/drivers/pinctrl/pinctrl-utils.c +++ b/drivers/pinctrl/pinctrl-utils.c @@ -126,10 +126,16 @@ void pinctrl_utils_dt_free_map(struct pinctrl_dev *pctldev, { int i; - for (i = 0; i < num_maps; i++) - if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP) + for (i = 0; i < num_maps; i++) { + switch (map[i].type) { + case PIN_MAP_TYPE_CONFIGS_GROUP: + case PIN_MAP_TYPE_CONFIGS_PIN: kfree(map[i].data.configs.configs); - + break; + default: + break; + } + } kfree(map); } EXPORT_SYMBOL_GPL(pinctrl_utils_dt_free_map); diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index 447269672e2c..201e68de2d11 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -140,15 +140,52 @@ static inline unsigned long pinconf_to_config_packed(enum pin_config_param param #ifdef CONFIG_OF #include +#include struct pinctrl_dev; struct pinctrl_map; -int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, +int pinconf_generic_dt_subnode_to_map_new(struct pinctrl_dev *pctldev, struct device_node *np, struct pinctrl_map **map, - unsigned *reserved_maps, unsigned *num_maps); -int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev, + unsigned *reserved_maps, unsigned *num_maps, + enum pinctrl_map_type type); +int pinconf_generic_dt_node_to_map_new(struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, - unsigned *num_maps); + unsigned *num_maps, enum pinctrl_map_type type); + +static inline int pinconf_generic_dt_node_to_map_group( + struct pinctrl_dev *pctldev, struct device_node *np_config, + struct pinctrl_map **map, unsigned *num_maps) +{ + return pinconf_generic_dt_node_to_map_new(pctldev, np_config, map, num_maps, + PIN_MAP_TYPE_CONFIGS_GROUP); +} + +static inline 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) +{ + return pinconf_generic_dt_subnode_to_map_new(pctldev, np, map, + reserved_maps, num_maps, + PIN_MAP_TYPE_CONFIGS_PIN); +} + +static inline int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, struct pinctrl_map **map, + unsigned *num_maps) +{ + return pinconf_generic_dt_node_to_map_new(pctldev, np_config, + map, num_maps, + PIN_MAP_TYPE_CONFIGS_PIN); +} + + +static inline int pinconf_generic_dt_node_to_map_pin( + struct pinctrl_dev *pctldev, struct device_node *np_config, + struct pinctrl_map **map, unsigned *num_maps) +{ + return pinconf_generic_dt_node_to_map_new(pctldev, np_config, map, num_maps, + PIN_MAP_TYPE_CONFIGS_PIN); +} #endif