mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 17:57:38 -04:00
Merge branch 'ib-mux-pinctrl' into devel
This commit is contained in:
@@ -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>;
|
||||
};
|
||||
};
|
||||
@@ -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: >
|
||||
|
||||
@@ -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 @@ static struct mux_state *__devm_mux_state_get(struct device *dev, const char *mu
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
184
drivers/pinctrl/pinctrl-generic-mux.c
Normal file
184
drivers/pinctrl/pinctrl-generic-mux.c
Normal file
@@ -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");
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user