Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dd4d01f7 authored by Soren Brinkmann's avatar Soren Brinkmann Committed by Linus Walleij
Browse files

pinctrl: pinconf-generic: Allow driver to specify DT params



Additionally to the generic DT parameters, allow drivers to provide
driver-specific DT parameters to be used with the generic parser
infrastructure.

To achieve this 'struct pinctrl_desc' is extended to pass custom pinconf
option to the core. In order to pass this kind of information, the
related data structures - 'struct pinconf_generic_dt_params',
'pin_config_item' - are moved from pinconf internals to the
pinconf-generic header.

Additionally pinconfg-generic is refactored to not only iterate over the
generic pinconf parameters but also take the parameters into account
that are provided through the driver's 'struct pinctrl_desc'.
In particular 'pinconf_generic_parse_dt_config()' and
'pinconf_generic_dump' helpers are split into two parts each. In order
to have a more generic helper that can be used to process the generic
parameters as well as the driver-specific ones.

v2:
 - fix typo
 - add missing documentation for @conf_items member in struct
 - rebase to pinctrl/devel: conflict in abx500
 - rename _pinconf_generic_dump() to pinconf_generic_dump_one()
 - removed '_' from _parse_dt_cfg()
 - removed BUG_ONs, error condition is handled in if statements
 - removed pinconf_generic_dump_group() & pinconf_generic_dump_pin
   helpers
   - fixed up corresponding call sites
   - renamed pinconf_generic_dump() to pinconf_generic_dump_pins()
   - added kernel-doc to pinconf_generic_dump_pins()
 - add kernel-doc
 - more verbose commit message

Signed-off-by: default avatarSoren Brinkmann <soren.brinkmann@xilinx.com>
Tested-by: default avatarAndreas Färber <afaerber@suse.de>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 31c89c95
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -914,7 +914,7 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev,
		}
		}
	}
	}


	ret = pinconf_generic_parse_dt_config(np, &configs, &nconfigs);
	ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, &nconfigs);
	if (nconfigs) {
	if (nconfigs) {
		const char *gpio_name;
		const char *gpio_name;
		const char *pin;
		const char *pin;
+100 −82
Original line number Original line Diff line number Diff line
@@ -27,17 +27,6 @@
#include "pinctrl-utils.h"
#include "pinctrl-utils.h"


#ifdef CONFIG_DEBUG_FS
#ifdef CONFIG_DEBUG_FS

struct pin_config_item {
	const enum pin_config_param param;
	const char * const display;
	const char * const format;
	bool has_arg;
};

#define PCONFDUMP(a, b, c, d) { .param = a, .display = b, .format = c, \
				.has_arg = d }

static const struct pin_config_item conf_items[] = {
static const struct pin_config_item conf_items[] = {
	PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL, false),
	PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL, false),
	PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL, false),
	PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL, false),
@@ -60,21 +49,24 @@ static const struct pin_config_item conf_items[] = {
	PCONFDUMP(PIN_CONFIG_OUTPUT, "pin output", "level", true),
	PCONFDUMP(PIN_CONFIG_OUTPUT, "pin output", "level", true),
};
};


void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev,
			      struct seq_file *s, unsigned pin)
				     struct seq_file *s, const char *gname,
				     unsigned pin,
				     const struct pin_config_item *items,
				     int nitems)
{
{
	const struct pinconf_ops *ops = pctldev->desc->confops;
	int i;
	int i;


	if (!ops->is_generic)
	for (i = 0; i < nitems; i++) {
		return;

	for (i = 0; i < ARRAY_SIZE(conf_items); i++) {
		unsigned long config;
		unsigned long config;
		int ret;
		int ret;


		/* We want to check out this parameter */
		/* We want to check out this parameter */
		config = pinconf_to_config_packed(conf_items[i].param, 0);
		config = pinconf_to_config_packed(items[i].param, 0);
		if (gname)
			ret = pin_config_group_get(dev_name(pctldev->dev),
						   gname, &config);
		else
			ret = pin_config_get_for_pin(pctldev, pin, &config);
			ret = pin_config_get_for_pin(pctldev, pin, &config);
		/* These are legal errors */
		/* These are legal errors */
		if (ret == -EINVAL || ret == -ENOTSUPP)
		if (ret == -EINVAL || ret == -ENOTSUPP)
@@ -85,56 +77,46 @@ void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
		}
		}
		/* Space between multiple configs */
		/* Space between multiple configs */
		seq_puts(s, " ");
		seq_puts(s, " ");
		seq_puts(s, conf_items[i].display);
		seq_puts(s, items[i].display);
		/* Print unit if available */
		/* Print unit if available */
		if (conf_items[i].has_arg) {
		if (items[i].has_arg) {
			seq_printf(s, " (%u",
			seq_printf(s, " (%u",
				   pinconf_to_config_argument(config));
				   pinconf_to_config_argument(config));
			if (conf_items[i].format)
			if (items[i].format)
				seq_printf(s, " %s)", conf_items[i].format);
				seq_printf(s, " %s)", items[i].format);
			else
			else
				seq_puts(s, ")");
				seq_puts(s, ")");
		}
		}
	}
	}
}
}


void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
/**
			      struct seq_file *s, const char *gname)
 * pinconf_generic_dump_pins - Print information about pin or group of pins
 * @pctldev:	Pincontrol device
 * @s:		File to print to
 * @gname:	Group name specifying pins
 * @pin:	Pin number specyfying pin
 *
 * Print the pinconf configuration for the requested pin(s) to @s. Pins can be
 * specified either by pin using @pin or by group using @gname. Only one needs
 * to be specified the other can be NULL/0.
 */
void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev, struct seq_file *s,
			       const char *gname, unsigned pin)
{
{
	const struct pinconf_ops *ops = pctldev->desc->confops;
	const struct pinconf_ops *ops = pctldev->desc->confops;
	int i;


	if (!ops->is_generic)
	if (!ops->is_generic)
		return;
		return;


	for (i = 0; i < ARRAY_SIZE(conf_items); i++) {
	/* generic parameters */
		unsigned long config;
	pinconf_generic_dump_one(pctldev, s, gname, pin, conf_items,
		int ret;
				 ARRAY_SIZE(conf_items));

	/* driver-specific parameters */
		/* We want to check out this parameter */
	if (pctldev->desc->num_dt_params && pctldev->desc->conf_items)
		config = pinconf_to_config_packed(conf_items[i].param, 0);
		pinconf_generic_dump_one(pctldev, s, gname, pin,
		ret = pin_config_group_get(dev_name(pctldev->dev), gname,
					 pctldev->desc->conf_items,
					   &config);
					 pctldev->desc->num_dt_params);
		/* 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].has_arg) {
			seq_printf(s, " (%u",
				   pinconf_to_config_argument(config));
			if (conf_items[i].format)
				seq_printf(s, " %s)", conf_items[i].format);
			else
				seq_puts(s, ")");
		}
	}
}
}


void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
@@ -148,17 +130,21 @@ void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
		seq_printf(s, "%s: 0x%x", conf_items[i].display,
		seq_printf(s, "%s: 0x%x", conf_items[i].display,
			   pinconf_to_config_argument(config));
			   pinconf_to_config_argument(config));
	}
	}

	if (!pctldev->desc->num_dt_params || !pctldev->desc->conf_items)
		return;

	for (i = 0; i < pctldev->desc->num_dt_params; i++) {
		if (pinconf_to_config_param(config) != pctldev->desc->conf_items[i].param)
			continue;
		seq_printf(s, "%s: 0x%x", pctldev->desc->conf_items[i].display,
			   pinconf_to_config_argument(config));
	}
}
}
EXPORT_SYMBOL_GPL(pinconf_generic_dump_config);
EXPORT_SYMBOL_GPL(pinconf_generic_dump_config);
#endif
#endif


#ifdef CONFIG_OF
#ifdef CONFIG_OF
struct pinconf_generic_dt_params {
	const char * const property;
	enum pin_config_param param;
	u32 default_value;
};

static const struct pinconf_generic_dt_params dt_params[] = {
static const struct pinconf_generic_dt_params dt_params[] = {
	{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
	{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
	{ "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
	{ "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
@@ -183,6 +169,47 @@ static const struct pinconf_generic_dt_params dt_params[] = {
	{ "slew-rate", PIN_CONFIG_SLEW_RATE, 0},
	{ "slew-rate", PIN_CONFIG_SLEW_RATE, 0},
};
};


/**
 * parse_dt_cfg - Parse DT pinconf parameters
 * @np:	DT node
 * @params:	Array of describing DT parameters
 * @count:	Number of entries in @params
 * @cfg:	Array of parsed config options
 * @ncfg:	Number of entries in @cfg
 *
 * Parse the config options described in @params from @np and puts the result
 * in @cfg. @cfg does not need to be empty, entries are added beggining at
 * @ncfg. @ncfg is updated to reflect the number of entries after parsing. @cfg
 * needs to have enough memory allocated to hold all possible entries.
 */
static void parse_dt_cfg(struct device_node *np,
			 const struct pinconf_generic_dt_params *params,
			 unsigned int count, unsigned long *cfg,
			 unsigned int *ncfg)
{
	int i;

	for (i = 0; i < count; i++) {
		u32 val;
		int ret;
		const struct pinconf_generic_dt_params *par = &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)++;
	}
}

/**
/**
 * pinconf_generic_parse_dt_config()
 * pinconf_generic_parse_dt_config()
 * parse the config properties into generic pinconfig values.
 * parse the config properties into generic pinconfig values.
@@ -191,39 +218,29 @@ static const struct pinconf_generic_dt_params dt_params[] = {
 * @nconfigs: umber of configurations
 * @nconfigs: umber of configurations
 */
 */
int pinconf_generic_parse_dt_config(struct device_node *np,
int pinconf_generic_parse_dt_config(struct device_node *np,
				    struct pinctrl_dev *pctldev,
				    unsigned long **configs,
				    unsigned long **configs,
				    unsigned int *nconfigs)
				    unsigned int *nconfigs)
{
{
	unsigned long *cfg;
	unsigned long *cfg;
	unsigned int ncfg = 0;
	unsigned int max_cfg, ncfg = 0;
	int ret;
	int ret;
	int i;
	u32 val;


	if (!np)
	if (!np)
		return -EINVAL;
		return -EINVAL;


	/* allocate a temporary array big enough to hold one of each option */
	/* allocate a temporary array big enough to hold one of each option */
	cfg = kzalloc(sizeof(*cfg) * ARRAY_SIZE(dt_params), GFP_KERNEL);
	max_cfg = ARRAY_SIZE(dt_params);
	if (pctldev)
		max_cfg += pctldev->desc->num_dt_params;
	cfg = kcalloc(max_cfg, sizeof(*cfg), GFP_KERNEL);
	if (!cfg)
	if (!cfg)
		return -ENOMEM;
		return -ENOMEM;


	for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
	parse_dt_cfg(np, dt_params, ARRAY_SIZE(dt_params), cfg, &ncfg);
		const struct pinconf_generic_dt_params *par = &dt_params[i];
	if (pctldev && pctldev->desc->num_dt_params && pctldev->desc->params)
		ret = of_property_read_u32(np, par->property, &val);
		parse_dt_cfg(np, pctldev->desc->params,

			      pctldev->desc->num_dt_params, cfg, &ncfg);
		/* 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++;
	}


	ret = 0;
	ret = 0;


@@ -274,7 +291,8 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,
		function = NULL;
		function = NULL;
	}
	}


	ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs);
	ret = pinconf_generic_parse_dt_config(np, pctldev, &configs,
					      &num_configs);
	if (ret < 0) {
	if (ret < 0) {
		dev_err(dev, "could not parse node property\n");
		dev_err(dev, "could not parse node property\n");
		return ret;
		return ret;
+2 −2
Original line number Original line Diff line number Diff line
@@ -288,7 +288,7 @@ static void pinconf_dump_pin(struct pinctrl_dev *pctldev,
	const struct pinconf_ops *ops = pctldev->desc->confops;
	const struct pinconf_ops *ops = pctldev->desc->confops;


	/* no-op when not using generic pin config */
	/* no-op when not using generic pin config */
	pinconf_generic_dump_pin(pctldev, s, pin);
	pinconf_generic_dump_pins(pctldev, s, NULL, pin);
	if (ops && ops->pin_config_dbg_show)
	if (ops && ops->pin_config_dbg_show)
		ops->pin_config_dbg_show(pctldev, s, pin);
		ops->pin_config_dbg_show(pctldev, s, pin);
}
}
@@ -333,7 +333,7 @@ static void pinconf_dump_group(struct pinctrl_dev *pctldev,
	const struct pinconf_ops *ops = pctldev->desc->confops;
	const struct pinconf_ops *ops = pctldev->desc->confops;


	/* no-op when not using generic pin config */
	/* no-op when not using generic pin config */
	pinconf_generic_dump_group(pctldev, s, gname);
	pinconf_generic_dump_pins(pctldev, s, gname, 0);
	if (ops && ops->pin_config_group_dbg_show)
	if (ops && ops->pin_config_group_dbg_show)
		ops->pin_config_group_dbg_show(pctldev, s, selector);
		ops->pin_config_group_dbg_show(pctldev, s, selector);
}
}
+7 −15
Original line number Original line Diff line number Diff line
@@ -92,26 +92,17 @@ static inline void pinconf_init_device_debugfs(struct dentry *devroot,


#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_DEBUG_FS)
#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_DEBUG_FS)


void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev,
			      struct seq_file *s, unsigned pin);
			       struct seq_file *s, const char *gname,

			       unsigned pin);
void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
			      struct seq_file *s, const char *gname);


void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
				 struct seq_file *s, unsigned long config);
				 struct seq_file *s, unsigned long config);
#else
#else


static inline void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
static inline void pinconf_generic_dump_pins(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,
					     struct seq_file *s,
					      const char *gname)
					     const char *gname, unsigned pin)
{
{
	return;
	return;
}
}
@@ -126,6 +117,7 @@ static inline void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,


#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_OF)
#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_OF)
int pinconf_generic_parse_dt_config(struct device_node *np,
int pinconf_generic_parse_dt_config(struct device_node *np,
				    struct pinctrl_dev *pctldev,
				    unsigned long **configs,
				    unsigned long **configs,
				    unsigned int *nconfigs);
				    unsigned int *nconfigs);
#endif
#endif
+1 −1
Original line number Original line Diff line number Diff line
@@ -1140,7 +1140,7 @@ static int rockchip_pinctrl_parse_groups(struct device_node *np,
			return -EINVAL;
			return -EINVAL;


		np_config = of_find_node_by_phandle(be32_to_cpup(phandle));
		np_config = of_find_node_by_phandle(be32_to_cpup(phandle));
		ret = pinconf_generic_parse_dt_config(np_config,
		ret = pinconf_generic_parse_dt_config(np_config, NULL,
				&grp->data[j].configs, &grp->data[j].nconfigs);
				&grp->data[j].configs, &grp->data[j].nconfigs);
		if (ret)
		if (ret)
			return ret;
			return ret;
Loading