diff options
author | Mark Brown <broonie@kernel.org> | 2017-04-25 18:35:35 +0300 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-04-25 18:35:35 +0300 |
commit | 9095bf25ea08135a5b74875dd0e3eeaddc4218a0 (patch) | |
tree | a4e6976eab0e7a5b6258281077cd5853c7e69514 /drivers/pinctrl/pinmux.c | |
parent | cdf4275e957c6bad3756e98942341667f1d7de7d (diff) | |
parent | c1ae3cfa0e89fa1a7ecc4c99031f5e9ae99d9201 (diff) | |
download | linux-9095bf25ea08135a5b74875dd0e3eeaddc4218a0.tar.xz |
Merge tag 'v4.11-rc1' into regulator-arizona
Linux 4.11-rc1
Diffstat (limited to 'drivers/pinctrl/pinmux.c')
-rw-r--r-- | drivers/pinctrl/pinmux.c | 216 |
1 files changed, 188 insertions, 28 deletions
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index ece702881946..29ad3151abec 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -99,37 +99,24 @@ static int pin_request(struct pinctrl_dev *pctldev, dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n", pin, desc->name, owner); - if (gpio_range) { - /* There's no need to support multiple GPIO requests */ - if (desc->gpio_owner) { - dev_err(pctldev->dev, - "pin %s already requested by %s; cannot claim for %s\n", - desc->name, desc->gpio_owner, owner); - goto out; - } - if (ops->strict && desc->mux_usecount && - strcmp(desc->mux_owner, owner)) { - dev_err(pctldev->dev, - "pin %s already requested by %s; cannot claim for %s\n", - desc->name, desc->mux_owner, owner); - goto out; - } + if ((!gpio_range || ops->strict) && + desc->mux_usecount && strcmp(desc->mux_owner, owner)) { + dev_err(pctldev->dev, + "pin %s already requested by %s; cannot claim for %s\n", + desc->name, desc->mux_owner, owner); + goto out; + } + if ((gpio_range || ops->strict) && desc->gpio_owner) { + dev_err(pctldev->dev, + "pin %s already requested by %s; cannot claim for %s\n", + desc->name, desc->gpio_owner, owner); + goto out; + } + + if (gpio_range) { desc->gpio_owner = owner; } else { - if (desc->mux_usecount && strcmp(desc->mux_owner, owner)) { - dev_err(pctldev->dev, - "pin %s already requested by %s; cannot claim for %s\n", - desc->name, desc->mux_owner, owner); - goto out; - } - if (ops->strict && desc->gpio_owner) { - dev_err(pctldev->dev, - "pin %s already requested by %s; cannot claim for %s\n", - desc->name, desc->gpio_owner, owner); - goto out; - } - desc->mux_usecount++; if (desc->mux_usecount > 1) return 0; @@ -695,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 */ |