293 lines · 8.1 KB · C
RawDownload
// 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);