forked from mirrors/linux
		
	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
					
				
					 5 changed files with 243 additions and 0 deletions
				
			
		| 
						 | 
					@ -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 a new issue