Skip to content

Commit

Permalink
pinctrl: core: Add generic pinctrl functions for managing groups
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Tony Lindgren authored and Linus Walleij committed Jan 3, 2017
1 parent c033a71 commit a76edc8
Show file tree
Hide file tree
Showing 5 changed files with 243 additions and 0 deletions.
4 changes: 4 additions & 0 deletions drivers/pinctrl/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 4 additions & 0 deletions drivers/pinctrl/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions drivers/pinctrl/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down
173 changes: 173 additions & 0 deletions drivers/pinctrl/pinmux.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 56 additions & 0 deletions drivers/pinctrl/pinmux.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

0 comments on commit a76edc8

Please sign in to comment.