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: Tony Lindgren <tony@atomide.com> [Renamed the Kconfig item and moved things around] Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
c033a718f6
commit
a76edc89b1
|
@ -14,6 +14,10 @@ config GENERIC_PINCTRL_GROUPS
|
||||||
config PINMUX
|
config PINMUX
|
||||||
bool "Support pin multiplexing controllers" if COMPILE_TEST
|
bool "Support pin multiplexing controllers" if COMPILE_TEST
|
||||||
|
|
||||||
|
config GENERIC_PINMUX_FUNCTIONS
|
||||||
|
bool
|
||||||
|
select PINMUX
|
||||||
|
|
||||||
config PINCONF
|
config PINCONF
|
||||||
bool "Support pin configuration controllers" if COMPILE_TEST
|
bool "Support pin configuration controllers" if COMPILE_TEST
|
||||||
|
|
||||||
|
|
|
@ -1995,6 +1995,9 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
|
||||||
INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
|
INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
|
||||||
#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
|
#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
|
||||||
INIT_RADIX_TREE(&pctldev->pin_group_tree, GFP_KERNEL);
|
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
|
#endif
|
||||||
INIT_LIST_HEAD(&pctldev->gpio_ranges);
|
INIT_LIST_HEAD(&pctldev->gpio_ranges);
|
||||||
INIT_DELAYED_WORK(&pctldev->late_init, pinctrl_late_init);
|
INIT_DELAYED_WORK(&pctldev->late_init, pinctrl_late_init);
|
||||||
|
@ -2076,6 +2079,7 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
|
||||||
mutex_lock(&pctldev->mutex);
|
mutex_lock(&pctldev->mutex);
|
||||||
/* TODO: check that no pinmuxes are still active? */
|
/* TODO: check that no pinmuxes are still active? */
|
||||||
list_del(&pctldev->node);
|
list_del(&pctldev->node);
|
||||||
|
pinmux_generic_free_functions(pctldev);
|
||||||
pinctrl_generic_free_groups(pctldev);
|
pinctrl_generic_free_groups(pctldev);
|
||||||
/* Destroy descriptor tree */
|
/* Destroy descriptor tree */
|
||||||
pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
|
pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
|
||||||
|
|
|
@ -26,6 +26,8 @@ struct pinctrl_gpio_range;
|
||||||
* this radix tree
|
* this radix tree
|
||||||
* @pin_group_tree: optionally each pin group can be stored in 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
|
* @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,
|
* @gpio_ranges: a list of GPIO ranges that is handled by this pin controller,
|
||||||
* ranges are added to this list at runtime
|
* ranges are added to this list at runtime
|
||||||
* @dev: the device entry for this pin controller
|
* @dev: the device entry for this pin controller
|
||||||
|
@ -46,6 +48,10 @@ struct pinctrl_dev {
|
||||||
#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
|
#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
|
||||||
struct radix_tree_root pin_group_tree;
|
struct radix_tree_root pin_group_tree;
|
||||||
unsigned int num_groups;
|
unsigned int num_groups;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS
|
||||||
|
struct radix_tree_root pin_function_tree;
|
||||||
|
unsigned int num_functions;
|
||||||
#endif
|
#endif
|
||||||
struct list_head gpio_ranges;
|
struct list_head gpio_ranges;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
|
|
@ -682,3 +682,176 @@ void pinmux_init_device_debugfs(struct dentry *devroot,
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_DEBUG_FS */
|
#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 */
|
||||||
|
|
|
@ -111,3 +111,59 @@ static inline void pinmux_init_device_debugfs(struct dentry *devroot,
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#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 */
|
||||||
|
|
Loading…
Reference in New Issue