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

Commit a76edc89 authored by Tony Lindgren's avatar Tony Lindgren Committed by Linus Walleij
Browse files

pinctrl: core: Add generic pinctrl functions for managing groups



We can add generic helpers for function handling for cases where the pin
controller driver does not need to use static arrays.

Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
[Renamed the Kconfig item and moved things around]
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent c033a718
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -14,6 +14,10 @@ config GENERIC_PINCTRL_GROUPS
config PINMUX
	bool "Support pin multiplexing controllers" if COMPILE_TEST

config GENERIC_PINMUX_FUNCTIONS
	bool
	select PINMUX

config PINCONF
	bool "Support pin configuration controllers" if COMPILE_TEST

+4 −0
Original line number Diff line number Diff line
@@ -1995,6 +1995,9 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
	INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
	INIT_RADIX_TREE(&pctldev->pin_group_tree, GFP_KERNEL);
#endif
#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS
	INIT_RADIX_TREE(&pctldev->pin_function_tree, GFP_KERNEL);
#endif
	INIT_LIST_HEAD(&pctldev->gpio_ranges);
	INIT_DELAYED_WORK(&pctldev->late_init, pinctrl_late_init);
@@ -2076,6 +2079,7 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
	mutex_lock(&pctldev->mutex);
	/* TODO: check that no pinmuxes are still active? */
	list_del(&pctldev->node);
	pinmux_generic_free_functions(pctldev);
	pinctrl_generic_free_groups(pctldev);
	/* Destroy descriptor tree */
	pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
+6 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ struct pinctrl_gpio_range;
 *	this radix tree
 * @pin_group_tree: optionally each pin group can be stored in this radix tree
 * @num_groups: optionally number of groups can be kept here
 * @pin_function_tree: optionally each function can be stored in this radix tree
 * @num_functions: optionally number of functions can be kept here
 * @gpio_ranges: a list of GPIO ranges that is handled by this pin controller,
 *	ranges are added to this list at runtime
 * @dev: the device entry for this pin controller
@@ -46,6 +48,10 @@ struct pinctrl_dev {
#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
	struct radix_tree_root pin_group_tree;
	unsigned int num_groups;
#endif
#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS
	struct radix_tree_root pin_function_tree;
	unsigned int num_functions;
#endif
	struct list_head gpio_ranges;
	struct device *dev;
+173 −0
Original line number Diff line number Diff line
@@ -682,3 +682,176 @@ void pinmux_init_device_debugfs(struct dentry *devroot,
}

#endif /* CONFIG_DEBUG_FS */

#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS

/**
 * pinmux_generic_get_function_count() - returns number of functions
 * @pctldev: pin controller device
 */
int pinmux_generic_get_function_count(struct pinctrl_dev *pctldev)
{
	return pctldev->num_functions;
}
EXPORT_SYMBOL_GPL(pinmux_generic_get_function_count);

/**
 * pinmux_generic_get_function_name() - returns the function name
 * @pctldev: pin controller device
 * @selector: function number
 */
const char *
pinmux_generic_get_function_name(struct pinctrl_dev *pctldev,
				 unsigned int selector)
{
	struct function_desc *function;

	function = radix_tree_lookup(&pctldev->pin_function_tree,
				     selector);
	if (!function)
		return NULL;

	return function->name;
}
EXPORT_SYMBOL_GPL(pinmux_generic_get_function_name);

/**
 * pinmux_generic_get_function_groups() - gets the function groups
 * @pctldev: pin controller device
 * @selector: function number
 * @groups: array of pin groups
 * @num_groups: number of pin groups
 */
int pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev,
				       unsigned int selector,
				       const char * const **groups,
				       unsigned * const num_groups)
{
	struct function_desc *function;

	function = radix_tree_lookup(&pctldev->pin_function_tree,
				     selector);
	if (!function) {
		dev_err(pctldev->dev, "%s could not find function%i\n",
			__func__, selector);
		return -EINVAL;
	}
	*groups = function->group_names;
	*num_groups = function->num_group_names;

	return 0;
}
EXPORT_SYMBOL_GPL(pinmux_generic_get_function_groups);

/**
 * pinmux_generic_get_function() - returns a function based on the number
 * @pctldev: pin controller device
 * @group_selector: function number
 */
struct function_desc *pinmux_generic_get_function(struct pinctrl_dev *pctldev,
						  unsigned int selector)
{
	struct function_desc *function;

	function = radix_tree_lookup(&pctldev->pin_function_tree,
				     selector);
	if (!function)
		return NULL;

	return function;
}
EXPORT_SYMBOL_GPL(pinmux_generic_get_function);

/**
 * pinmux_generic_get_function_groups() - gets the function groups
 * @pctldev: pin controller device
 * @name: name of the function
 * @groups: array of pin groups
 * @num_groups: number of pin groups
 * @data: pin controller driver specific data
 */
int pinmux_generic_add_function(struct pinctrl_dev *pctldev,
				const char *name,
				const char **groups,
				const unsigned int num_groups,
				void *data)
{
	struct function_desc *function;

	function = devm_kzalloc(pctldev->dev, sizeof(*function), GFP_KERNEL);
	if (!function)
		return -ENOMEM;

	function->name = name;
	function->group_names = groups;
	function->num_group_names = num_groups;
	function->data = data;

	radix_tree_insert(&pctldev->pin_function_tree, pctldev->num_functions,
			  function);

	pctldev->num_functions++;

	return 0;
}
EXPORT_SYMBOL_GPL(pinmux_generic_add_function);

/**
 * pinmux_generic_remove_function() - removes a numbered function
 * @pctldev: pin controller device
 * @selector: function number
 *
 * Note that the caller must take care of locking.
 */
int pinmux_generic_remove_function(struct pinctrl_dev *pctldev,
				   unsigned int selector)
{
	struct function_desc *function;

	function = radix_tree_lookup(&pctldev->pin_function_tree,
				     selector);
	if (!function)
		return -ENOENT;

	radix_tree_delete(&pctldev->pin_function_tree, selector);
	devm_kfree(pctldev->dev, function);

	pctldev->num_functions--;

	return 0;
}
EXPORT_SYMBOL_GPL(pinmux_generic_remove_function);

/**
 * pinmux_generic_free_functions() - removes all functions
 * @pctldev: pin controller device
 *
 * Note that the caller must take care of locking.
 */
void pinmux_generic_free_functions(struct pinctrl_dev *pctldev)
{
	struct radix_tree_iter iter;
	struct function_desc *function;
	unsigned long *indices;
	void **slot;
	int i = 0;

	indices = devm_kzalloc(pctldev->dev, sizeof(*indices) *
			       pctldev->num_functions, GFP_KERNEL);
	if (!indices)
		return;

	radix_tree_for_each_slot(slot, &pctldev->pin_function_tree, &iter, 0)
		indices[i++] = iter.index;

	for (i = 0; i < pctldev->num_functions; i++) {
		function = radix_tree_lookup(&pctldev->pin_function_tree,
					     indices[i]);
		radix_tree_delete(&pctldev->pin_function_tree, indices[i]);
		devm_kfree(pctldev->dev, function);
	}

	pctldev->num_functions = 0;
}

#endif /* CONFIG_GENERIC_PINMUX_FUNCTIONS */
+56 −0
Original line number Diff line number Diff line
@@ -111,3 +111,59 @@ static inline void pinmux_init_device_debugfs(struct dentry *devroot,
}

#endif

#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS

/**
 * struct function_desc - generic function descriptor
 * @name: name of the function
 * @group_names: array of pin group names
 * @num_group_names: number of pin group names
 * @data: pin controller driver specific data
 */
struct function_desc {
	const char *name;
	const char **group_names;
	int num_group_names;
	void *data;
};

int pinmux_generic_get_function_count(struct pinctrl_dev *pctldev);

const char *
pinmux_generic_get_function_name(struct pinctrl_dev *pctldev,
				 unsigned int selector);

int pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev,
				       unsigned int selector,
				       const char * const **groups,
				       unsigned * const num_groups);

struct function_desc *pinmux_generic_get_function(struct pinctrl_dev *pctldev,
						  unsigned int selector);

int pinmux_generic_add_function(struct pinctrl_dev *pctldev,
				const char *name,
				const char **groups,
				unsigned const num_groups,
				void *data);

int pinmux_generic_remove_function(struct pinctrl_dev *pctldev,
				   unsigned int selector);

static inline int
pinmux_generic_remove_last_function(struct pinctrl_dev *pctldev)
{
	return pinmux_generic_remove_function(pctldev,
					      pctldev->num_functions - 1);
}

void pinmux_generic_free_functions(struct pinctrl_dev *pctldev);

#else

static inline void pinmux_generic_free_functions(struct pinctrl_dev *pctldev)
{
}

#endif /* CONFIG_GENERIC_PINMUX_FUNCTIONS */