18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Marvell PXA2xx family pin control
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2015 Robert Jarzmik
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/bitops.h>
98c2ecf20Sopenharmony_ci#include <linux/io.h>
108c2ecf20Sopenharmony_ci#include <linux/of.h>
118c2ecf20Sopenharmony_ci#include <linux/of_address.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/pinctrl/machine.h>
148c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf.h>
158c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h>
168c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h>
178c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h>
188c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
198c2ecf20Sopenharmony_ci#include <linux/slab.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include "../pinctrl-utils.h"
228c2ecf20Sopenharmony_ci#include "pinctrl-pxa2xx.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic int pxa2xx_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	return pctl->ngroups;
298c2ecf20Sopenharmony_ci}
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic const char *pxa2xx_pctrl_get_group_name(struct pinctrl_dev *pctldev,
328c2ecf20Sopenharmony_ci					       unsigned tgroup)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
358c2ecf20Sopenharmony_ci	struct pxa_pinctrl_group *group = pctl->groups + tgroup;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	return group->name;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic int pxa2xx_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
418c2ecf20Sopenharmony_ci				       unsigned tgroup,
428c2ecf20Sopenharmony_ci				       const unsigned **pins,
438c2ecf20Sopenharmony_ci				       unsigned *num_pins)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
468c2ecf20Sopenharmony_ci	struct pxa_pinctrl_group *group = pctl->groups + tgroup;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	*pins = (unsigned *)&group->pin;
498c2ecf20Sopenharmony_ci	*num_pins = 1;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	return 0;
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic const struct pinctrl_ops pxa2xx_pctl_ops = {
558c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
568c2ecf20Sopenharmony_ci	.dt_node_to_map		= pinconf_generic_dt_node_to_map_all,
578c2ecf20Sopenharmony_ci	.dt_free_map		= pinctrl_utils_free_map,
588c2ecf20Sopenharmony_ci#endif
598c2ecf20Sopenharmony_ci	.get_groups_count	= pxa2xx_pctrl_get_groups_count,
608c2ecf20Sopenharmony_ci	.get_group_name		= pxa2xx_pctrl_get_group_name,
618c2ecf20Sopenharmony_ci	.get_group_pins		= pxa2xx_pctrl_get_group_pins,
628c2ecf20Sopenharmony_ci};
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic struct pxa_desc_function *
658c2ecf20Sopenharmony_cipxa_desc_by_func_group(struct pxa_pinctrl *pctl, const char *pin_name,
668c2ecf20Sopenharmony_ci		       const char *func_name)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	int i;
698c2ecf20Sopenharmony_ci	struct pxa_desc_function *df;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	for (i = 0; i < pctl->npins; i++) {
728c2ecf20Sopenharmony_ci		const struct pxa_desc_pin *pin = pctl->ppins + i;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci		if (!strcmp(pin->pin.name, pin_name))
758c2ecf20Sopenharmony_ci			for (df = pin->functions; df->name; df++)
768c2ecf20Sopenharmony_ci				if (!strcmp(df->name, func_name))
778c2ecf20Sopenharmony_ci					return df;
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	return NULL;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic int pxa2xx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
848c2ecf20Sopenharmony_ci					 struct pinctrl_gpio_range *range,
858c2ecf20Sopenharmony_ci					 unsigned pin,
868c2ecf20Sopenharmony_ci					 bool input)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
898c2ecf20Sopenharmony_ci	unsigned long flags;
908c2ecf20Sopenharmony_ci	uint32_t val;
918c2ecf20Sopenharmony_ci	void __iomem *gpdr;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	gpdr = pctl->base_gpdr[pin / 32];
948c2ecf20Sopenharmony_ci	dev_dbg(pctl->dev, "set_direction(pin=%d): dir=%d\n",
958c2ecf20Sopenharmony_ci		pin, !input);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	spin_lock_irqsave(&pctl->lock, flags);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	val = readl_relaxed(gpdr);
1008c2ecf20Sopenharmony_ci	val = (val & ~BIT(pin % 32)) | (input ? 0 : BIT(pin % 32));
1018c2ecf20Sopenharmony_ci	writel_relaxed(val, gpdr);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&pctl->lock, flags);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return 0;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic const char *pxa2xx_pmx_get_func_name(struct pinctrl_dev *pctldev,
1098c2ecf20Sopenharmony_ci					    unsigned function)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
1128c2ecf20Sopenharmony_ci	struct pxa_pinctrl_function *pf = pctl->functions + function;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return pf->name;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic int pxa2xx_get_functions_count(struct pinctrl_dev *pctldev)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	return pctl->nfuncs;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic int pxa2xx_pmx_get_func_groups(struct pinctrl_dev *pctldev,
1258c2ecf20Sopenharmony_ci				      unsigned function,
1268c2ecf20Sopenharmony_ci				      const char * const **groups,
1278c2ecf20Sopenharmony_ci				      unsigned * const num_groups)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
1308c2ecf20Sopenharmony_ci	struct pxa_pinctrl_function *pf = pctl->functions + function;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	*groups = pf->groups;
1338c2ecf20Sopenharmony_ci	*num_groups = pf->ngroups;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return 0;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic int pxa2xx_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned function,
1398c2ecf20Sopenharmony_ci			      unsigned tgroup)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
1428c2ecf20Sopenharmony_ci	struct pxa_pinctrl_group *group = pctl->groups + tgroup;
1438c2ecf20Sopenharmony_ci	struct pxa_desc_function *df;
1448c2ecf20Sopenharmony_ci	int pin, shift;
1458c2ecf20Sopenharmony_ci	unsigned long flags;
1468c2ecf20Sopenharmony_ci	void __iomem *gafr, *gpdr;
1478c2ecf20Sopenharmony_ci	u32 val;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	df = pxa_desc_by_func_group(pctl, group->name,
1518c2ecf20Sopenharmony_ci				    (pctl->functions + function)->name);
1528c2ecf20Sopenharmony_ci	if (!df)
1538c2ecf20Sopenharmony_ci		return -EINVAL;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	pin = group->pin;
1568c2ecf20Sopenharmony_ci	gafr = pctl->base_gafr[pin / 16];
1578c2ecf20Sopenharmony_ci	gpdr = pctl->base_gpdr[pin / 32];
1588c2ecf20Sopenharmony_ci	shift = (pin % 16) << 1;
1598c2ecf20Sopenharmony_ci	dev_dbg(pctl->dev, "set_mux(pin=%d): af=%d dir=%d\n",
1608c2ecf20Sopenharmony_ci		pin, df->muxval >> 1, df->muxval & 0x1);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	spin_lock_irqsave(&pctl->lock, flags);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	val = readl_relaxed(gafr);
1658c2ecf20Sopenharmony_ci	val = (val & ~(0x3 << shift)) | ((df->muxval >> 1) << shift);
1668c2ecf20Sopenharmony_ci	writel_relaxed(val, gafr);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	val = readl_relaxed(gpdr);
1698c2ecf20Sopenharmony_ci	val = (val & ~BIT(pin % 32)) | ((df->muxval & 1) ? BIT(pin % 32) : 0);
1708c2ecf20Sopenharmony_ci	writel_relaxed(val, gpdr);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&pctl->lock, flags);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	return 0;
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_cistatic const struct pinmux_ops pxa2xx_pinmux_ops = {
1778c2ecf20Sopenharmony_ci	.get_functions_count = pxa2xx_get_functions_count,
1788c2ecf20Sopenharmony_ci	.get_function_name = pxa2xx_pmx_get_func_name,
1798c2ecf20Sopenharmony_ci	.get_function_groups = pxa2xx_pmx_get_func_groups,
1808c2ecf20Sopenharmony_ci	.set_mux = pxa2xx_pmx_set_mux,
1818c2ecf20Sopenharmony_ci	.gpio_set_direction = pxa2xx_pmx_gpio_set_direction,
1828c2ecf20Sopenharmony_ci};
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic int pxa2xx_pconf_group_get(struct pinctrl_dev *pctldev,
1858c2ecf20Sopenharmony_ci				  unsigned group,
1868c2ecf20Sopenharmony_ci				  unsigned long *config)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
1898c2ecf20Sopenharmony_ci	struct pxa_pinctrl_group *g = pctl->groups + group;
1908c2ecf20Sopenharmony_ci	unsigned long flags;
1918c2ecf20Sopenharmony_ci	unsigned pin = g->pin;
1928c2ecf20Sopenharmony_ci	void __iomem *pgsr = pctl->base_pgsr[pin / 32];
1938c2ecf20Sopenharmony_ci	u32 val;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	spin_lock_irqsave(&pctl->lock, flags);
1968c2ecf20Sopenharmony_ci	val = readl_relaxed(pgsr) & BIT(pin % 32);
1978c2ecf20Sopenharmony_ci	*config = val ? PIN_CONFIG_LOW_POWER_MODE : 0;
1988c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&pctl->lock, flags);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	dev_dbg(pctl->dev, "get sleep gpio state(pin=%d) %d\n",
2018c2ecf20Sopenharmony_ci		pin, !!val);
2028c2ecf20Sopenharmony_ci	return 0;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic int pxa2xx_pconf_group_set(struct pinctrl_dev *pctldev,
2068c2ecf20Sopenharmony_ci				  unsigned group,
2078c2ecf20Sopenharmony_ci				  unsigned long *configs,
2088c2ecf20Sopenharmony_ci				  unsigned num_configs)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
2118c2ecf20Sopenharmony_ci	struct pxa_pinctrl_group *g = pctl->groups + group;
2128c2ecf20Sopenharmony_ci	unsigned long flags;
2138c2ecf20Sopenharmony_ci	unsigned pin = g->pin;
2148c2ecf20Sopenharmony_ci	void __iomem *pgsr = pctl->base_pgsr[pin / 32];
2158c2ecf20Sopenharmony_ci	int i, is_set = 0;
2168c2ecf20Sopenharmony_ci	u32 val;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	for (i = 0; i < num_configs; i++) {
2198c2ecf20Sopenharmony_ci		switch (pinconf_to_config_param(configs[i])) {
2208c2ecf20Sopenharmony_ci		case PIN_CONFIG_LOW_POWER_MODE:
2218c2ecf20Sopenharmony_ci			is_set = pinconf_to_config_argument(configs[i]);
2228c2ecf20Sopenharmony_ci			break;
2238c2ecf20Sopenharmony_ci		default:
2248c2ecf20Sopenharmony_ci			return -EINVAL;
2258c2ecf20Sopenharmony_ci		}
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	dev_dbg(pctl->dev, "set sleep gpio state(pin=%d) %d\n",
2298c2ecf20Sopenharmony_ci		pin, is_set);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	spin_lock_irqsave(&pctl->lock, flags);
2328c2ecf20Sopenharmony_ci	val = readl_relaxed(pgsr);
2338c2ecf20Sopenharmony_ci	val = (val & ~BIT(pin % 32)) | (is_set ? BIT(pin % 32) : 0);
2348c2ecf20Sopenharmony_ci	writel_relaxed(val, pgsr);
2358c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&pctl->lock, flags);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	return 0;
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic const struct pinconf_ops pxa2xx_pconf_ops = {
2418c2ecf20Sopenharmony_ci	.pin_config_group_get	= pxa2xx_pconf_group_get,
2428c2ecf20Sopenharmony_ci	.pin_config_group_set	= pxa2xx_pconf_group_set,
2438c2ecf20Sopenharmony_ci	.is_generic		= true,
2448c2ecf20Sopenharmony_ci};
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic struct pinctrl_desc pxa2xx_pinctrl_desc = {
2478c2ecf20Sopenharmony_ci	.confops	= &pxa2xx_pconf_ops,
2488c2ecf20Sopenharmony_ci	.pctlops	= &pxa2xx_pctl_ops,
2498c2ecf20Sopenharmony_ci	.pmxops		= &pxa2xx_pinmux_ops,
2508c2ecf20Sopenharmony_ci};
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic const struct pxa_pinctrl_function *
2538c2ecf20Sopenharmony_cipxa2xx_find_function(struct pxa_pinctrl *pctl, const char *fname,
2548c2ecf20Sopenharmony_ci		     const struct pxa_pinctrl_function *functions)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	const struct pxa_pinctrl_function *func;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	for (func = functions; func->name; func++)
2598c2ecf20Sopenharmony_ci		if (!strcmp(fname, func->name))
2608c2ecf20Sopenharmony_ci			return func;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	return NULL;
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic int pxa2xx_build_functions(struct pxa_pinctrl *pctl)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	int i;
2688c2ecf20Sopenharmony_ci	struct pxa_pinctrl_function *functions;
2698c2ecf20Sopenharmony_ci	struct pxa_desc_function *df;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	/*
2728c2ecf20Sopenharmony_ci	 * Each pin can have at most 6 alternate functions, and 2 gpio functions
2738c2ecf20Sopenharmony_ci	 * which are common to each pin. As there are more than 2 pins without
2748c2ecf20Sopenharmony_ci	 * alternate function, 6 * npins is an absolute high limit of the number
2758c2ecf20Sopenharmony_ci	 * of functions.
2768c2ecf20Sopenharmony_ci	 */
2778c2ecf20Sopenharmony_ci	functions = devm_kcalloc(pctl->dev, pctl->npins * 6,
2788c2ecf20Sopenharmony_ci				 sizeof(*functions), GFP_KERNEL);
2798c2ecf20Sopenharmony_ci	if (!functions)
2808c2ecf20Sopenharmony_ci		return -ENOMEM;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	for (i = 0; i < pctl->npins; i++)
2838c2ecf20Sopenharmony_ci		for (df = pctl->ppins[i].functions; df->name; df++)
2848c2ecf20Sopenharmony_ci			if (!pxa2xx_find_function(pctl, df->name, functions))
2858c2ecf20Sopenharmony_ci				(functions + pctl->nfuncs++)->name = df->name;
2868c2ecf20Sopenharmony_ci	pctl->functions = devm_kmemdup(pctl->dev, functions,
2878c2ecf20Sopenharmony_ci				       pctl->nfuncs * sizeof(*functions),
2888c2ecf20Sopenharmony_ci				       GFP_KERNEL);
2898c2ecf20Sopenharmony_ci	if (!pctl->functions)
2908c2ecf20Sopenharmony_ci		return -ENOMEM;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	devm_kfree(pctl->dev, functions);
2938c2ecf20Sopenharmony_ci	return 0;
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_cistatic int pxa2xx_build_groups(struct pxa_pinctrl *pctl)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	int i, j, ngroups;
2998c2ecf20Sopenharmony_ci	struct pxa_pinctrl_function *func;
3008c2ecf20Sopenharmony_ci	struct pxa_desc_function *df;
3018c2ecf20Sopenharmony_ci	char **gtmp;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	gtmp = devm_kmalloc_array(pctl->dev, pctl->npins, sizeof(*gtmp),
3048c2ecf20Sopenharmony_ci				  GFP_KERNEL);
3058c2ecf20Sopenharmony_ci	if (!gtmp)
3068c2ecf20Sopenharmony_ci		return -ENOMEM;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	for (i = 0; i < pctl->nfuncs; i++) {
3098c2ecf20Sopenharmony_ci		ngroups = 0;
3108c2ecf20Sopenharmony_ci		for (j = 0; j < pctl->npins; j++)
3118c2ecf20Sopenharmony_ci			for (df = pctl->ppins[j].functions; df->name;
3128c2ecf20Sopenharmony_ci			     df++)
3138c2ecf20Sopenharmony_ci				if (!strcmp(pctl->functions[i].name,
3148c2ecf20Sopenharmony_ci					    df->name))
3158c2ecf20Sopenharmony_ci					gtmp[ngroups++] = (char *)
3168c2ecf20Sopenharmony_ci						pctl->ppins[j].pin.name;
3178c2ecf20Sopenharmony_ci		func = pctl->functions + i;
3188c2ecf20Sopenharmony_ci		func->ngroups = ngroups;
3198c2ecf20Sopenharmony_ci		func->groups =
3208c2ecf20Sopenharmony_ci			devm_kmalloc_array(pctl->dev, ngroups,
3218c2ecf20Sopenharmony_ci					   sizeof(char *), GFP_KERNEL);
3228c2ecf20Sopenharmony_ci		if (!func->groups)
3238c2ecf20Sopenharmony_ci			return -ENOMEM;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci		memcpy(func->groups, gtmp, ngroups * sizeof(*gtmp));
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	devm_kfree(pctl->dev, gtmp);
3298c2ecf20Sopenharmony_ci	return 0;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic int pxa2xx_build_state(struct pxa_pinctrl *pctl,
3338c2ecf20Sopenharmony_ci			      const struct pxa_desc_pin *ppins, int npins)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	struct pxa_pinctrl_group *group;
3368c2ecf20Sopenharmony_ci	struct pinctrl_pin_desc *pins;
3378c2ecf20Sopenharmony_ci	int ret, i;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	pctl->npins = npins;
3408c2ecf20Sopenharmony_ci	pctl->ppins = ppins;
3418c2ecf20Sopenharmony_ci	pctl->ngroups = npins;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	pctl->desc.npins = npins;
3448c2ecf20Sopenharmony_ci	pins = devm_kcalloc(pctl->dev, npins, sizeof(*pins), GFP_KERNEL);
3458c2ecf20Sopenharmony_ci	if (!pins)
3468c2ecf20Sopenharmony_ci		return -ENOMEM;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	pctl->desc.pins = pins;
3498c2ecf20Sopenharmony_ci	for (i = 0; i < npins; i++)
3508c2ecf20Sopenharmony_ci		pins[i] = ppins[i].pin;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	pctl->groups = devm_kmalloc_array(pctl->dev, pctl->ngroups,
3538c2ecf20Sopenharmony_ci					  sizeof(*pctl->groups), GFP_KERNEL);
3548c2ecf20Sopenharmony_ci	if (!pctl->groups)
3558c2ecf20Sopenharmony_ci		return -ENOMEM;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	for (i = 0; i < npins; i++) {
3588c2ecf20Sopenharmony_ci		group = pctl->groups + i;
3598c2ecf20Sopenharmony_ci		group->name = ppins[i].pin.name;
3608c2ecf20Sopenharmony_ci		group->pin = ppins[i].pin.number;
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	ret = pxa2xx_build_functions(pctl);
3648c2ecf20Sopenharmony_ci	if (ret)
3658c2ecf20Sopenharmony_ci		return ret;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	ret = pxa2xx_build_groups(pctl);
3688c2ecf20Sopenharmony_ci	if (ret)
3698c2ecf20Sopenharmony_ci		return ret;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	return 0;
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ciint pxa2xx_pinctrl_init(struct platform_device *pdev,
3758c2ecf20Sopenharmony_ci			const struct pxa_desc_pin *ppins, int npins,
3768c2ecf20Sopenharmony_ci			void __iomem *base_gafr[], void __iomem *base_gpdr[],
3778c2ecf20Sopenharmony_ci			void __iomem *base_pgsr[])
3788c2ecf20Sopenharmony_ci{
3798c2ecf20Sopenharmony_ci	struct pxa_pinctrl *pctl;
3808c2ecf20Sopenharmony_ci	int ret, i, maxpin = 0;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	for (i = 0; i < npins; i++)
3838c2ecf20Sopenharmony_ci		maxpin = max_t(int, ppins[i].pin.number, maxpin);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
3868c2ecf20Sopenharmony_ci	if (!pctl)
3878c2ecf20Sopenharmony_ci		return -ENOMEM;
3888c2ecf20Sopenharmony_ci	pctl->base_gafr = devm_kcalloc(&pdev->dev, roundup(maxpin, 16),
3898c2ecf20Sopenharmony_ci				       sizeof(*pctl->base_gafr), GFP_KERNEL);
3908c2ecf20Sopenharmony_ci	pctl->base_gpdr = devm_kcalloc(&pdev->dev, roundup(maxpin, 32),
3918c2ecf20Sopenharmony_ci				       sizeof(*pctl->base_gpdr), GFP_KERNEL);
3928c2ecf20Sopenharmony_ci	pctl->base_pgsr = devm_kcalloc(&pdev->dev, roundup(maxpin, 32),
3938c2ecf20Sopenharmony_ci				       sizeof(*pctl->base_pgsr), GFP_KERNEL);
3948c2ecf20Sopenharmony_ci	if (!pctl->base_gafr || !pctl->base_gpdr || !pctl->base_pgsr)
3958c2ecf20Sopenharmony_ci		return -ENOMEM;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, pctl);
3988c2ecf20Sopenharmony_ci	spin_lock_init(&pctl->lock);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	pctl->dev = &pdev->dev;
4018c2ecf20Sopenharmony_ci	pctl->desc = pxa2xx_pinctrl_desc;
4028c2ecf20Sopenharmony_ci	pctl->desc.name = dev_name(&pdev->dev);
4038c2ecf20Sopenharmony_ci	pctl->desc.owner = THIS_MODULE;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	for (i = 0; i < roundup(maxpin, 16); i += 16)
4068c2ecf20Sopenharmony_ci		pctl->base_gafr[i / 16] = base_gafr[i / 16];
4078c2ecf20Sopenharmony_ci	for (i = 0; i < roundup(maxpin, 32); i += 32) {
4088c2ecf20Sopenharmony_ci		pctl->base_gpdr[i / 32] = base_gpdr[i / 32];
4098c2ecf20Sopenharmony_ci		pctl->base_pgsr[i / 32] = base_pgsr[i / 32];
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	ret = pxa2xx_build_state(pctl, ppins, npins);
4138c2ecf20Sopenharmony_ci	if (ret)
4148c2ecf20Sopenharmony_ci		return ret;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->desc, pctl);
4178c2ecf20Sopenharmony_ci	if (IS_ERR(pctl->pctl_dev)) {
4188c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
4198c2ecf20Sopenharmony_ci		return PTR_ERR(pctl->pctl_dev);
4208c2ecf20Sopenharmony_ci	}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	dev_info(&pdev->dev, "initialized pxa2xx pinctrl driver\n");
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	return 0;
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pxa2xx_pinctrl_init);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ciMODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
4298c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Marvell PXA2xx pinctrl driver");
4308c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
431