Commit c7059c5a authored by Tony Lindgren's avatar Tony Lindgren Committed by Linus Walleij

pinctrl: core: Add generic pinctrl functions for managing groups

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: default avatarTony Lindgren <tony@atomide.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 2d22e5b0
...@@ -8,6 +8,9 @@ config PINCTRL ...@@ -8,6 +8,9 @@ config PINCTRL
menu "Pin controllers" menu "Pin controllers"
depends on PINCTRL depends on PINCTRL
config GENERIC_PINCTRL
bool
config PINMUX config PINMUX
bool "Support pin multiplexing controllers" if COMPILE_TEST bool "Support pin multiplexing controllers" if COMPILE_TEST
......
...@@ -540,6 +540,182 @@ void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev, ...@@ -540,6 +540,182 @@ void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
} }
EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range); 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 * pinctrl_get_group_selector() - returns the group selector for a group
* @pctldev: the pin controller handling the group * @pctldev: the pin controller handling the group
...@@ -1817,6 +1993,7 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, ...@@ -1817,6 +1993,7 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
pctldev->desc = pctldesc; pctldev->desc = pctldesc;
pctldev->driver_data = driver_data; pctldev->driver_data = driver_data;
INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL); 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_LIST_HEAD(&pctldev->gpio_ranges);
INIT_DELAYED_WORK(&pctldev->late_init, pinctrl_late_init); INIT_DELAYED_WORK(&pctldev->late_init, pinctrl_late_init);
pctldev->dev = dev; pctldev->dev = dev;
...@@ -1897,6 +2074,7 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev) ...@@ -1897,6 +2074,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);
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,
pctldev->desc->npins); pctldev->desc->npins);
......
...@@ -24,6 +24,8 @@ struct pinctrl_gpio_range; ...@@ -24,6 +24,8 @@ struct pinctrl_gpio_range;
* controller * controller
* @pin_desc_tree: each pin descriptor for this pin controller is stored in * @pin_desc_tree: each pin descriptor for this pin controller is stored in
* this radix tree * 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, * @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
...@@ -41,6 +43,8 @@ struct pinctrl_dev { ...@@ -41,6 +43,8 @@ struct pinctrl_dev {
struct list_head node; struct list_head node;
struct pinctrl_desc *desc; struct pinctrl_desc *desc;
struct radix_tree_root pin_desc_tree; struct radix_tree_root pin_desc_tree;
struct radix_tree_root pin_group_tree;
unsigned int num_groups;
struct list_head gpio_ranges; struct list_head gpio_ranges;
struct device *dev; struct device *dev;
struct module *owner; struct module *owner;
...@@ -161,6 +165,20 @@ struct pin_desc { ...@@ -161,6 +165,20 @@ struct pin_desc {
#endif #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 * struct pinctrl_maps - a list item containing part of the mapping table
* @node: mapping table list node * @node: mapping table list node
...@@ -173,6 +191,35 @@ struct pinctrl_maps { ...@@ -173,6 +191,35 @@ struct pinctrl_maps {
unsigned num_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_devname(const char *dev_name);
struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np); 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); int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment