18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Driver for the ST Microelectronics SPEAr pinmux
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2012 ST Microelectronics
58c2ecf20Sopenharmony_ci * Viresh Kumar <vireshk@kernel.org>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Inspired from:
88c2ecf20Sopenharmony_ci * - U300 Pinctl drivers
98c2ecf20Sopenharmony_ci * - Tegra Pinctl drivers
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public
128c2ecf20Sopenharmony_ci * License version 2. This program is licensed "as is" without any
138c2ecf20Sopenharmony_ci * warranty of any kind, whether express or implied.
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/err.h>
178c2ecf20Sopenharmony_ci#include <linux/module.h>
188c2ecf20Sopenharmony_ci#include <linux/of.h>
198c2ecf20Sopenharmony_ci#include <linux/of_address.h>
208c2ecf20Sopenharmony_ci#include <linux/of_gpio.h>
218c2ecf20Sopenharmony_ci#include <linux/pinctrl/machine.h>
228c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h>
238c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h>
248c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
258c2ecf20Sopenharmony_ci#include <linux/slab.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include "pinctrl-spear.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define DRIVER_NAME "spear-pinmux"
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic void muxregs_endisable(struct spear_pmx *pmx,
328c2ecf20Sopenharmony_ci		struct spear_muxreg *muxregs, u8 count, bool enable)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	struct spear_muxreg *muxreg;
358c2ecf20Sopenharmony_ci	u32 val, temp, j;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	for (j = 0; j < count; j++) {
388c2ecf20Sopenharmony_ci		muxreg = &muxregs[j];
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci		val = pmx_readl(pmx, muxreg->reg);
418c2ecf20Sopenharmony_ci		val &= ~muxreg->mask;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci		if (enable)
448c2ecf20Sopenharmony_ci			temp = muxreg->val;
458c2ecf20Sopenharmony_ci		else
468c2ecf20Sopenharmony_ci			temp = ~muxreg->val;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci		val |= muxreg->mask & temp;
498c2ecf20Sopenharmony_ci		pmx_writel(pmx, val, muxreg->reg);
508c2ecf20Sopenharmony_ci	}
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic int set_mode(struct spear_pmx *pmx, int mode)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	struct spear_pmx_mode *pmx_mode = NULL;
568c2ecf20Sopenharmony_ci	int i;
578c2ecf20Sopenharmony_ci	u32 val;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	if (!pmx->machdata->pmx_modes || !pmx->machdata->npmx_modes)
608c2ecf20Sopenharmony_ci		return -EINVAL;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	for (i = 0; i < pmx->machdata->npmx_modes; i++) {
638c2ecf20Sopenharmony_ci		if (pmx->machdata->pmx_modes[i]->mode == (1 << mode)) {
648c2ecf20Sopenharmony_ci			pmx_mode = pmx->machdata->pmx_modes[i];
658c2ecf20Sopenharmony_ci			break;
668c2ecf20Sopenharmony_ci		}
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	if (!pmx_mode)
708c2ecf20Sopenharmony_ci		return -EINVAL;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	val = pmx_readl(pmx, pmx_mode->reg);
738c2ecf20Sopenharmony_ci	val &= ~pmx_mode->mask;
748c2ecf20Sopenharmony_ci	val |= pmx_mode->val;
758c2ecf20Sopenharmony_ci	pmx_writel(pmx, val, pmx_mode->reg);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	pmx->machdata->mode = pmx_mode->mode;
788c2ecf20Sopenharmony_ci	dev_info(pmx->dev, "Configured Mode: %s with id: %x\n\n",
798c2ecf20Sopenharmony_ci			pmx_mode->name ? pmx_mode->name : "no_name",
808c2ecf20Sopenharmony_ci			pmx_mode->reg);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	return 0;
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_civoid pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup,
868c2ecf20Sopenharmony_ci				 unsigned count, u16 reg)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	int i, j;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++)
918c2ecf20Sopenharmony_ci		for (j = 0; j < gpio_pingroup[i].nmuxregs; j++)
928c2ecf20Sopenharmony_ci			gpio_pingroup[i].muxregs[j].reg = reg;
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_civoid pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	struct spear_pingroup *pgroup;
988c2ecf20Sopenharmony_ci	struct spear_modemux *modemux;
998c2ecf20Sopenharmony_ci	int i, j, group;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	for (group = 0; group < machdata->ngroups; group++) {
1028c2ecf20Sopenharmony_ci		pgroup = machdata->groups[group];
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci		for (i = 0; i < pgroup->nmodemuxs; i++) {
1058c2ecf20Sopenharmony_ci			modemux = &pgroup->modemuxs[i];
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci			for (j = 0; j < modemux->nmuxregs; j++)
1088c2ecf20Sopenharmony_ci				if (modemux->muxregs[j].reg == 0xFFFF)
1098c2ecf20Sopenharmony_ci					modemux->muxregs[j].reg = reg;
1108c2ecf20Sopenharmony_ci		}
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic int spear_pinctrl_get_groups_cnt(struct pinctrl_dev *pctldev)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	return pmx->machdata->ngroups;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic const char *spear_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
1228c2ecf20Sopenharmony_ci		unsigned group)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	return pmx->machdata->groups[group]->name;
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic int spear_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
1308c2ecf20Sopenharmony_ci		unsigned group, const unsigned **pins, unsigned *num_pins)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	*pins = pmx->machdata->groups[group]->pins;
1358c2ecf20Sopenharmony_ci	*num_pins = pmx->machdata->groups[group]->npins;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	return 0;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic void spear_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
1418c2ecf20Sopenharmony_ci		struct seq_file *s, unsigned offset)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	seq_printf(s, " " DRIVER_NAME);
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
1478c2ecf20Sopenharmony_ci					struct device_node *np_config,
1488c2ecf20Sopenharmony_ci					struct pinctrl_map **map,
1498c2ecf20Sopenharmony_ci					unsigned *num_maps)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
1528c2ecf20Sopenharmony_ci	struct device_node *np;
1538c2ecf20Sopenharmony_ci	struct property *prop;
1548c2ecf20Sopenharmony_ci	const char *function, *group;
1558c2ecf20Sopenharmony_ci	int ret, index = 0, count = 0;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	/* calculate number of maps required */
1588c2ecf20Sopenharmony_ci	for_each_child_of_node(np_config, np) {
1598c2ecf20Sopenharmony_ci		ret = of_property_read_string(np, "st,function", &function);
1608c2ecf20Sopenharmony_ci		if (ret < 0) {
1618c2ecf20Sopenharmony_ci			of_node_put(np);
1628c2ecf20Sopenharmony_ci			return ret;
1638c2ecf20Sopenharmony_ci		}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci		ret = of_property_count_strings(np, "st,pins");
1668c2ecf20Sopenharmony_ci		if (ret < 0) {
1678c2ecf20Sopenharmony_ci			of_node_put(np);
1688c2ecf20Sopenharmony_ci			return ret;
1698c2ecf20Sopenharmony_ci		}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci		count += ret;
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	if (!count) {
1758c2ecf20Sopenharmony_ci		dev_err(pmx->dev, "No child nodes passed via DT\n");
1768c2ecf20Sopenharmony_ci		return -ENODEV;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	*map = kcalloc(count, sizeof(**map), GFP_KERNEL);
1808c2ecf20Sopenharmony_ci	if (!*map)
1818c2ecf20Sopenharmony_ci		return -ENOMEM;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	for_each_child_of_node(np_config, np) {
1848c2ecf20Sopenharmony_ci		of_property_read_string(np, "st,function", &function);
1858c2ecf20Sopenharmony_ci		of_property_for_each_string(np, "st,pins", prop, group) {
1868c2ecf20Sopenharmony_ci			(*map)[index].type = PIN_MAP_TYPE_MUX_GROUP;
1878c2ecf20Sopenharmony_ci			(*map)[index].data.mux.group = group;
1888c2ecf20Sopenharmony_ci			(*map)[index].data.mux.function = function;
1898c2ecf20Sopenharmony_ci			index++;
1908c2ecf20Sopenharmony_ci		}
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	*num_maps = count;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	return 0;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
1998c2ecf20Sopenharmony_ci				      struct pinctrl_map *map,
2008c2ecf20Sopenharmony_ci				      unsigned num_maps)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	kfree(map);
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic const struct pinctrl_ops spear_pinctrl_ops = {
2068c2ecf20Sopenharmony_ci	.get_groups_count = spear_pinctrl_get_groups_cnt,
2078c2ecf20Sopenharmony_ci	.get_group_name = spear_pinctrl_get_group_name,
2088c2ecf20Sopenharmony_ci	.get_group_pins = spear_pinctrl_get_group_pins,
2098c2ecf20Sopenharmony_ci	.pin_dbg_show = spear_pinctrl_pin_dbg_show,
2108c2ecf20Sopenharmony_ci	.dt_node_to_map = spear_pinctrl_dt_node_to_map,
2118c2ecf20Sopenharmony_ci	.dt_free_map = spear_pinctrl_dt_free_map,
2128c2ecf20Sopenharmony_ci};
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic int spear_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	return pmx->machdata->nfunctions;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistatic const char *spear_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
2228c2ecf20Sopenharmony_ci		unsigned function)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	return pmx->machdata->functions[function]->name;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic int spear_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
2308c2ecf20Sopenharmony_ci		unsigned function, const char *const **groups,
2318c2ecf20Sopenharmony_ci		unsigned * const ngroups)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	*groups = pmx->machdata->functions[function]->groups;
2368c2ecf20Sopenharmony_ci	*ngroups = pmx->machdata->functions[function]->ngroups;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	return 0;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic int spear_pinctrl_endisable(struct pinctrl_dev *pctldev,
2428c2ecf20Sopenharmony_ci		unsigned function, unsigned group, bool enable)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
2458c2ecf20Sopenharmony_ci	const struct spear_pingroup *pgroup;
2468c2ecf20Sopenharmony_ci	const struct spear_modemux *modemux;
2478c2ecf20Sopenharmony_ci	int i;
2488c2ecf20Sopenharmony_ci	bool found = false;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	pgroup = pmx->machdata->groups[group];
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	for (i = 0; i < pgroup->nmodemuxs; i++) {
2538c2ecf20Sopenharmony_ci		modemux = &pgroup->modemuxs[i];
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci		/* SoC have any modes */
2568c2ecf20Sopenharmony_ci		if (pmx->machdata->modes_supported) {
2578c2ecf20Sopenharmony_ci			if (!(pmx->machdata->mode & modemux->modes))
2588c2ecf20Sopenharmony_ci				continue;
2598c2ecf20Sopenharmony_ci		}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci		found = true;
2628c2ecf20Sopenharmony_ci		muxregs_endisable(pmx, modemux->muxregs, modemux->nmuxregs,
2638c2ecf20Sopenharmony_ci				enable);
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	if (!found) {
2678c2ecf20Sopenharmony_ci		dev_err(pmx->dev, "pinmux group: %s not supported\n",
2688c2ecf20Sopenharmony_ci				pgroup->name);
2698c2ecf20Sopenharmony_ci		return -ENODEV;
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	return 0;
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic int spear_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned function,
2768c2ecf20Sopenharmony_ci		unsigned group)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	return spear_pinctrl_endisable(pctldev, function, group, true);
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci/* gpio with pinmux */
2828c2ecf20Sopenharmony_cistatic struct spear_gpio_pingroup *get_gpio_pingroup(struct spear_pmx *pmx,
2838c2ecf20Sopenharmony_ci		unsigned pin)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	struct spear_gpio_pingroup *gpio_pingroup;
2868c2ecf20Sopenharmony_ci	int i, j;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (!pmx->machdata->gpio_pingroups)
2898c2ecf20Sopenharmony_ci		return NULL;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	for (i = 0; i < pmx->machdata->ngpio_pingroups; i++) {
2928c2ecf20Sopenharmony_ci		gpio_pingroup = &pmx->machdata->gpio_pingroups[i];
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci		for (j = 0; j < gpio_pingroup->npins; j++) {
2958c2ecf20Sopenharmony_ci			if (gpio_pingroup->pins[j] == pin)
2968c2ecf20Sopenharmony_ci				return gpio_pingroup;
2978c2ecf20Sopenharmony_ci		}
2988c2ecf20Sopenharmony_ci	}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	return NULL;
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic int gpio_request_endisable(struct pinctrl_dev *pctldev,
3048c2ecf20Sopenharmony_ci		struct pinctrl_gpio_range *range, unsigned offset, bool enable)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
3078c2ecf20Sopenharmony_ci	struct spear_pinctrl_machdata *machdata = pmx->machdata;
3088c2ecf20Sopenharmony_ci	struct spear_gpio_pingroup *gpio_pingroup;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	/*
3118c2ecf20Sopenharmony_ci	 * Some SoC have configuration options applicable to group of pins,
3128c2ecf20Sopenharmony_ci	 * rather than a single pin.
3138c2ecf20Sopenharmony_ci	 */
3148c2ecf20Sopenharmony_ci	gpio_pingroup = get_gpio_pingroup(pmx, offset);
3158c2ecf20Sopenharmony_ci	if (gpio_pingroup)
3168c2ecf20Sopenharmony_ci		muxregs_endisable(pmx, gpio_pingroup->muxregs,
3178c2ecf20Sopenharmony_ci				gpio_pingroup->nmuxregs, enable);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	/*
3208c2ecf20Sopenharmony_ci	 * SoC may need some extra configurations, or configurations for single
3218c2ecf20Sopenharmony_ci	 * pin
3228c2ecf20Sopenharmony_ci	 */
3238c2ecf20Sopenharmony_ci	if (machdata->gpio_request_endisable)
3248c2ecf20Sopenharmony_ci		machdata->gpio_request_endisable(pmx, offset, enable);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	return 0;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic int gpio_request_enable(struct pinctrl_dev *pctldev,
3308c2ecf20Sopenharmony_ci		struct pinctrl_gpio_range *range, unsigned offset)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	return gpio_request_endisable(pctldev, range, offset, true);
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic void gpio_disable_free(struct pinctrl_dev *pctldev,
3368c2ecf20Sopenharmony_ci		struct pinctrl_gpio_range *range, unsigned offset)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	gpio_request_endisable(pctldev, range, offset, false);
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic const struct pinmux_ops spear_pinmux_ops = {
3428c2ecf20Sopenharmony_ci	.get_functions_count = spear_pinctrl_get_funcs_count,
3438c2ecf20Sopenharmony_ci	.get_function_name = spear_pinctrl_get_func_name,
3448c2ecf20Sopenharmony_ci	.get_function_groups = spear_pinctrl_get_func_groups,
3458c2ecf20Sopenharmony_ci	.set_mux = spear_pinctrl_set_mux,
3468c2ecf20Sopenharmony_ci	.gpio_request_enable = gpio_request_enable,
3478c2ecf20Sopenharmony_ci	.gpio_disable_free = gpio_disable_free,
3488c2ecf20Sopenharmony_ci};
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_cistatic struct pinctrl_desc spear_pinctrl_desc = {
3518c2ecf20Sopenharmony_ci	.name = DRIVER_NAME,
3528c2ecf20Sopenharmony_ci	.pctlops = &spear_pinctrl_ops,
3538c2ecf20Sopenharmony_ci	.pmxops = &spear_pinmux_ops,
3548c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
3558c2ecf20Sopenharmony_ci};
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ciint spear_pinctrl_probe(struct platform_device *pdev,
3588c2ecf20Sopenharmony_ci			struct spear_pinctrl_machdata *machdata)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
3618c2ecf20Sopenharmony_ci	struct spear_pmx *pmx;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	if (!machdata)
3648c2ecf20Sopenharmony_ci		return -ENODEV;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
3678c2ecf20Sopenharmony_ci	if (!pmx)
3688c2ecf20Sopenharmony_ci		return -ENOMEM;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	pmx->vbase = devm_platform_ioremap_resource(pdev, 0);
3718c2ecf20Sopenharmony_ci	if (IS_ERR(pmx->vbase))
3728c2ecf20Sopenharmony_ci		return PTR_ERR(pmx->vbase);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	pmx->dev = &pdev->dev;
3758c2ecf20Sopenharmony_ci	pmx->machdata = machdata;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	/* configure mode, if supported by SoC */
3788c2ecf20Sopenharmony_ci	if (machdata->modes_supported) {
3798c2ecf20Sopenharmony_ci		int mode = 0;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci		if (of_property_read_u32(np, "st,pinmux-mode", &mode)) {
3828c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "OF: pinmux mode not passed\n");
3838c2ecf20Sopenharmony_ci			return -EINVAL;
3848c2ecf20Sopenharmony_ci		}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci		if (set_mode(pmx, mode)) {
3878c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "OF: Couldn't configure mode: %x\n",
3888c2ecf20Sopenharmony_ci					mode);
3898c2ecf20Sopenharmony_ci			return -EINVAL;
3908c2ecf20Sopenharmony_ci		}
3918c2ecf20Sopenharmony_ci	}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, pmx);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	spear_pinctrl_desc.pins = machdata->pins;
3968c2ecf20Sopenharmony_ci	spear_pinctrl_desc.npins = machdata->npins;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	pmx->pctl = devm_pinctrl_register(&pdev->dev, &spear_pinctrl_desc, pmx);
3998c2ecf20Sopenharmony_ci	if (IS_ERR(pmx->pctl)) {
4008c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
4018c2ecf20Sopenharmony_ci		return PTR_ERR(pmx->pctl);
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	return 0;
4058c2ecf20Sopenharmony_ci}
406