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 pin group handling for cases where the pin
controller driver does not need to use static arrays.

Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
  • Loading branch information
Tony Lindgren authored and Linus Walleij committed Jan 3, 2017
1 parent 2d22e5b commit c7059c5
Show file tree
Hide file tree
Showing 3 changed files with 228 additions and 0 deletions.
3 changes: 3 additions & 0 deletions drivers/pinctrl/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ config PINCTRL
menu "Pin controllers"
depends on PINCTRL

config GENERIC_PINCTRL
bool

config PINMUX
bool "Support pin multiplexing controllers" if COMPILE_TEST

Expand Down
178 changes: 178 additions & 0 deletions drivers/pinctrl/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,182 @@ void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
}
EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);

#ifdef CONFIG_GENERIC_PINCTRL

/**
* pinctrl_generic_get_group_count() - returns the number of pin groups
* @pctldev: pin controller device
*/
int pinctrl_generic_get_group_count(struct pinctrl_dev *pctldev)
{
return pctldev->num_groups;
}
EXPORT_SYMBOL_GPL(pinctrl_generic_get_group_count);

/**
* pinctrl_generic_get_group_name() - returns the name of a pin group
* @pctldev: pin controller device
* @selector: group number
*/
const char *pinctrl_generic_get_group_name(struct pinctrl_dev *pctldev,
unsigned int selector)
{
struct group_desc *group;

group = radix_tree_lookup(&pctldev->pin_group_tree,
selector);
if (!group)
return NULL;

return group->name;
}
EXPORT_SYMBOL_GPL(pinctrl_generic_get_group_name);

/**
* pinctrl_generic_get_group_pins() - gets the pin group pins
* @pctldev: pin controller device
* @selector: group number
* @pins: pins in the group
* @num_pins: number of pins in the group
*/
int pinctrl_generic_get_group_pins(struct pinctrl_dev *pctldev,
unsigned int selector,
const unsigned int **pins,
unsigned int *num_pins)
{
struct group_desc *group;

group = radix_tree_lookup(&pctldev->pin_group_tree,
selector);
if (!group) {
dev_err(pctldev->dev, "%s could not find pingroup%i\n",
__func__, selector);
return -EINVAL;
}

*pins = group->pins;
*num_pins = group->num_pins;

return 0;
}
EXPORT_SYMBOL_GPL(pinctrl_generic_get_group_pins);

/**
* pinctrl_generic_get_group() - returns a pin group based on the number
* @pctldev: pin controller device
* @gselector: group number
*/
struct group_desc *pinctrl_generic_get_group(struct pinctrl_dev *pctldev,
unsigned int selector)
{
struct group_desc *group;

group = radix_tree_lookup(&pctldev->pin_group_tree,
selector);
if (!group)
return NULL;

return group;
}
EXPORT_SYMBOL_GPL(pinctrl_generic_get_group);

/**
* pinctrl_generic_add_group() - adds a new pin group
* @pctldev: pin controller device
* @name: name of the pin group
* @pins: pins in the pin group
* @num_pins: number of pins in the pin group
* @data: pin controller driver specific data
*
* Note that the caller must take care of locking.
*/
int pinctrl_generic_add_group(struct pinctrl_dev *pctldev, const char *name,
int *pins, int num_pins, void *data)
{
struct group_desc *group;

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

group->name = name;
group->pins = pins;
group->num_pins = num_pins;
group->data = data;

radix_tree_insert(&pctldev->pin_group_tree, pctldev->num_groups,
group);

pctldev->num_groups++;

return 0;
}
EXPORT_SYMBOL_GPL(pinctrl_generic_add_group);

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

group = radix_tree_lookup(&pctldev->pin_group_tree,
selector);
if (!group)
return -ENOENT;

radix_tree_delete(&pctldev->pin_group_tree, selector);
devm_kfree(pctldev->dev, group);

pctldev->num_groups--;

return 0;
}
EXPORT_SYMBOL_GPL(pinctrl_generic_remove_group);

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

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

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

for (i = 0; i < pctldev->num_groups; i++) {
group = radix_tree_lookup(&pctldev->pin_group_tree,
indices[i]);
radix_tree_delete(&pctldev->pin_group_tree, indices[i]);
devm_kfree(pctldev->dev, group);
}

pctldev->num_groups = 0;
}

#else
static inline void pinctrl_generic_free_groups(struct pinctrl_dev *pctldev)
{
}
#endif /* CONFIG_GENERIC_PINCTRL */

/**
* pinctrl_get_group_selector() - returns the group selector for a group
* @pctldev: the pin controller handling the group
Expand Down Expand Up @@ -1817,6 +1993,7 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
pctldev->desc = pctldesc;
pctldev->driver_data = driver_data;
INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
INIT_RADIX_TREE(&pctldev->pin_group_tree, GFP_KERNEL);
INIT_LIST_HEAD(&pctldev->gpio_ranges);
INIT_DELAYED_WORK(&pctldev->late_init, pinctrl_late_init);
pctldev->dev = dev;
Expand Down Expand Up @@ -1897,6 +2074,7 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
mutex_lock(&pctldev->mutex);
/* TODO: check that no pinmuxes are still active? */
list_del(&pctldev->node);
pinctrl_generic_free_groups(pctldev);
/* Destroy descriptor tree */
pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
pctldev->desc->npins);
Expand Down
47 changes: 47 additions & 0 deletions drivers/pinctrl/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ struct pinctrl_gpio_range;
* controller
* @pin_desc_tree: each pin descriptor for this pin controller is 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
* @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 @@ -41,6 +43,8 @@ struct pinctrl_dev {
struct list_head node;
struct pinctrl_desc *desc;
struct radix_tree_root pin_desc_tree;
struct radix_tree_root pin_group_tree;
unsigned int num_groups;
struct list_head gpio_ranges;
struct device *dev;
struct module *owner;
Expand Down Expand Up @@ -161,6 +165,20 @@ struct pin_desc {
#endif
};

/**
* struct group_desc - generic pin group descriptor
* @name: name of the pin group
* @pins: array of pins that belong to the group
* @num_pins: number of pins in the group
* @data: pin controller driver specific data
*/
struct group_desc {
const char *name;
int *pins;
int num_pins;
void *data;
};

/**
* struct pinctrl_maps - a list item containing part of the mapping table
* @node: mapping table list node
Expand All @@ -173,6 +191,35 @@ struct pinctrl_maps {
unsigned num_maps;
};

#ifdef CONFIG_GENERIC_PINCTRL

int pinctrl_generic_get_group_count(struct pinctrl_dev *pctldev);

const char *pinctrl_generic_get_group_name(struct pinctrl_dev *pctldev,
unsigned int group_selector);

int pinctrl_generic_get_group_pins(struct pinctrl_dev *pctldev,
unsigned int group_selector,
const unsigned int **pins,
unsigned int *npins);

struct group_desc *pinctrl_generic_get_group(struct pinctrl_dev *pctldev,
unsigned int group_selector);

int pinctrl_generic_add_group(struct pinctrl_dev *pctldev, const char *name,
int *gpins, int ngpins, void *data);

int pinctrl_generic_remove_group(struct pinctrl_dev *pctldev,
unsigned int group_selector);

static inline int
pinctrl_generic_remove_last_group(struct pinctrl_dev *pctldev)
{
return pinctrl_generic_remove_group(pctldev, pctldev->num_groups - 1);
}

#endif /* CONFIG_GENERIC_PINCTRL */

struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np);
int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
Expand Down

0 comments on commit c7059c5

Please sign in to comment.