brintos

brintos / linux-shallow public Read only

0
0
Text · 8.2 KiB · c372a2a Raw
340 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Marvell Berlin SoC pinctrl core driver4 *5 * Copyright (C) 2014 Marvell Technology Group Ltd.6 *7 * Antoine Ténart <antoine.tenart@free-electrons.com>8 */9 10#include <linux/io.h>11#include <linux/mfd/syscon.h>12#include <linux/module.h>13#include <linux/of.h>14#include <linux/of_address.h>15#include <linux/of_device.h>16#include <linux/pinctrl/pinctrl.h>17#include <linux/pinctrl/pinmux.h>18#include <linux/platform_device.h>19#include <linux/regmap.h>20#include <linux/slab.h>21 22#include "../core.h"23#include "../pinctrl-utils.h"24#include "berlin.h"25 26struct berlin_pinctrl {27	struct regmap *regmap;28	struct device *dev;29	const struct berlin_pinctrl_desc *desc;30	struct pinfunction *functions;31	unsigned nfunctions;32	struct pinctrl_dev *pctrl_dev;33};34 35static int berlin_pinctrl_get_group_count(struct pinctrl_dev *pctrl_dev)36{37	struct berlin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrl_dev);38 39	return pctrl->desc->ngroups;40}41 42static const char *berlin_pinctrl_get_group_name(struct pinctrl_dev *pctrl_dev,43						 unsigned group)44{45	struct berlin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrl_dev);46 47	return pctrl->desc->groups[group].name;48}49 50static int berlin_pinctrl_dt_node_to_map(struct pinctrl_dev *pctrl_dev,51					 struct device_node *node,52					 struct pinctrl_map **map,53					 unsigned *num_maps)54{55	struct berlin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrl_dev);56	struct property *prop;57	const char *function_name, *group_name;58	unsigned reserved_maps = 0;59	int ret, ngroups;60 61	*map = NULL;62	*num_maps = 0;63 64	ret = of_property_read_string(node, "function", &function_name);65	if (ret) {66		dev_err(pctrl->dev,67			"missing function property in node %pOFn\n", node);68		return -EINVAL;69	}70 71	ngroups = of_property_count_strings(node, "groups");72	if (ngroups < 0) {73		dev_err(pctrl->dev,74			"missing groups property in node %pOFn\n", node);75		return -EINVAL;76	}77 78	ret = pinctrl_utils_reserve_map(pctrl_dev, map, &reserved_maps,79					num_maps, ngroups);80	if (ret) {81		dev_err(pctrl->dev, "can't reserve map: %d\n", ret);82		return ret;83	}84 85	of_property_for_each_string(node, "groups", prop, group_name) {86		ret = pinctrl_utils_add_map_mux(pctrl_dev, map, &reserved_maps,87						num_maps, group_name,88						function_name);89		if (ret) {90			dev_err(pctrl->dev, "can't add map: %d\n", ret);91			return ret;92		}93	}94 95	return 0;96}97 98static const struct pinctrl_ops berlin_pinctrl_ops = {99	.get_groups_count	= berlin_pinctrl_get_group_count,100	.get_group_name		= berlin_pinctrl_get_group_name,101	.dt_node_to_map		= berlin_pinctrl_dt_node_to_map,102	.dt_free_map		= pinctrl_utils_free_map,103};104 105static int berlin_pinmux_get_functions_count(struct pinctrl_dev *pctrl_dev)106{107	struct berlin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrl_dev);108 109	return pctrl->nfunctions;110}111 112static const char *berlin_pinmux_get_function_name(struct pinctrl_dev *pctrl_dev,113						   unsigned function)114{115	struct berlin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrl_dev);116 117	return pctrl->functions[function].name;118}119 120static int berlin_pinmux_get_function_groups(struct pinctrl_dev *pctrl_dev,121					     unsigned function,122					     const char * const **groups,123					     unsigned * const ngroups)124{125	struct berlin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrl_dev);126 127	*groups = pctrl->functions[function].groups;128	*ngroups = pctrl->functions[function].ngroups;129 130	return 0;131}132 133static struct berlin_desc_function *134berlin_pinctrl_find_function_by_name(struct berlin_pinctrl *pctrl,135				     const struct berlin_desc_group *group,136				     const char *fname)137{138	struct berlin_desc_function *function = group->functions;139 140	while (function->name) {141		if (!strcmp(function->name, fname))142			return function;143 144		function++;145	}146 147	return NULL;148}149 150static int berlin_pinmux_set(struct pinctrl_dev *pctrl_dev,151			     unsigned function,152			     unsigned group)153{154	struct berlin_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrl_dev);155	const struct berlin_desc_group *group_desc = pctrl->desc->groups + group;156	struct pinfunction *func = pctrl->functions + function;157	struct berlin_desc_function *function_desc =158		berlin_pinctrl_find_function_by_name(pctrl, group_desc,159						     func->name);160	u32 mask, val;161 162	if (!function_desc)163		return -EINVAL;164 165	mask = GENMASK(group_desc->lsb + group_desc->bit_width - 1,166		       group_desc->lsb);167	val = function_desc->muxval << group_desc->lsb;168	regmap_update_bits(pctrl->regmap, group_desc->offset, mask, val);169 170	return 0;171}172 173static const struct pinmux_ops berlin_pinmux_ops = {174	.get_functions_count	= &berlin_pinmux_get_functions_count,175	.get_function_name	= &berlin_pinmux_get_function_name,176	.get_function_groups	= &berlin_pinmux_get_function_groups,177	.set_mux		= &berlin_pinmux_set,178};179 180static int berlin_pinctrl_add_function(struct berlin_pinctrl *pctrl,181				       const char *name)182{183	struct pinfunction *function = pctrl->functions;184 185	while (function->name) {186		if (!strcmp(function->name, name)) {187			function->ngroups++;188			return -EEXIST;189		}190		function++;191	}192 193	function->name = name;194	function->ngroups = 1;195 196	pctrl->nfunctions++;197 198	return 0;199}200 201static int berlin_pinctrl_build_state(struct platform_device *pdev)202{203	struct berlin_pinctrl *pctrl = platform_get_drvdata(pdev);204	const struct berlin_desc_group *desc_group;205	const struct berlin_desc_function *desc_function;206	int i, max_functions = 0;207 208	pctrl->nfunctions = 0;209 210	for (i = 0; i < pctrl->desc->ngroups; i++) {211		desc_group = pctrl->desc->groups + i;212		/* compute the maximum number of functions a group can have */213		max_functions += 1 << (desc_group->bit_width + 1);214	}215 216	/* we will reallocate later */217	pctrl->functions = kcalloc(max_functions, sizeof(*pctrl->functions), GFP_KERNEL);218	if (!pctrl->functions)219		return -ENOMEM;220 221	/* register all functions */222	for (i = 0; i < pctrl->desc->ngroups; i++) {223		desc_group = pctrl->desc->groups + i;224		desc_function = desc_group->functions;225 226		while (desc_function->name) {227			berlin_pinctrl_add_function(pctrl, desc_function->name);228			desc_function++;229		}230	}231 232	pctrl->functions = krealloc(pctrl->functions,233				    pctrl->nfunctions * sizeof(*pctrl->functions),234				    GFP_KERNEL);235	if (!pctrl->functions)236		return -ENOMEM;237 238	/* map functions to theirs groups */239	for (i = 0; i < pctrl->desc->ngroups; i++) {240		desc_group = pctrl->desc->groups + i;241		desc_function = desc_group->functions;242 243		while (desc_function->name) {244			struct pinfunction *function = pctrl->functions;245			const char **groups;246			bool found = false;247 248			while (function->name) {249				if (!strcmp(desc_function->name, function->name)) {250					found = true;251					break;252				}253				function++;254			}255 256			if (!found) {257				kfree(pctrl->functions);258				return -EINVAL;259			}260 261			if (!function->groups) {262				function->groups =263					devm_kcalloc(&pdev->dev,264						     function->ngroups,265						     sizeof(*function->groups),266						     GFP_KERNEL);267				if (!function->groups) {268					kfree(pctrl->functions);269					return -ENOMEM;270				}271			}272 273			groups = (const char **)function->groups;274			while (*groups)275				groups++;276 277			*groups = desc_group->name;278 279			desc_function++;280		}281	}282 283	return 0;284}285 286static struct pinctrl_desc berlin_pctrl_desc = {287	.name		= "berlin-pinctrl",288	.pctlops	= &berlin_pinctrl_ops,289	.pmxops		= &berlin_pinmux_ops,290	.owner		= THIS_MODULE,291};292 293int berlin_pinctrl_probe_regmap(struct platform_device *pdev,294				const struct berlin_pinctrl_desc *desc,295				struct regmap *regmap)296{297	struct device *dev = &pdev->dev;298	struct berlin_pinctrl *pctrl;299	int ret;300 301	pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL);302	if (!pctrl)303		return -ENOMEM;304 305	platform_set_drvdata(pdev, pctrl);306 307	pctrl->regmap = regmap;308	pctrl->dev = &pdev->dev;309	pctrl->desc = desc;310 311	ret = berlin_pinctrl_build_state(pdev);312	if (ret) {313		dev_err(dev, "cannot build driver state: %d\n", ret);314		return ret;315	}316 317	pctrl->pctrl_dev = devm_pinctrl_register(dev, &berlin_pctrl_desc,318						 pctrl);319	if (IS_ERR(pctrl->pctrl_dev)) {320		dev_err(dev, "failed to register pinctrl driver\n");321		return PTR_ERR(pctrl->pctrl_dev);322	}323 324	return 0;325}326 327int berlin_pinctrl_probe(struct platform_device *pdev,328			 const struct berlin_pinctrl_desc *desc)329{330	struct device *dev = &pdev->dev;331	struct device_node *parent_np = of_get_parent(dev->of_node);332	struct regmap *regmap = syscon_node_to_regmap(parent_np);333 334	of_node_put(parent_np);335	if (IS_ERR(regmap))336		return PTR_ERR(regmap);337 338	return berlin_pinctrl_probe_regmap(pdev, desc, regmap);339}340