diff options
| -rw-r--r-- | drivers/pinctrl/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/pinctrl/Makefile | 1 | ||||
| -rw-r--r-- | drivers/pinctrl/pinconf-generic.c | 120 | ||||
| -rw-r--r-- | drivers/pinctrl/pinconf.c | 6 | ||||
| -rw-r--r-- | drivers/pinctrl/pinconf.h | 43 | ||||
| -rw-r--r-- | include/linux/pinctrl/pinconf-generic.h | 114 | ||||
| -rw-r--r-- | include/linux/pinctrl/pinconf.h | 5 | 
7 files changed, 289 insertions, 4 deletions
| diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index c6d29ff61d7e..07f3d8d38580 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -17,6 +17,10 @@ config PINMUX  config PINCONF  	bool "Support pin configuration controllers" +config GENERIC_PINCONF +	bool +	select PINCONF +  config DEBUG_PINCTRL  	bool "Debug PINCTRL calls"  	depends on DEBUG_KERNEL diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 754329b9c611..6d4150b4eced 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -5,6 +5,7 @@ ccflags-$(CONFIG_DEBUG_PINCTRL)	+= -DDEBUG  obj-$(CONFIG_PINCTRL)		+= core.o  obj-$(CONFIG_PINMUX)		+= pinmux.o  obj-$(CONFIG_PINCONF)		+= pinconf.o +obj-$(CONFIG_GENERIC_PINCONF)	+= pinconf-generic.o  obj-$(CONFIG_PINCTRL_PXA3xx)	+= pinctrl-pxa3xx.o  obj-$(CONFIG_PINCTRL_MMP2)	+= pinctrl-mmp2.o  obj-$(CONFIG_PINCTRL_PXA168)	+= pinctrl-pxa168.o diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c new file mode 100644 index 000000000000..33fbaeaa65dd --- /dev/null +++ b/drivers/pinctrl/pinconf-generic.c @@ -0,0 +1,120 @@ +/* + * Core driver for the generic pin config portions of the pin control subsystem + * + * Copyright (C) 2011 ST-Ericsson SA + * Written on behalf of Linaro for ST-Ericsson + * + * Author: Linus Walleij <linus.walleij@linaro.org> + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#define pr_fmt(fmt) "generic pinconfig core: " fmt + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinconf-generic.h> +#include "core.h" +#include "pinconf.h" + +#ifdef CONFIG_DEBUG_FS + +struct pin_config_item { +	const enum pin_config_param param; +	const char * const display; +	const char * const format; +}; + +#define PCONFDUMP(a, b, c) { .param = a, .display = b, .format = c } + +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_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), +	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_INPUT_SCHMITT, "input schmitt trigger", NULL), +	PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "time units"), +	PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector"), +	PCONFDUMP(PIN_CONFIG_LOW_POWER_MODE, "pin low power", "mode"), +}; + +void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, +			      struct seq_file *s, unsigned pin) +{ +	const struct pinconf_ops *ops = pctldev->desc->confops; +	int i; + +	if (!ops->is_generic) +		return; + +	for(i = 0; i < ARRAY_SIZE(conf_items); i++) { +		unsigned long config; +		int ret; + +		/* We want to check out this parameter */ +		config = pinconf_to_config_packed(conf_items[i].param, 0); +		ret = pin_config_get_for_pin(pctldev, pin, &config); +		/* These are legal errors */ +		if (ret == -EINVAL || ret == -ENOTSUPP) +			continue; +		if (ret) { +			seq_printf(s, "ERROR READING CONFIG SETTING %d ", i); +			continue; +		} +		/* Space between multiple configs */ +		seq_puts(s, " "); +		seq_puts(s, conf_items[i].display); +		/* Print unit if available */ +		if (conf_items[i].format && +		    pinconf_to_config_argument(config) != 0) +			seq_printf(s, " (%u %s)", +				   pinconf_to_config_argument(config), +				   conf_items[i].format); +	} +} + +void pinconf_generic_dump_group(struct pinctrl_dev *pctldev, +			      struct seq_file *s, const char *gname) +{ +	const struct pinconf_ops *ops = pctldev->desc->confops; +	int i; + +	if (!ops->is_generic) +		return; + +	for(i = 0; i < ARRAY_SIZE(conf_items); i++) { +		unsigned long config; +		int ret; + +		/* We want to check out this parameter */ +		config = pinconf_to_config_packed(conf_items[i].param, 0); +		ret = pin_config_group_get(dev_name(pctldev->dev), gname, +					   &config); +		/* These are legal errors */ +		if (ret == -EINVAL || ret == -ENOTSUPP) +			continue; +		if (ret) { +			seq_printf(s, "ERROR READING CONFIG SETTING %d ", i); +			continue; +		} +		/* Space between multiple configs */ +		seq_puts(s, " "); +		seq_puts(s, conf_items[i].display); +		/* Print unit if available */ +		if (conf_items[i].format && config != 0) +			seq_printf(s, " (%u %s)", +				   pinconf_to_config_argument(config), +				   conf_items[i].format); +	} +} + +#endif diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index b40ac1b4fb17..7321e8601294 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -54,7 +54,7 @@ int pinconf_validate_map(struct pinctrl_map const *map, int i)  	return 0;  } -static int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin, +int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin,  			   unsigned long *config)  {  	const struct pinconf_ops *ops = pctldev->desc->confops; @@ -439,6 +439,8 @@ static void pinconf_dump_pin(struct pinctrl_dev *pctldev,  {  	const struct pinconf_ops *ops = pctldev->desc->confops; +	/* no-op when not using generic pin config */ +	pinconf_generic_dump_pin(pctldev, s, pin);  	if (ops && ops->pin_config_dbg_show)  		ops->pin_config_dbg_show(pctldev, s, pin);  } @@ -482,6 +484,8 @@ static void pinconf_dump_group(struct pinctrl_dev *pctldev,  {  	const struct pinconf_ops *ops = pctldev->desc->confops; +	/* no-op when not using generic pin config */ +	pinconf_generic_dump_group(pctldev, s, gname);  	if (ops && ops->pin_config_group_dbg_show)  		ops->pin_config_group_dbg_show(pctldev, s, selector);  } diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h index 0ded227661a5..54510de5e8c6 100644 --- a/drivers/pinctrl/pinconf.h +++ b/drivers/pinctrl/pinconf.h @@ -14,20 +14,26 @@  #ifdef CONFIG_PINCONF  int pinconf_check_ops(struct pinctrl_dev *pctldev); -  int pinconf_validate_map(struct pinctrl_map const *map, int i); -  int pinconf_map_to_setting(struct pinctrl_map const *map,  			  struct pinctrl_setting *setting);  void pinconf_free_setting(struct pinctrl_setting const *setting);  int pinconf_apply_setting(struct pinctrl_setting const *setting); -  void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map);  void pinconf_show_setting(struct seq_file *s,  			  struct pinctrl_setting const *setting);  void pinconf_init_device_debugfs(struct dentry *devroot,  				 struct pinctrl_dev *pctldev); +/* + * You will only be interested in these if you're using PINCONF + * so don't supply any stubs for these. + */ +int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin, +			   unsigned long *config); +int pin_config_group_get(const char *dev_name, const char *pin_group, +			 unsigned long *config); +  #else  static inline int pinconf_check_ops(struct pinctrl_dev *pctldev) @@ -71,3 +77,34 @@ static inline void pinconf_init_device_debugfs(struct dentry *devroot,  }  #endif + +/* + * The following functions are available if the driver uses the generic + * pin config. + */ + +#ifdef CONFIG_GENERIC_PINCONF + +void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, +			      struct seq_file *s, unsigned pin); + +void pinconf_generic_dump_group(struct pinctrl_dev *pctldev, +			      struct seq_file *s, const char *gname); + +#else + +static inline void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, +					    struct seq_file *s, +					    unsigned pin) +{ +	return; +} + +static inline void pinconf_generic_dump_group(struct pinctrl_dev *pctldev, +					      struct seq_file *s, +					      const char *gname) +{ +	return; +} + +#endif diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h new file mode 100644 index 000000000000..4f0abb9f1c09 --- /dev/null +++ b/include/linux/pinctrl/pinconf-generic.h @@ -0,0 +1,114 @@ +/* + * Interface the generic pinconfig portions of the pinctrl subsystem + * + * Copyright (C) 2011 ST-Ericsson SA + * Written on behalf of Linaro for ST-Ericsson + * This interface is used in the core to keep track of pins. + * + * Author: Linus Walleij <linus.walleij@linaro.org> + * + * License terms: GNU General Public License (GPL) version 2 + */ +#ifndef __LINUX_PINCTRL_PINCONF_GENERIC_H +#define __LINUX_PINCTRL_PINCONF_GENERIC_H + +/* + * You shouldn't even be able to compile with these enums etc unless you're + * using generic pin config. That is why this is defined out. + */ +#ifdef CONFIG_GENERIC_PINCONF + +/** + * enum pin_config_param - possible pin configuration parameters + * @PIN_CONFIG_BIAS_DISABLE: disable any pin bias on the pin, a + *	transition from say pull-up to pull-down implies that you disable + *	pull-up in the process, this setting disables all biasing. + * @PIN_CONFIG_BIAS_HIGH_IMPEDANCE: the pin will be set to a high impedance + *	mode, also know as "third-state" (tristate) or "high-Z" or "floating". + *	On output pins this effectively disconnects the pin, which is useful + *	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_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. + * @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_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. Sending this config will enabale + *	push-pull mode, the argument is ignored. + * @PIN_CONFIG_DRIVE_OPEN_DRAIN: the pin will be driven with open drain (open + *	collector) which means it is usually wired with other output ports + *	which are then pulled up with an external resistor. Sending this + *	config will enabale open drain mode, the argument is ignored. + * @PIN_CONFIG_DRIVE_OPEN_SOURCE: the pin will be driven with open source + *	(open emitter). Sending this config will enabale open drain mode, the + *	argument is ignored. + * @PIN_CONFIG_INPUT_SCHMITT: this will configure an input pin to run in + *	schmitt-trigger mode. If the schmitt-trigger has adjustable hysteresis, + *	the threshold value is given on a custom format as argument when + *	setting pins to this mode. The argument zero turns the schmitt trigger + *	off. + * @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 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 + *	the driver which alternative power source to use. + * @PIN_CONFIG_LOW_POWER_MODE: this will configure the pin for low power + *	operation, if several modes of operation are supported these can be + *	passed in the argument on a custom form, else just use argument 1 + *	to indicate low power mode, argument 0 turns low power mode off. + * @PIN_CONFIG_END: this is the last enumerator for pin configurations, if + *	you need to pass in custom configurations to the pin controller, use + *	PIN_CONFIG_END+1 as the base offset. + */ +enum pin_config_param { +	PIN_CONFIG_BIAS_DISABLE, +	PIN_CONFIG_BIAS_HIGH_IMPEDANCE, +	PIN_CONFIG_BIAS_PULL_UP, +	PIN_CONFIG_BIAS_PULL_DOWN, +	PIN_CONFIG_DRIVE_PUSH_PULL, +	PIN_CONFIG_DRIVE_OPEN_DRAIN, +	PIN_CONFIG_DRIVE_OPEN_SOURCE, +	PIN_CONFIG_INPUT_SCHMITT, +	PIN_CONFIG_INPUT_DEBOUNCE, +	PIN_CONFIG_POWER_SOURCE, +	PIN_CONFIG_LOW_POWER_MODE, +	PIN_CONFIG_END = 0x7FFF, +}; + +/* + * Helpful configuration macro to be used in tables etc. + */ +#define PIN_CONF_PACKED(p, a) ((a << 16) | ((unsigned long) p & 0xffffUL)) + +/* + * The following inlines stuffs a configuration parameter and data value + * into and out of an unsigned long argument, as used by the generic pin config + * system. We put the parameter in the lower 16 bits and the argument in the + * upper 16 bits. + */ + +static inline enum pin_config_param pinconf_to_config_param(unsigned long config) +{ +	return (enum pin_config_param) (config & 0xffffUL); +} + +static inline u16 pinconf_to_config_argument(unsigned long config) +{ +	return (enum pin_config_param) ((config >> 16) & 0xffffUL); +} + +static inline unsigned long pinconf_to_config_packed(enum pin_config_param param, +						     u16 argument) +{ +	return PIN_CONF_PACKED(param, argument); +} + +#endif /* CONFIG_GENERIC_PINCONF */ + +#endif /* __LINUX_PINCTRL_PINCONF_GENERIC_H */ diff --git a/include/linux/pinctrl/pinconf.h b/include/linux/pinctrl/pinconf.h index f8cf156873d7..ec431f03362d 100644 --- a/include/linux/pinctrl/pinconf.h +++ b/include/linux/pinctrl/pinconf.h @@ -20,6 +20,8 @@ struct seq_file;  /**   * struct pinconf_ops - pin config operations, to be implemented by   * pin configuration capable drivers. + * @is_generic: for pin controllers that want to use the generic interface, + *	this flag tells the framework that it's generic.   * @pin_config_get: get the config of a certain pin, if the requested config   *	is not available on this controller this should return -ENOTSUPP   *	and if it is available but disabled it should return -EINVAL @@ -33,6 +35,9 @@ struct seq_file;   *	per-device info for a certain group in debugfs   */  struct pinconf_ops { +#ifdef CONFIG_GENERIC_PINCONF +	bool is_generic; +#endif  	int (*pin_config_get) (struct pinctrl_dev *pctldev,  			       unsigned pin,  			       unsigned long *config); | 
