// SPDX-License-Identifier: GPL-2.0-only #define pr_fmt(fmt) "generic pinconfig core: " fmt #include <linux/array_size.h>#include <linux/device.h>#include <linux/module.h>#include <linux/of.h>#include <linux/slab.h> #include <linux/pinctrl/pinconf-generic.h>#include <linux/pinctrl/pinconf.h>#include <linux/pinctrl/pinctrl.h> #include "core.h"#include "pinconf.h"#include "pinctrl-utils.h"#include "pinmux.h" 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, void *data, unsigned int *pins, unsigned int npins){ struct device *dev = pctldev->dev; unsigned int num_configs; const char *group_name; unsigned long *configs; int ret, reserve = 1; group_name = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", parent, np); if (!group_name) return -ENOMEM; group_names[ngroups] = group_name; ret = pinctrl_utils_reserve_map(pctldev, maps, num_reserved_maps, num_maps, reserve); if (ret) return ret; ret = pinctrl_utils_add_map_mux(pctldev, maps, num_reserved_maps, num_maps, group_name, parent->name); if (ret < 0) goto err_free_map; ret = pinctrl_generic_add_group(pctldev, group_name, pins, npins, data); if (ret < 0) { dev_err_probe(dev, ret, "failed to add group %s: %d\n", group_name, ret); goto err_free_map; } ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, &num_configs); if (ret) { dev_err_probe(dev, ret, "failed to parse pin config of group %s\n", group_name); goto err_free_map; } if (num_configs == 0) return 0; ret = pinctrl_utils_reserve_map(pctldev, maps, num_reserved_maps, num_maps, reserve); if (ret) goto err_free_map; ret = pinctrl_utils_add_map_configs(pctldev, maps, num_reserved_maps, num_maps, group_name, configs, num_configs, PIN_MAP_TYPE_CONFIGS_GROUP); kfree(configs); if (ret) goto err_free_map; return 0; err_free_map: pinctrl_utils_free_map(pctldev, *maps, *num_maps); *maps = NULL; *num_maps = 0; *num_reserved_maps = 0; return ret;};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);} static int pinctrl_generic_pinmux_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 *pins, *muxes; int npins, ret; npins = of_property_count_u32_elems(np, "pinmux"); 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; muxes = devm_kcalloc(dev, npins, sizeof(*muxes), GFP_KERNEL); if (!muxes) return -ENOMEM; for (int i = 0; i < npins; i++) { unsigned int pinmux; ret = of_property_read_u32_index(np, "pinmux", i, &pinmux); if (ret) return ret; pins[i] = pinmux >> 16; muxes[i] = pinmux & GENMASK(15, 0); } return pinctrl_generic_to_map(pctldev, parent, np, maps, num_maps, num_reserved_maps, group_names, ngroups, muxes, pins, npins);} static int pinctrl_generic_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np, struct pinctrl_map **maps, unsigned int *num_maps, int (dt_subnode_to_map)( struct pinctrl_dev *, struct device_node *, struct device_node *, struct pinctrl_map **, unsigned int *, unsigned int *, const char **, unsigned int)){ struct device *dev = pctldev->dev; struct device_node *child_np; const char **group_names; unsigned int num_reserved_maps = 0; int ngroups = 0; int ret; *maps = NULL; *num_maps = 0; /* * Check if this is actually the pins node, or a parent containing * multiple pins nodes. */ if (!of_property_present(np, "pins")) goto parent; group_names = devm_kcalloc(dev, 1, sizeof(*group_names), GFP_KERNEL); if (!group_names) return -ENOMEM; ret = dt_subnode_to_map(pctldev, np, np, maps, num_maps, &num_reserved_maps, group_names, ngroups); if (ret) { pinctrl_utils_free_map(pctldev, *maps, *num_maps); return dev_err_probe(dev, ret, "error figuring out mappings for %s\n", np->name); } ret = pinmux_generic_add_function(pctldev, np->name, group_names, 1, NULL); if (ret < 0) { pinctrl_utils_free_map(pctldev, *maps, *num_maps); return dev_err_probe(dev, ret, "error adding function %s\n", np->name); } return 0; parent: for_each_available_child_of_node(np, child_np) ngroups += 1; group_names = devm_kcalloc(dev, ngroups, sizeof(*group_names), GFP_KERNEL); if (!group_names) return -ENOMEM; ngroups = 0; for_each_available_child_of_node_scoped(np, child_np) { ret = dt_subnode_to_map(pctldev, np, child_np, maps, num_maps, &num_reserved_maps, group_names, ngroups); if (ret) { pinctrl_utils_free_map(pctldev, *maps, *num_maps); return dev_err_probe(dev, ret, "error figuring out mappings for %s\n", np->name); } ngroups++; } ret = pinmux_generic_add_function(pctldev, np->name, group_names, ngroups, NULL); if (ret < 0) { pinctrl_utils_free_map(pctldev, *maps, *num_maps); return dev_err_probe(dev, ret, "error adding function %s\n", np->name); } return 0;} /* * For platforms that do not define groups or functions in the driver, but * instead use the devicetree to describe them. This function will, unlike * pinconf_generic_dt_node_to_map() etc which rely on driver defined groups * and functions, create them in addition to parsing pinconf properties and * adding mappings. */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){ return pinctrl_generic_dt_node_to_map(pctldev, np, maps, num_maps, &pinctrl_generic_pins_function_dt_subnode_to_map);}EXPORT_SYMBOL_GPL(pinctrl_generic_pins_function_dt_node_to_map); /* * For platforms that do not define groups or functions in the driver, but * instead use the devicetree to describe them. This function will, unlike * pinconf_generic_dt_node_to_map() etc which rely on driver defined groups * and functions, create them in addition to parsing pinconf properties and * adding mappings. * * It assumes that the upper 16 bits of the pinmux items contain the pin * and the lower 16 the mux setting. */int pinctrl_generic_pinmux_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np, struct pinctrl_map **maps, unsigned int *num_maps){ return pinctrl_generic_dt_node_to_map(pctldev, np, maps, num_maps, &pinctrl_generic_pinmux_dt_subnode_to_map);};EXPORT_SYMBOL_GPL(pinctrl_generic_pinmux_dt_node_to_map);
// SPDX-License-Identifier: GPL-2.0-only
#define pr_fmt(fmt) "generic pinconfig core: " fmt
#include <linux/array_size.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include "core.h"
#include "pinconf.h"
#include "pinctrl-utils.h"
#include "pinmux.h"
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,
void *data, unsigned int *pins, unsigned int npins)
{
struct device *dev = pctldev->dev;
unsigned int num_configs;
const char *group_name;
unsigned long *configs;
int ret, reserve = 1;
group_name = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", parent, np);
if (!group_name)
return -ENOMEM;
group_names[ngroups] = group_name;
ret = pinctrl_utils_reserve_map(pctldev, maps, num_reserved_maps, num_maps, reserve);
if (ret)
return ret;
ret = pinctrl_utils_add_map_mux(pctldev, maps, num_reserved_maps, num_maps, group_name,
parent->name);
if (ret < 0)
goto err_free_map;
ret = pinctrl_generic_add_group(pctldev, group_name, pins, npins, data);
if (ret < 0) {
dev_err_probe(dev, ret, "failed to add group %s: %d\n",
group_name, ret);
goto err_free_map;
}
ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, &num_configs);
if (ret) {
dev_err_probe(dev, ret, "failed to parse pin config of group %s\n",
group_name);
goto err_free_map;
}
if (num_configs == 0)
return 0;
ret = pinctrl_utils_reserve_map(pctldev, maps, num_reserved_maps, num_maps, reserve);
if (ret)
goto err_free_map;
ret = pinctrl_utils_add_map_configs(pctldev, maps, num_reserved_maps, num_maps, group_name,
configs,
num_configs, PIN_MAP_TYPE_CONFIGS_GROUP);
kfree(configs);
if (ret)
goto err_free_map;
return 0;
err_free_map:
pinctrl_utils_free_map(pctldev, *maps, *num_maps);
*maps = NULL;
*num_maps = 0;
*num_reserved_maps = 0;
return ret;
};
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);
}
static int pinctrl_generic_pinmux_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 *pins, *muxes;
int npins, ret;
npins = of_property_count_u32_elems(np, "pinmux");
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;
muxes = devm_kcalloc(dev, npins, sizeof(*muxes), GFP_KERNEL);
if (!muxes)
return -ENOMEM;
for (int i = 0; i < npins; i++) {
unsigned int pinmux;
ret = of_property_read_u32_index(np, "pinmux", i, &pinmux);
if (ret)
return ret;
pins[i] = pinmux >> 16;
muxes[i] = pinmux & GENMASK(15, 0);
}
return pinctrl_generic_to_map(pctldev, parent, np, maps, num_maps,
num_reserved_maps, group_names, ngroups,
muxes, pins, npins);
}
static int pinctrl_generic_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np,
struct pinctrl_map **maps,
unsigned int *num_maps,
int (dt_subnode_to_map)(
struct pinctrl_dev *,
struct device_node *,
struct device_node *,
struct pinctrl_map **,
unsigned int *,
unsigned int *,
const char **,
unsigned int))
{
struct device *dev = pctldev->dev;
struct device_node *child_np;
const char **group_names;
unsigned int num_reserved_maps = 0;
int ngroups = 0;
int ret;
*maps = NULL;
*num_maps = 0;
/*
* Check if this is actually the pins node, or a parent containing
* multiple pins nodes.
*/
if (!of_property_present(np, "pins"))
goto parent;
group_names = devm_kcalloc(dev, 1, sizeof(*group_names), GFP_KERNEL);
if (!group_names)
return -ENOMEM;
ret = dt_subnode_to_map(pctldev, np, np, maps, num_maps,
&num_reserved_maps, group_names, ngroups);
if (ret) {
pinctrl_utils_free_map(pctldev, *maps, *num_maps);
return dev_err_probe(dev, ret, "error figuring out mappings for %s\n", np->name);
}
ret = pinmux_generic_add_function(pctldev, np->name, group_names, 1, NULL);
if (ret < 0) {
pinctrl_utils_free_map(pctldev, *maps, *num_maps);
return dev_err_probe(dev, ret, "error adding function %s\n", np->name);
}
return 0;
parent:
for_each_available_child_of_node(np, child_np)
ngroups += 1;
group_names = devm_kcalloc(dev, ngroups, sizeof(*group_names), GFP_KERNEL);
if (!group_names)
return -ENOMEM;
ngroups = 0;
for_each_available_child_of_node_scoped(np, child_np) {
ret = dt_subnode_to_map(pctldev, np, child_np, maps, num_maps,
&num_reserved_maps, group_names, ngroups);
if (ret) {
pinctrl_utils_free_map(pctldev, *maps, *num_maps);
return dev_err_probe(dev, ret, "error figuring out mappings for %s\n",
np->name);
}
ngroups++;
}
ret = pinmux_generic_add_function(pctldev, np->name, group_names, ngroups, NULL);
if (ret < 0) {
pinctrl_utils_free_map(pctldev, *maps, *num_maps);
return dev_err_probe(dev, ret, "error adding function %s\n", np->name);
}
return 0;
}
/*
* For platforms that do not define groups or functions in the driver, but
* instead use the devicetree to describe them. This function will, unlike
* pinconf_generic_dt_node_to_map() etc which rely on driver defined groups
* and functions, create them in addition to parsing pinconf properties and
* adding mappings.
*/
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)
{
return pinctrl_generic_dt_node_to_map(pctldev, np, maps, num_maps,
&pinctrl_generic_pins_function_dt_subnode_to_map);
}
EXPORT_SYMBOL_GPL(pinctrl_generic_pins_function_dt_node_to_map);
/*
* For platforms that do not define groups or functions in the driver, but
* instead use the devicetree to describe them. This function will, unlike
* pinconf_generic_dt_node_to_map() etc which rely on driver defined groups
* and functions, create them in addition to parsing pinconf properties and
* adding mappings.
*
* It assumes that the upper 16 bits of the pinmux items contain the pin
* and the lower 16 the mux setting.
*/
int pinctrl_generic_pinmux_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np,
struct pinctrl_map **maps,
unsigned int *num_maps)
{
return pinctrl_generic_dt_node_to_map(pctldev, np, maps, num_maps,
&pinctrl_generic_pinmux_dt_subnode_to_map);
};
EXPORT_SYMBOL_GPL(pinctrl_generic_pinmux_dt_node_to_map);