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

Commit 1e2082b5 authored by Stephen Warren's avatar Stephen Warren Committed by Linus Walleij
Browse files

pinctrl: enhance mapping table to support pin config operations



The pinctrl mapping table can now contain entries to:
* Set the mux function of a pin group
* Apply a set of pin config options to a pin or a group

This allows pinctrl_select_state() to apply pin configs settings as well
as mux settings.

v3: Fix find_pinctrl() to iterate over the correct list.
   s/_MUX_CONFIGS_/_CONFIGS_/ in mapping table macros.
   Fix documentation to use correct mapping table macro.
v2: Added numerous extra PIN_MAP_*() special-case macros.
   Fixed kerneldoc typo. Delete pinctrl_get_pin_id() and
   replace it with pin_get_from_name(). Various minor fixes.
   Updates due to rebase.

Signed-off-by: default avatarStephen Warren <swarren@nvidia.com>
Acked-by: default avatarDong Aisheng <dong.aisheng@linaro.org>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 6e5e959d
Loading
Loading
Loading
Loading
+64 −12
Original line number Original line Diff line number Diff line
@@ -206,14 +206,21 @@ 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
stable value when nothing is driving the rail it is connected to, or when it's
unconnected.
unconnected.


For example, a platform may do this:
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 <linux/pinctrl/consumer.h>
#include <linux/pinctrl/consumer.h>


ret = pin_config_set("foo-dev", "FOO_GPIO_PIN", PLATFORM_X_PULL_UP);
ret = pin_config_set("foo-dev", "FOO_GPIO_PIN", PLATFORM_X_PULL_UP);


To pull up a pin to VDD. The pin configuration driver implements callbacks for
The format and meaning of the configuration parameter, PLATFORM_X_PULL_UP
changing pin configuration in the pin controller ops like this:
above, is entirely defined by the pin controller driver.

The pin configuration driver implements callbacks for changing pin
configuration in the pin controller ops like this:


#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf.h>
@@ -765,7 +772,7 @@ obtain the function "gpioN" where "N" is the global GPIO pin number if no
special GPIO-handler is registered.
special GPIO-handler is registered.




Pinmux board/machine configuration
Board/machine configuration
==================================
==================================


Boards and machines define how a certain complete running system is put
Boards and machines define how a certain complete running system is put
@@ -773,9 +780,9 @@ together, including how GPIOs and devices are muxed, how regulators are
constrained and how the clock tree looks. Of course pinmux settings are also
constrained and how the clock tree looks. Of course pinmux settings are also
part of this.
part of this.


A pinmux config for a machine looks pretty much like a simple regulator
A pin controller configuration for a machine looks pretty much like a simple
configuration, so for the example array above we want to enable i2c and
regulator configuration, so for the example array above we want to enable i2c
spi on the second function mapping:
and spi on the second function mapping:


#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/machine.h>


@@ -783,20 +790,23 @@ static const struct pinctrl_map __initdata mapping[] = {
	{
	{
		.dev_name = "foo-spi.0",
		.dev_name = "foo-spi.0",
		.name = PINCTRL_STATE_DEFAULT,
		.name = PINCTRL_STATE_DEFAULT,
		.type = PIN_MAP_TYPE_MUX_GROUP,
		.ctrl_dev_name = "pinctrl-foo",
		.ctrl_dev_name = "pinctrl-foo",
		.function = "spi0",
		.data.mux.function = "spi0",
	},
	},
	{
	{
		.dev_name = "foo-i2c.0",
		.dev_name = "foo-i2c.0",
		.name = PINCTRL_STATE_DEFAULT,
		.name = PINCTRL_STATE_DEFAULT,
		.type = PIN_MAP_TYPE_MUX_GROUP,
		.ctrl_dev_name = "pinctrl-foo",
		.ctrl_dev_name = "pinctrl-foo",
		.function = "i2c0",
		.data.mux.function = "i2c0",
	},
	},
	{
	{
		.dev_name = "foo-mmc.0",
		.dev_name = "foo-mmc.0",
		.name = PINCTRL_STATE_DEFAULT,
		.name = PINCTRL_STATE_DEFAULT,
		.type = PIN_MAP_TYPE_MUX_GROUP,
		.ctrl_dev_name = "pinctrl-foo",
		.ctrl_dev_name = "pinctrl-foo",
		.function = "mmc0",
		.data.mux.function = "mmc0",
	},
	},
};
};


@@ -817,7 +827,40 @@ it even more compact which assumes you want to use pinctrl-foo and position
0 for mapping, for example:
0 for mapping, for example:


static struct pinctrl_map __initdata mapping[] = {
static struct pinctrl_map __initdata mapping[] = {
	PIN_MAP(PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0", "foo-i2c.0"),
	PIN_MAP_MUX_GROUP("foo-i2c.o", PINCTRL_STATE_DEFAULT, "pinctrl-foo", NULL, "i2c0"),
};

The mapping table may also contain pin configuration entries. It's common for
each pin/group to have a number of configuration entries that affect it, so
the table entries for configuration reference an array of config parameters
and values. An example using the convenience macros is shown below:

static unsigned long i2c_grp_configs[] = {
	FOO_PIN_DRIVEN,
	FOO_PIN_PULLUP,
};

static unsigned long i2c_pin_configs[] = {
	FOO_OPEN_COLLECTOR,
	FOO_SLEW_RATE_SLOW,
};

static struct pinctrl_map __initdata mapping[] = {
	PIN_MAP_MUX_GROUP("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0", "i2c0"),
	PIN_MAP_MUX_CONFIGS_GROUP("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0", i2c_grp_configs),
	PIN_MAP_MUX_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0scl", i2c_pin_configs),
	PIN_MAP_MUX_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0sda", i2c_pin_configs),
};

Finally, some devices expect the mapping table to contain certain specific
named states. When running on hardware that doesn't need any pin controller
configuration, the mapping table must still contain those named states, in
order to explicitly indicate that the states were provided and intended to
be empty. Table entry macro PIN_MAP_DUMMY_STATE serves the purpose of defining
a named state without causing any pin controller to be programmed:

static struct pinctrl_map __initdata mapping[] = {
	PIN_MAP_DUMMY_STATE("foo-i2c.0", PINCTRL_STATE_DEFAULT),
};
};




@@ -831,6 +874,7 @@ As it is possible to map a function to different groups of pins an optional
{
{
	.dev_name = "foo-spi.0",
	.dev_name = "foo-spi.0",
	.name = "spi0-pos-A",
	.name = "spi0-pos-A",
	.type = PIN_MAP_TYPE_MUX_GROUP,
	.ctrl_dev_name = "pinctrl-foo",
	.ctrl_dev_name = "pinctrl-foo",
	.function = "spi0",
	.function = "spi0",
	.group = "spi0_0_grp",
	.group = "spi0_0_grp",
@@ -838,6 +882,7 @@ As it is possible to map a function to different groups of pins an optional
{
{
	.dev_name = "foo-spi.0",
	.dev_name = "foo-spi.0",
	.name = "spi0-pos-B",
	.name = "spi0-pos-B",
	.type = PIN_MAP_TYPE_MUX_GROUP,
	.ctrl_dev_name = "pinctrl-foo",
	.ctrl_dev_name = "pinctrl-foo",
	.function = "spi0",
	.function = "spi0",
	.group = "spi0_1_grp",
	.group = "spi0_1_grp",
@@ -857,6 +902,7 @@ case), we define a mapping like this:
{
{
	.dev_name = "foo-mmc.0",
	.dev_name = "foo-mmc.0",
	.name = "2bit"
	.name = "2bit"
	.type = PIN_MAP_TYPE_MUX_GROUP,
	.ctrl_dev_name = "pinctrl-foo",
	.ctrl_dev_name = "pinctrl-foo",
	.function = "mmc0",
	.function = "mmc0",
	.group = "mmc0_1_grp",
	.group = "mmc0_1_grp",
@@ -864,6 +910,7 @@ case), we define a mapping like this:
{
{
	.dev_name = "foo-mmc.0",
	.dev_name = "foo-mmc.0",
	.name = "4bit"
	.name = "4bit"
	.type = PIN_MAP_TYPE_MUX_GROUP,
	.ctrl_dev_name = "pinctrl-foo",
	.ctrl_dev_name = "pinctrl-foo",
	.function = "mmc0",
	.function = "mmc0",
	.group = "mmc0_1_grp",
	.group = "mmc0_1_grp",
@@ -871,6 +918,7 @@ case), we define a mapping like this:
{
{
	.dev_name = "foo-mmc.0",
	.dev_name = "foo-mmc.0",
	.name = "4bit"
	.name = "4bit"
	.type = PIN_MAP_TYPE_MUX_GROUP,
	.ctrl_dev_name = "pinctrl-foo",
	.ctrl_dev_name = "pinctrl-foo",
	.function = "mmc0",
	.function = "mmc0",
	.group = "mmc0_2_grp",
	.group = "mmc0_2_grp",
@@ -878,6 +926,7 @@ case), we define a mapping like this:
{
{
	.dev_name = "foo-mmc.0",
	.dev_name = "foo-mmc.0",
	.name = "8bit"
	.name = "8bit"
	.type = PIN_MAP_TYPE_MUX_GROUP,
	.ctrl_dev_name = "pinctrl-foo",
	.ctrl_dev_name = "pinctrl-foo",
	.function = "mmc0",
	.function = "mmc0",
	.group = "mmc0_1_grp",
	.group = "mmc0_1_grp",
@@ -885,6 +934,7 @@ case), we define a mapping like this:
{
{
	.dev_name = "foo-mmc.0",
	.dev_name = "foo-mmc.0",
	.name = "8bit"
	.name = "8bit"
	.type = PIN_MAP_TYPE_MUX_GROUP,
	.ctrl_dev_name = "pinctrl-foo",
	.ctrl_dev_name = "pinctrl-foo",
	.function = "mmc0",
	.function = "mmc0",
	.group = "mmc0_2_grp",
	.group = "mmc0_2_grp",
@@ -892,6 +942,7 @@ case), we define a mapping like this:
{
{
	.dev_name = "foo-mmc.0",
	.dev_name = "foo-mmc.0",
	.name = "8bit"
	.name = "8bit"
	.type = PIN_MAP_TYPE_MUX_GROUP,
	.ctrl_dev_name = "pinctrl-foo",
	.ctrl_dev_name = "pinctrl-foo",
	.function = "mmc0",
	.function = "mmc0",
	.group = "mmc0_3_grp",
	.group = "mmc0_3_grp",
@@ -1014,6 +1065,7 @@ to the pin controller device name, and the state name is PINCTRL_STATE_DEFAULT.
{
{
	.dev_name = "pinctrl-foo",
	.dev_name = "pinctrl-foo",
	.name = PINCTRL_STATE_DEFAULT,
	.name = PINCTRL_STATE_DEFAULT,
	.type = PIN_MAP_TYPE_MUX_GROUP,
	.ctrl_dev_name = "pinctrl-foo",
	.ctrl_dev_name = "pinctrl-foo",
	.function = "power_func",
	.function = "power_func",
},
},
@@ -1022,7 +1074,7 @@ Since it may be common to request the core to hog a few always-applicable
mux settings on the primary pin controller, there is a convenience macro for
mux settings on the primary pin controller, there is a convenience macro for
this:
this:


PIN_MAP_SYS_HOG("pinctrl-foo", "power_func")
PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-foo", NULL /* group */, "power_func")


This gives the exact same result as the above construction.
This gives the exact same result as the above construction.


+6 −6
Original line number Original line Diff line number Diff line
@@ -1608,13 +1608,13 @@ static struct platform_device dma_device = {
/* Pinmux settings */
/* Pinmux settings */
static struct pinctrl_map __initdata u300_pinmux_map[] = {
static struct pinctrl_map __initdata u300_pinmux_map[] = {
	/* anonymous maps for chip power and EMIFs */
	/* anonymous maps for chip power and EMIFs */
	PIN_MAP_SYS_HOG("pinctrl-u300", "power"),
	PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-u300", NULL, "power"),
	PIN_MAP_SYS_HOG("pinctrl-u300", "emif0"),
	PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-u300", NULL, "emif0"),
	PIN_MAP_SYS_HOG("pinctrl-u300", "emif1"),
	PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-u300", NULL, "emif1"),
	/* per-device maps for MMC/SD, SPI and UART */
	/* per-device maps for MMC/SD, SPI and UART */
	PIN_MAP(PINCTRL_STATE_DEFAULT, "pinctrl-u300", "mmc0", "mmci"),
	PIN_MAP_MUX_GROUP_DEFAULT("mmci",  "pinctrl-u300", NULL, "mmc0"),
	PIN_MAP(PINCTRL_STATE_DEFAULT, "pinctrl-u300", "spi0", "pl022"),
	PIN_MAP_MUX_GROUP_DEFAULT("pl022", "pinctrl-u300", NULL, "spi0"),
	PIN_MAP(PINCTRL_STATE_DEFAULT, "pinctrl-u300", "uart0", "uart0"),
	PIN_MAP_MUX_GROUP_DEFAULT("uart0", "pinctrl-u300", NULL, "uart0"),
};
};


struct u300_mux_hog {
struct u300_mux_hog {
+128 −26
Original line number Original line Diff line number Diff line
@@ -502,6 +502,9 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
	if (IS_ERR(state))
	if (IS_ERR(state))
		return PTR_ERR(state);
		return PTR_ERR(state);


	if (map->type == PIN_MAP_TYPE_DUMMY_STATE)
		return 0;

	setting = kzalloc(sizeof(*setting), GFP_KERNEL);
	setting = kzalloc(sizeof(*setting), GFP_KERNEL);
	if (setting == NULL) {
	if (setting == NULL) {
		dev_err(p->dev,
		dev_err(p->dev,
@@ -509,6 +512,8 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
		return -ENOMEM;
		return -ENOMEM;
	}
	}


	setting->type = map->type;

	setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
	setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
	if (setting->pctldev == NULL) {
	if (setting->pctldev == NULL) {
		dev_err(p->dev, "unknown pinctrl device %s in map entry",
		dev_err(p->dev, "unknown pinctrl device %s in map entry",
@@ -518,7 +523,18 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
		return -ENODEV;
		return -ENODEV;
	}
	}


	switch (map->type) {
	case PIN_MAP_TYPE_MUX_GROUP:
		ret = pinmux_map_to_setting(map, setting);
		ret = pinmux_map_to_setting(map, setting);
		break;
	case PIN_MAP_TYPE_CONFIGS_PIN:
	case PIN_MAP_TYPE_CONFIGS_GROUP:
		ret = pinconf_map_to_setting(map, setting);
		break;
	default:
		ret = -EINVAL;
		break;
	}
	if (ret < 0) {
	if (ret < 0) {
		kfree(setting);
		kfree(setting);
		return ret;
		return ret;
@@ -533,7 +549,7 @@ static struct pinctrl *find_pinctrl(struct device *dev)
{
{
	struct pinctrl *p;
	struct pinctrl *p;


	list_for_each_entry(p, &pinctrldev_list, node)
	list_for_each_entry(p, &pinctrl_list, node)
		if (p->dev == dev)
		if (p->dev == dev)
			return p;
			return p;


@@ -626,9 +642,19 @@ static void pinctrl_put_locked(struct pinctrl *p, bool inlist)


	list_for_each_entry_safe(state, n1, &p->states, node) {
	list_for_each_entry_safe(state, n1, &p->states, node) {
		list_for_each_entry_safe(setting, n2, &state->settings, node) {
		list_for_each_entry_safe(setting, n2, &state->settings, node) {
			switch (setting->type) {
			case PIN_MAP_TYPE_MUX_GROUP:
				if (state == p->state)
				if (state == p->state)
					pinmux_disable_setting(setting);
					pinmux_disable_setting(setting);
				pinmux_free_setting(setting);
				pinmux_free_setting(setting);
				break;
			case PIN_MAP_TYPE_CONFIGS_PIN:
			case PIN_MAP_TYPE_CONFIGS_GROUP:
				pinconf_free_setting(setting);
				break;
			default:
				break;
			}
			list_del(&setting->node);
			list_del(&setting->node);
			kfree(setting);
			kfree(setting);
		}
		}
@@ -703,9 +729,13 @@ static int pinctrl_select_state_locked(struct pinctrl *p,
		 */
		 */
		list_for_each_entry(setting, &p->state->settings, node) {
		list_for_each_entry(setting, &p->state->settings, node) {
			bool found = false;
			bool found = false;
			if (setting->type != PIN_MAP_TYPE_MUX_GROUP)
				continue;
			list_for_each_entry(setting2, &state->settings, node) {
			list_for_each_entry(setting2, &state->settings, node) {
				if (setting2->group_selector ==
				if (setting2->type != PIN_MAP_TYPE_MUX_GROUP)
						setting->group_selector) {
					continue;
				if (setting2->data.mux.group ==
						setting->data.mux.group) {
					found = true;
					found = true;
					break;
					break;
				}
				}
@@ -719,7 +749,18 @@ static int pinctrl_select_state_locked(struct pinctrl *p,


	/* Apply all the settings for the new state */
	/* Apply all the settings for the new state */
	list_for_each_entry(setting, &state->settings, node) {
	list_for_each_entry(setting, &state->settings, node) {
		switch (setting->type) {
		case PIN_MAP_TYPE_MUX_GROUP:
			ret = pinmux_enable_setting(setting);
			ret = pinmux_enable_setting(setting);
			break;
		case PIN_MAP_TYPE_CONFIGS_PIN:
		case PIN_MAP_TYPE_CONFIGS_GROUP:
			ret = pinconf_apply_setting(setting);
			break;
		default:
			ret = -EINVAL;
			break;
		}
		if (ret < 0) {
		if (ret < 0) {
			/* FIXME: Difficult to return to prev state */
			/* FIXME: Difficult to return to prev state */
			return ret;
			return ret;
@@ -756,33 +797,48 @@ EXPORT_SYMBOL_GPL(pinctrl_select_state);
int pinctrl_register_mappings(struct pinctrl_map const *maps,
int pinctrl_register_mappings(struct pinctrl_map const *maps,
			      unsigned num_maps)
			      unsigned num_maps)
{
{
	int i;
	int i, ret;
	struct pinctrl_maps *maps_node;
	struct pinctrl_maps *maps_node;


	pr_debug("add %d pinmux maps\n", num_maps);
	pr_debug("add %d pinmux maps\n", num_maps);


	/* First sanity check the new mapping */
	/* First sanity check the new mapping */
	for (i = 0; i < num_maps; i++) {
	for (i = 0; i < num_maps; i++) {
		if (!maps[i].dev_name) {
			pr_err("failed to register map %s (%d): no device given\n",
			       maps[i].name, i);
			return -EINVAL;
		}

		if (!maps[i].name) {
		if (!maps[i].name) {
			pr_err("failed to register map %d: no map name given\n",
			pr_err("failed to register map %d: no map name given\n",
			       i);
			       i);
			return -EINVAL;
			return -EINVAL;
		}
		}


		if (!maps[i].ctrl_dev_name) {
		if (maps[i].type != PIN_MAP_TYPE_DUMMY_STATE &&
				!maps[i].ctrl_dev_name) {
			pr_err("failed to register map %s (%d): no pin control device given\n",
			pr_err("failed to register map %s (%d): no pin control device given\n",
			       maps[i].name, i);
			       maps[i].name, i);
			return -EINVAL;
			return -EINVAL;
		}
		}


		if (!maps[i].function) {
		switch (maps[i].type) {
			pr_err("failed to register map %s (%d): no function ID given\n",
		case PIN_MAP_TYPE_DUMMY_STATE:
			       maps[i].name, i);
			break;
			return -EINVAL;
		case PIN_MAP_TYPE_MUX_GROUP:
		}
			ret = pinmux_validate_map(&maps[i], i);

			if (ret < 0)
		if (!maps[i].dev_name) {
				return 0;
			pr_err("failed to register map %s (%d): no device given\n",
			break;
		case PIN_MAP_TYPE_CONFIGS_PIN:
		case PIN_MAP_TYPE_CONFIGS_GROUP:
			ret = pinconf_validate_map(&maps[i], i);
			if (ret < 0)
				return 0;
			break;
		default:
			pr_err("failed to register map %s (%d): invalid type given\n",
			       maps[i].name, i);
			       maps[i].name, i);
			return -EINVAL;
			return -EINVAL;
		}
		}
@@ -934,6 +990,22 @@ static int pinctrl_devices_show(struct seq_file *s, void *what)
	return 0;
	return 0;
}
}


static inline const char *map_type(enum pinctrl_map_type type)
{
	static const char * const names[] = {
		"INVALID",
		"DUMMY_STATE",
		"MUX_GROUP",
		"CONFIGS_PIN",
		"CONFIGS_GROUP",
	};

	if (type >= ARRAY_SIZE(names))
		return "UNKNOWN";

	return names[type];
}

static int pinctrl_maps_show(struct seq_file *s, void *what)
static int pinctrl_maps_show(struct seq_file *s, void *what)
{
{
	struct pinctrl_maps *maps_node;
	struct pinctrl_maps *maps_node;
@@ -945,12 +1017,27 @@ static int pinctrl_maps_show(struct seq_file *s, void *what)
	mutex_lock(&pinctrl_mutex);
	mutex_lock(&pinctrl_mutex);


	for_each_maps(maps_node, i, map) {
	for_each_maps(maps_node, i, map) {
		seq_printf(s, "%s:\n", map->name);
		seq_printf(s, "device %s\nstate %s\ntype %s (%d)\n",
		seq_printf(s, "  device: %s\n", map->dev_name);
			   map->dev_name, map->name, map_type(map->type),
		seq_printf(s, "  controlling device %s\n", map->ctrl_dev_name);
			   map->type);
		seq_printf(s, "  function: %s\n", map->function);

		seq_printf(s, "  group: %s\n", map->group ? map->group :
		if (map->type != PIN_MAP_TYPE_DUMMY_STATE)
			   "(default)");
			seq_printf(s, "controlling device %s\n",
				   map->ctrl_dev_name);

		switch (map->type) {
		case PIN_MAP_TYPE_MUX_GROUP:
			pinmux_show_map(s, map);
			break;
		case PIN_MAP_TYPE_CONFIGS_PIN:
		case PIN_MAP_TYPE_CONFIGS_GROUP:
			pinconf_show_map(s, map);
			break;
		default:
			break;
		}

		seq_printf(s, "\n");
	}
	}


	mutex_unlock(&pinctrl_mutex);
	mutex_unlock(&pinctrl_mutex);
@@ -977,8 +1064,23 @@ static int pinctrl_show(struct seq_file *s, void *what)
			seq_printf(s, "  state: %s\n", state->name);
			seq_printf(s, "  state: %s\n", state->name);


			list_for_each_entry(setting, &state->settings, node) {
			list_for_each_entry(setting, &state->settings, node) {
				seq_printf(s, "    ");
				struct pinctrl_dev *pctldev = setting->pctldev;
				pinmux_dbg_show(s, setting);

				seq_printf(s, "    type: %s controller %s ",
					   map_type(setting->type),
					   pinctrl_dev_get_name(pctldev));

				switch (setting->type) {
				case PIN_MAP_TYPE_MUX_GROUP:
					pinmux_show_setting(s, setting);
					break;
				case PIN_MAP_TYPE_CONFIGS_PIN:
				case PIN_MAP_TYPE_CONFIGS_GROUP:
					pinconf_show_setting(s, setting);
					break;
				default:
					break;
				}
			}
			}
		}
		}
	}
	}
+31 −4
Original line number Original line Diff line number Diff line
@@ -71,18 +71,45 @@ struct pinctrl_state {
	struct list_head settings;
	struct list_head settings;
};
};


/**
 * struct pinctrl_setting_mux - setting data for MAP_TYPE_MUX_GROUP
 * @group: the group selector to program
 * @func: the function selector to program
 */
struct pinctrl_setting_mux {
	unsigned group;
	unsigned func;
};

/**
 * struct pinctrl_setting_configs - setting data for MAP_TYPE_CONFIGS_*
 * @group_or_pin: the group selector or pin ID to program
 * @configs: a pointer to an array of config parameters/values to program into
 *	hardware. Each individual pin controller defines the format and meaning
 *	of config parameters.
 * @num_configs: the number of entries in array @configs
 */
struct pinctrl_setting_configs {
	unsigned group_or_pin;
	unsigned long *configs;
	unsigned num_configs;
};

/**
/**
 * struct pinctrl_setting - an individual mux setting
 * struct pinctrl_setting - an individual mux setting
 * @node: list node for struct pinctrl_settings's @settings field
 * @node: list node for struct pinctrl_settings's @settings field
 * @type: the type of setting
 * @pctldev: pin control device handling to be programmed
 * @pctldev: pin control device handling to be programmed
 * @group_selector: the group selector to program
 * @data: Data specific to the setting type
 * @func_selector: the function selector to program
 */
 */
struct pinctrl_setting {
struct pinctrl_setting {
	struct list_head node;
	struct list_head node;
	enum pinctrl_map_type type;
	struct pinctrl_dev *pctldev;
	struct pinctrl_dev *pctldev;
	unsigned group_selector;
	union {
	unsigned func_selector;
		struct pinctrl_setting_mux mux;
		struct pinctrl_setting_configs configs;
	} data;
};
};


/**
/**
+165 −0
Original line number Original line Diff line number Diff line
@@ -36,6 +36,24 @@ int pinconf_check_ops(struct pinctrl_dev *pctldev)
	return 0;
	return 0;
}
}


int pinconf_validate_map(struct pinctrl_map const *map, int i)
{
	if (!map->data.configs.group_or_pin) {
		pr_err("failed to register map %s (%d): no group/pin given\n",
		       map->name, i);
		return -EINVAL;
	}

	if (map->data.configs.num_configs &&
			!map->data.configs.configs) {
		pr_err("failed to register map %s (%d): no configs ptr given\n",
		       map->name, i);
		return -EINVAL;
	}

	return 0;
}

static int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin,
static int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin,
			   unsigned long *config)
			   unsigned long *config)
{
{
@@ -260,8 +278,155 @@ unlock:
}
}
EXPORT_SYMBOL(pin_config_group_set);
EXPORT_SYMBOL(pin_config_group_set);


int pinconf_map_to_setting(struct pinctrl_map const *map,
			  struct pinctrl_setting *setting)
{
	struct pinctrl_dev *pctldev = setting->pctldev;

	switch (setting->type) {
	case PIN_MAP_TYPE_CONFIGS_PIN:
		setting->data.configs.group_or_pin =
			pin_get_from_name(pctldev,
					  map->data.configs.group_or_pin);
		if (setting->data.configs.group_or_pin < 0)
			return setting->data.configs.group_or_pin;
		break;
	case PIN_MAP_TYPE_CONFIGS_GROUP:
		setting->data.configs.group_or_pin =
			pinctrl_get_group_selector(pctldev,
					map->data.configs.group_or_pin);
		if (setting->data.configs.group_or_pin < 0)
			return setting->data.configs.group_or_pin;
		break;
	default:
		return -EINVAL;
	}

	setting->data.configs.num_configs = map->data.configs.num_configs;
	setting->data.configs.configs = map->data.configs.configs;

	return 0;
}

void pinconf_free_setting(struct pinctrl_setting const *setting)
{
}

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;

	if (!ops) {
		dev_err(pctldev->dev, "missing confops\n");
		return -EINVAL;
	}

	switch (setting->type) {
	case PIN_MAP_TYPE_CONFIGS_PIN:
		if (!ops->pin_config_set) {
			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,
					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) {
			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,
					setting->data.configs.group_or_pin,
					setting->data.configs.configs[i]);
			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;
	default:
		return -EINVAL;
	}

	return 0;
}

#ifdef CONFIG_DEBUG_FS
#ifdef CONFIG_DEBUG_FS


void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map)
{
	int i;

	switch (map->type) {
	case PIN_MAP_TYPE_CONFIGS_PIN:
		seq_printf(s, "pin ");
		break;
	case PIN_MAP_TYPE_CONFIGS_GROUP:
		seq_printf(s, "group ");
		break;
	default:
		break;
	}

	seq_printf(s, "%s\n", map->data.configs.group_or_pin);

	for (i = 0; i < map->data.configs.num_configs; i++)
		seq_printf(s, "config %08lx\n", map->data.configs.configs[i]);
}

void pinconf_show_setting(struct seq_file *s,
			  struct pinctrl_setting const *setting)
{
	struct pinctrl_dev *pctldev = setting->pctldev;
	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
	struct pin_desc *desc;
	int i;

	switch (setting->type) {
	case PIN_MAP_TYPE_CONFIGS_PIN:
		desc = pin_desc_get(setting->pctldev,
				    setting->data.configs.group_or_pin);
		seq_printf(s, "pin %s (%d)",
			   desc->name ? desc->name : "unnamed",
			   setting->data.configs.group_or_pin);
		break;
	case PIN_MAP_TYPE_CONFIGS_GROUP:
		seq_printf(s, "group %s (%d)",
			   pctlops->get_group_name(pctldev,
					setting->data.configs.group_or_pin),
			   setting->data.configs.group_or_pin);
		break;
	default:
		break;
	}

	/*
	 * FIXME: We should really get the pin controler to dump the config
	 * values, so they can be decoded to something meaningful.
	 */
	for (i = 0; i < setting->data.configs.num_configs; i++)
		seq_printf(s, " %08lx", setting->data.configs.configs[i]);

	seq_printf(s, "\n");
}

static void pinconf_dump_pin(struct pinctrl_dev *pctldev,
static void pinconf_dump_pin(struct pinctrl_dev *pctldev,
			     struct seq_file *s, int pin)
			     struct seq_file *s, int pin)
{
{
Loading