diff options
| author | Linus Walleij <linusw@kernel.org> | 2026-05-11 22:33:30 +0200 |
|---|---|---|
| committer | Linus Walleij <linusw@kernel.org> | 2026-05-11 22:33:30 +0200 |
| commit | 42ec31ec8df4675af621ec686db7410153beebfd (patch) | |
| tree | b8fc157fa4111282e01f0ab1e263e830a5315b35 | |
| parent | 0942cdb8f4b14cbfdc1996c2c332c6402a203bf3 (diff) | |
| parent | d8074fd57a0231457e580c1f6cd33f089f09fd12 (diff) | |
Merge branch 'ib-mux-pinctrl' into devel
| -rw-r--r-- | Documentation/devicetree/bindings/pinctrl/pinctrl-multiplexer.yaml | 57 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/pinctrl/pinctrl.yaml | 2 | ||||
| -rw-r--r-- | drivers/mux/core.c | 43 | ||||
| -rw-r--r-- | drivers/pinctrl/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/pinctrl/Makefile | 1 | ||||
| -rw-r--r-- | drivers/pinctrl/pinconf.h | 18 | ||||
| -rw-r--r-- | drivers/pinctrl/pinctrl-generic-mux.c | 184 | ||||
| -rw-r--r-- | drivers/pinctrl/pinctrl-generic.c | 95 | ||||
| -rw-r--r-- | drivers/pinctrl/pinmux.c | 5 | ||||
| -rw-r--r-- | include/linux/mux/consumer.h | 8 | ||||
| -rw-r--r-- | include/linux/pinctrl/pinmux.h | 5 |
11 files changed, 370 insertions, 57 deletions
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-multiplexer.yaml b/Documentation/devicetree/bindings/pinctrl/pinctrl-multiplexer.yaml new file mode 100644 index 000000000000..2b0385ed879b --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-multiplexer.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/pinctrl-multiplexer.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic pinctrl device for on-board MUX Chips + +maintainers: + - Frank Li <Frank.Li@nxp.com> + +description: + Generic pinctrl device for on-board MUX Chips, which switch SoC signals + between different peripherals (e.g. MMC and UART). + + The MUX select lines are often driven by a I2C GPIO expander. + +properties: + compatible: + const: pinctrl-multiplexer + +patternProperties: + '-grp$': + type: object + additionalProperties: false + properties: + mux-states: + maxItems: 1 + + required: + - mux-states + +required: + - compatible + +allOf: + - $ref: pinctrl.yaml# + +unevaluatedProperties: false + +examples: + - | + pinctrl-mux { + compatible = "pinctrl-multiplexer"; + + uart-grp { + mux-states = <&mux 0>; + }; + + spi-grp { + mux-states = <&mux 1>; + }; + + i2c-grp { + mux-states = <&mux 2>; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/pinctrl.yaml index 290438826c50..20176bf30747 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl.yaml @@ -27,7 +27,7 @@ description: | properties: $nodename: - pattern: "^(pinctrl|pinmux)(@[0-9a-f]+)?$" + pattern: "^(pinctrl|pinmux)(@[0-9a-f]+|-[a-z0-9]+)?$" "#pinctrl-cells": description: > diff --git a/drivers/mux/core.c b/drivers/mux/core.c index 23538de2c91b..5083e3d19606 100644 --- a/drivers/mux/core.c +++ b/drivers/mux/core.c @@ -533,14 +533,16 @@ static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np) * @state: Pointer to where the requested state is returned, or NULL when * the required multiplexer states are handled by other means. * @optional: Whether to return NULL and silence errors when mux doesn't exist. + * @node: the device nodes, use dev->of_node if it is NULL. * * Return: Pointer to the mux-control on success, an ERR_PTR with a negative * errno on error, or NULL if optional is true and mux doesn't exist. */ static struct mux_control *mux_get(struct device *dev, const char *mux_name, - unsigned int *state, bool optional) + unsigned int *state, bool optional, + struct device_node *node) { - struct device_node *np = dev->of_node; + struct device_node *np = node ? node : dev->of_node; struct of_phandle_args args; struct mux_chip *mux_chip; unsigned int controller; @@ -635,7 +637,7 @@ static struct mux_control *mux_get(struct device *dev, const char *mux_name, */ struct mux_control *mux_control_get(struct device *dev, const char *mux_name) { - struct mux_control *mux = mux_get(dev, mux_name, NULL, false); + struct mux_control *mux = mux_get(dev, mux_name, NULL, false, NULL); if (!mux) return ERR_PTR(-ENOENT); @@ -654,7 +656,7 @@ EXPORT_SYMBOL_GPL(mux_control_get); */ struct mux_control *mux_control_get_optional(struct device *dev, const char *mux_name) { - return mux_get(dev, mux_name, NULL, true); + return mux_get(dev, mux_name, NULL, true, NULL); } EXPORT_SYMBOL_GPL(mux_control_get_optional); @@ -712,11 +714,14 @@ EXPORT_SYMBOL_GPL(devm_mux_control_get); * @dev: The device that needs a mux-state. * @mux_name: The name identifying the mux-state. * @optional: Whether to return NULL and silence errors when mux doesn't exist. + * @np: the device nodes, use dev->of_node if it is NULL. * * Return: Pointer to the mux-state on success, an ERR_PTR with a negative * errno on error, or NULL if optional is true and mux doesn't exist. */ -static struct mux_state *mux_state_get(struct device *dev, const char *mux_name, bool optional) +static struct mux_state * +mux_state_get(struct device *dev, const char *mux_name, bool optional, + struct device_node *np) { struct mux_state *mstate; @@ -724,7 +729,7 @@ static struct mux_state *mux_state_get(struct device *dev, const char *mux_name, if (!mstate) return ERR_PTR(-ENOMEM); - mstate->mux = mux_get(dev, mux_name, &mstate->state, optional); + mstate->mux = mux_get(dev, mux_name, &mstate->state, optional, np); if (IS_ERR(mstate->mux)) { int err = PTR_ERR(mstate->mux); @@ -766,6 +771,7 @@ static void devm_mux_state_release(struct device *dev, void *res) * @dev: The device that needs a mux-state. * @mux_name: The name identifying the mux-state. * @optional: Whether to return NULL and silence errors when mux doesn't exist. + * @np: The device nodes, use dev->of_node if it is NULL. * @init: Optional function pointer for mux-state object initialisation. * @exit: Optional function pointer for mux-state object cleanup on release. * @@ -773,7 +779,7 @@ static void devm_mux_state_release(struct device *dev, void *res) * errno on error, or NULL if optional is true and mux doesn't exist. */ static struct mux_state *__devm_mux_state_get(struct device *dev, const char *mux_name, - bool optional, + bool optional, struct device_node *np, int (*init)(struct mux_state *mstate), int (*exit)(struct mux_state *mstate)) { @@ -781,7 +787,7 @@ static struct mux_state *__devm_mux_state_get(struct device *dev, const char *mu struct mux_state *mstate; int ret; - mstate = mux_state_get(dev, mux_name, optional); + mstate = mux_state_get(dev, mux_name, optional, np); if (IS_ERR(mstate)) return ERR_CAST(mstate); else if (optional && !mstate) @@ -815,20 +821,23 @@ err_devres_alloc: } /** - * devm_mux_state_get() - Get the mux-state for a device, with resource - * management. + * devm_mux_state_get_from_np() - Get the mux-state for a device, with resource + * management. * @dev: The device that needs a mux-control. * @mux_name: The name identifying the mux-control. + * @np: the device nodes, use dev->of_node if it is NULL. * * Return: Pointer to the mux-state, or an ERR_PTR with a negative errno. * * The mux-state will automatically be freed on release. */ -struct mux_state *devm_mux_state_get(struct device *dev, const char *mux_name) +struct mux_state * +devm_mux_state_get_from_np(struct device *dev, const char *mux_name, + struct device_node *np) { - return __devm_mux_state_get(dev, mux_name, false, NULL, NULL); + return __devm_mux_state_get(dev, mux_name, false, np, NULL, NULL); } -EXPORT_SYMBOL_GPL(devm_mux_state_get); +EXPORT_SYMBOL_GPL(devm_mux_state_get_from_np); /** * devm_mux_state_get_optional() - Get the optional mux-state for a device, @@ -843,7 +852,7 @@ EXPORT_SYMBOL_GPL(devm_mux_state_get); */ struct mux_state *devm_mux_state_get_optional(struct device *dev, const char *mux_name) { - return __devm_mux_state_get(dev, mux_name, true, NULL, NULL); + return __devm_mux_state_get(dev, mux_name, true, NULL, NULL, NULL); } EXPORT_SYMBOL_GPL(devm_mux_state_get_optional); @@ -861,7 +870,8 @@ EXPORT_SYMBOL_GPL(devm_mux_state_get_optional); */ struct mux_state *devm_mux_state_get_selected(struct device *dev, const char *mux_name) { - return __devm_mux_state_get(dev, mux_name, false, mux_state_select, mux_state_deselect); + return __devm_mux_state_get(dev, mux_name, false, NULL, + mux_state_select, mux_state_deselect); } EXPORT_SYMBOL_GPL(devm_mux_state_get_selected); @@ -881,7 +891,8 @@ EXPORT_SYMBOL_GPL(devm_mux_state_get_selected); struct mux_state *devm_mux_state_get_optional_selected(struct device *dev, const char *mux_name) { - return __devm_mux_state_get(dev, mux_name, true, mux_state_select, mux_state_deselect); + return __devm_mux_state_get(dev, mux_name, true, NULL, + mux_state_select, mux_state_deselect); } EXPORT_SYMBOL_GPL(devm_mux_state_get_optional_selected); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 03f2e3ee065f..31d698fbaa01 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -272,6 +272,15 @@ config PINCTRL_GEMINI select GENERIC_PINCONF select MFD_SYSCON +config PINCTRL_GENERIC_MUX + tristate "Generic Pinctrl driver by using multiplexer" + depends on MULTIPLEXER + select PINMUX + select GENERIC_PINCTRL + help + Generic pinctrl driver by MULTIPLEXER framework to control on + board pin selection. + config PINCTRL_INGENIC bool "Pinctrl driver for the Ingenic JZ47xx SoCs" default MACH_INGENIC diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 78135ee963db..1438a246b93f 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_PINCTRL_EQUILIBRIUM) += pinctrl-equilibrium.o obj-$(CONFIG_PINCTRL_EP93XX) += pinctrl-ep93xx.o obj-$(CONFIG_PINCTRL_EYEQ5) += pinctrl-eyeq5.o obj-$(CONFIG_PINCTRL_GEMINI) += pinctrl-gemini.o +obj-$(CONFIG_PINCTRL_GENERIC_MUX) += pinctrl-generic-mux.o obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o obj-$(CONFIG_PINCTRL_K210) += pinctrl-k210.o obj-$(CONFIG_PINCTRL_K230) += pinctrl-k230.o diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h index 659a781e2091..fa8fb0d290d1 100644 --- a/drivers/pinctrl/pinconf.h +++ b/drivers/pinctrl/pinconf.h @@ -172,6 +172,13 @@ int pinctrl_generic_pins_function_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np, struct pinctrl_map **maps, unsigned int *num_maps); + +int pinctrl_generic_to_map(struct pinctrl_dev *pctldev, struct device_node *parent, + struct device_node *np, struct pinctrl_map **maps, + unsigned int *num_maps, unsigned int *num_reserved_maps, + const char **group_name, unsigned int ngroups, + const char **functions, unsigned int *pins, + unsigned int npins); #else static inline int pinctrl_generic_pins_function_dt_node_to_map(struct pinctrl_dev *pctldev, @@ -181,4 +188,15 @@ pinctrl_generic_pins_function_dt_node_to_map(struct pinctrl_dev *pctldev, { return -ENOTSUPP; } + +static inline int +pinctrl_generic_to_map(struct pinctrl_dev *pctldev, struct device_node *parent, + struct device_node *np, struct pinctrl_map **maps, + unsigned int *num_maps, unsigned int *num_reserved_maps, + const char **group_name, unsigned int ngroups, + const char **functions, unsigned int *pins, + void *function_data) +{ + return -ENOTSUPP; +} #endif diff --git a/drivers/pinctrl/pinctrl-generic-mux.c b/drivers/pinctrl/pinctrl-generic-mux.c new file mode 100644 index 000000000000..da5a5ec01583 --- /dev/null +++ b/drivers/pinctrl/pinctrl-generic-mux.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Generic Pin Control Driver for Board-Level Mux Chips + * Copyright 2026 NXP + */ + +#include <linux/cleanup.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/mutex.h> +#include <linux/mux/consumer.h> +#include <linux/platform_device.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/slab.h> + +#include "core.h" +#include "pinconf.h" +#include "pinmux.h" +#include "pinctrl-utils.h" + +struct mux_pin_function { + struct mux_state *mux_state; +}; + +struct mux_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl; + + /* mutex protect [pinctrl|pinmux]_generic functions */ + struct mutex lock; +}; + +static int +mux_pinmux_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **maps, unsigned int *num_maps) +{ + unsigned int num_reserved_maps = 0; + struct mux_pin_function *function; + const char **group_names; + int ret; + + function = devm_kzalloc(pctldev->dev, sizeof(*function), GFP_KERNEL); + if (!function) + return -ENOMEM; + + group_names = devm_kcalloc(pctldev->dev, 1, sizeof(*group_names), GFP_KERNEL); + if (!group_names) + return -ENOMEM; + + function->mux_state = devm_mux_state_get_from_np(pctldev->dev, NULL, np_config); + if (IS_ERR(function->mux_state)) + return PTR_ERR(function->mux_state); + + ret = pinctrl_generic_to_map(pctldev, np_config, np_config, maps, + num_maps, &num_reserved_maps, group_names, + 0, &np_config->name, NULL, 0); + + if (ret) + return ret; + + ret = pinmux_generic_add_function(pctldev, np_config->name, group_names, + 1, function); + if (ret < 0) { + pinctrl_utils_free_map(pctldev, *maps, *num_maps); + return ret; + } + + return 0; +} + +static const struct pinctrl_ops mux_pinctrl_ops = { + .get_groups_count = pinctrl_generic_get_group_count, + .get_group_name = pinctrl_generic_get_group_name, + .get_group_pins = pinctrl_generic_get_group_pins, + .dt_node_to_map = mux_pinmux_dt_node_to_map, + .dt_free_map = pinctrl_utils_free_map, +}; + +static int mux_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned int func_selector, + unsigned int group_selector) +{ + struct mux_pinctrl *mpctl = pinctrl_dev_get_drvdata(pctldev); + const struct function_desc *function; + struct mux_pin_function *func; + int ret; + + guard(mutex)(&mpctl->lock); + + function = pinmux_generic_get_function(pctldev, func_selector); + func = function->data; + + ret = mux_state_select(func->mux_state); + if (ret) + return ret; + + return 0; +} + +static void mux_pinmux_release_mux(struct pinctrl_dev *pctldev, + unsigned int func_selector, + unsigned int group_selector) +{ + struct mux_pinctrl *mpctl = pinctrl_dev_get_drvdata(pctldev); + const struct function_desc *function; + struct mux_pin_function *func; + + guard(mutex)(&mpctl->lock); + + function = pinmux_generic_get_function(pctldev, func_selector); + func = function->data; + + mux_state_deselect(func->mux_state); +} + +static const struct pinmux_ops mux_pinmux_ops = { + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, + .set_mux = mux_pinmux_set_mux, + .release_mux = mux_pinmux_release_mux, +}; + +static int mux_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mux_pinctrl *mpctl; + struct pinctrl_desc *pctl_desc; + int ret; + + mpctl = devm_kzalloc(dev, sizeof(*mpctl), GFP_KERNEL); + if (!mpctl) + return -ENOMEM; + + mpctl->dev = dev; + + platform_set_drvdata(pdev, mpctl); + + pctl_desc = devm_kzalloc(dev, sizeof(*pctl_desc), GFP_KERNEL); + if (!pctl_desc) + return -ENOMEM; + + ret = devm_mutex_init(dev, &mpctl->lock); + if (ret) + return ret; + + pctl_desc->name = dev_name(dev); + pctl_desc->owner = THIS_MODULE; + pctl_desc->pctlops = &mux_pinctrl_ops; + pctl_desc->pmxops = &mux_pinmux_ops; + + ret = devm_pinctrl_register_and_init(dev, pctl_desc, mpctl, + &mpctl->pctl); + if (ret) + return dev_err_probe(dev, ret, "Failed to register pinctrl.\n"); + + ret = pinctrl_enable(mpctl->pctl); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable pinctrl.\n"); + + return 0; +} + +static const struct of_device_id mux_pinctrl_of_match[] = { + { .compatible = "pinctrl-multiplexer" }, + { } +}; +MODULE_DEVICE_TABLE(of, mux_pinctrl_of_match); + +static struct platform_driver mux_pinctrl_driver = { + .driver = { + .name = "generic-pinctrl-mux", + .of_match_table = mux_pinctrl_of_match, + }, + .probe = mux_pinctrl_probe, +}; +module_platform_driver(mux_pinctrl_driver); + +MODULE_AUTHOR("Frank Li <Frank.Li@nxp.com>"); +MODULE_DESCRIPTION("Generic Pin Control Driver for Board-Level Mux Chips"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/pinctrl-generic.c b/drivers/pinctrl/pinctrl-generic.c index efb39c6a6703..e4cd16ce2bda 100644 --- a/drivers/pinctrl/pinctrl-generic.c +++ b/drivers/pinctrl/pinctrl-generic.c @@ -17,29 +17,18 @@ #include "pinctrl-utils.h" #include "pinmux.h" -static int pinctrl_generic_pins_function_dt_subnode_to_map(struct pinctrl_dev *pctldev, - struct device_node *parent, - struct device_node *np, - struct pinctrl_map **maps, - unsigned int *num_maps, - unsigned int *num_reserved_maps, - const char **group_names, - unsigned int ngroups) +int pinctrl_generic_to_map(struct pinctrl_dev *pctldev, struct device_node *parent, + struct device_node *np, struct pinctrl_map **maps, + unsigned int *num_maps, unsigned int *num_reserved_maps, + const char **group_names, unsigned int ngroups, + const char **functions, unsigned int *pins, + unsigned int npins) { struct device *dev = pctldev->dev; - const char **functions; + unsigned int num_configs; const char *group_name; unsigned long *configs; - unsigned int num_configs, pin, *pins; - int npins, ret, reserve = 1; - - npins = of_property_count_u32_elems(np, "pins"); - - if (npins < 1) { - dev_err(dev, "invalid pinctrl group %pOFn.%pOFn %d\n", - parent, np, npins); - return npins; - } + int ret, reserve = 1; group_name = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", parent, np); if (!group_name) @@ -47,26 +36,6 @@ static int pinctrl_generic_pins_function_dt_subnode_to_map(struct pinctrl_dev *p group_names[ngroups] = group_name; - pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); - if (!pins) - return -ENOMEM; - - functions = devm_kcalloc(dev, npins, sizeof(*functions), GFP_KERNEL); - if (!functions) - return -ENOMEM; - - for (int i = 0; i < npins; i++) { - ret = of_property_read_u32_index(np, "pins", i, &pin); - if (ret) - return ret; - - pins[i] = pin; - - ret = of_property_read_string(np, "function", &functions[i]); - if (ret) - return ret; - } - ret = pinctrl_utils_reserve_map(pctldev, maps, num_reserved_maps, num_maps, reserve); if (ret) return ret; @@ -102,6 +71,54 @@ static int pinctrl_generic_pins_function_dt_subnode_to_map(struct pinctrl_dev *p return 0; }; +EXPORT_SYMBOL_GPL(pinctrl_generic_to_map); + +static int pinctrl_generic_pins_function_dt_subnode_to_map(struct pinctrl_dev *pctldev, + struct device_node *parent, + struct device_node *np, + struct pinctrl_map **maps, + unsigned int *num_maps, + unsigned int *num_reserved_maps, + const char **group_names, + unsigned int ngroups) +{ + struct device *dev = pctldev->dev; + unsigned int pin, *pins; + const char **functions; + int npins, ret; + + npins = of_property_count_u32_elems(np, "pins"); + + if (npins < 1) { + dev_err(dev, "invalid pinctrl group %pOFn.%pOFn %d\n", + parent, np, npins); + return npins; + } + + pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); + if (!pins) + return -ENOMEM; + + functions = devm_kcalloc(dev, npins, sizeof(*functions), GFP_KERNEL); + if (!functions) + return -ENOMEM; + + for (int i = 0; i < npins; i++) { + ret = of_property_read_u32_index(np, "pins", i, &pin); + if (ret) + return ret; + + pins[i] = pin; + + ret = of_property_read_string(np, "function", &functions[i]); + if (ret) + return ret; + } + + return pinctrl_generic_to_map(pctldev, parent, np, maps, num_maps, + num_reserved_maps, group_names, ngroups, + functions, pins, npins); +} /* * For platforms that do not define groups or functions in the driver, but diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 3a8dd184ba3d..c705bc182266 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -517,6 +517,7 @@ void pinmux_disable_setting(const struct pinctrl_setting *setting) { struct pinctrl_dev *pctldev = setting->pctldev; const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; + const struct pinmux_ops *ops = pctldev->desc->pmxops; int ret = 0; const unsigned int *pins = NULL; unsigned int num_pins = 0; @@ -563,6 +564,10 @@ void pinmux_disable_setting(const struct pinctrl_setting *setting) pins[i], desc->name, gname); } } + + if (ops->release_mux) + ops->release_mux(pctldev, setting->data.mux.func, + setting->data.mux.group); } #ifdef CONFIG_DEBUG_FS diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h index a961861a503b..449e38e6e2c5 100644 --- a/include/linux/mux/consumer.h +++ b/include/linux/mux/consumer.h @@ -60,7 +60,10 @@ struct mux_control *mux_control_get_optional(struct device *dev, const char *mux void mux_control_put(struct mux_control *mux); struct mux_control *devm_mux_control_get(struct device *dev, const char *mux_name); -struct mux_state *devm_mux_state_get(struct device *dev, const char *mux_name); + +struct mux_state * +devm_mux_state_get_from_np(struct device *dev, const char *mux_name, struct device_node *np); + struct mux_state *devm_mux_state_get_optional(struct device *dev, const char *mux_name); struct mux_state *devm_mux_state_get_selected(struct device *dev, const char *mux_name); struct mux_state *devm_mux_state_get_optional_selected(struct device *dev, const char *mux_name); @@ -161,4 +164,7 @@ static inline struct mux_state *devm_mux_state_get_optional_selected(struct devi #endif /* CONFIG_MULTIPLEXER */ +#define devm_mux_state_get(dev, mux_name) \ + devm_mux_state_get_from_np(dev, mux_name, NULL) + #endif /* _LINUX_MUX_CONSUMER_H */ diff --git a/include/linux/pinctrl/pinmux.h b/include/linux/pinctrl/pinmux.h index 094bbe2fd6fd..77664937eeb2 100644 --- a/include/linux/pinctrl/pinmux.h +++ b/include/linux/pinctrl/pinmux.h @@ -51,6 +51,8 @@ struct pinctrl_gpio_range; * are handled by the pinmux subsystem. The @func_selector selects a * certain function whereas @group_selector selects a certain set of pins * to be used. On simple controllers the latter argument may be ignored + * @release_mux: Release software resources acquired by @set_mux. This callback + * must not change hardware state to avoid glitches when switching mux. * @gpio_request_enable: requests and enables GPIO on a certain pin. * Implement this only if you can mux every pin individually as GPIO. The * affected GPIO range is passed along with an offset(pin number) into that @@ -80,6 +82,9 @@ struct pinmux_ops { unsigned int selector); int (*set_mux) (struct pinctrl_dev *pctldev, unsigned int func_selector, unsigned int group_selector); + void (*release_mux) (struct pinctrl_dev *pctldev, + unsigned int func_selector, + unsigned int group_selector); int (*gpio_request_enable) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned int offset); |
