18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Spreadtrum pin controller driver
48c2ecf20Sopenharmony_ci * Copyright (C) 2017 Spreadtrum  - http://www.spreadtrum.com
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
88c2ecf20Sopenharmony_ci#include <linux/err.h>
98c2ecf20Sopenharmony_ci#include <linux/init.h>
108c2ecf20Sopenharmony_ci#include <linux/io.h>
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/of.h>
148c2ecf20Sopenharmony_ci#include <linux/of_device.h>
158c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
168c2ecf20Sopenharmony_ci#include <linux/pinctrl/machine.h>
178c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf.h>
188c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h>
198c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h>
208c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h>
218c2ecf20Sopenharmony_ci#include <linux/slab.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include "../core.h"
248c2ecf20Sopenharmony_ci#include "../pinmux.h"
258c2ecf20Sopenharmony_ci#include "../pinconf.h"
268c2ecf20Sopenharmony_ci#include "../pinctrl-utils.h"
278c2ecf20Sopenharmony_ci#include "pinctrl-sprd.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define PINCTRL_BIT_MASK(width)		(~(~0UL << (width)))
308c2ecf20Sopenharmony_ci#define PINCTRL_REG_OFFSET		0x20
318c2ecf20Sopenharmony_ci#define PINCTRL_REG_MISC_OFFSET		0x4020
328c2ecf20Sopenharmony_ci#define PINCTRL_REG_LEN			0x4
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define PIN_FUNC_MASK			(BIT(4) | BIT(5))
358c2ecf20Sopenharmony_ci#define PIN_FUNC_SEL_1			~PIN_FUNC_MASK
368c2ecf20Sopenharmony_ci#define PIN_FUNC_SEL_2			BIT(4)
378c2ecf20Sopenharmony_ci#define PIN_FUNC_SEL_3			BIT(5)
388c2ecf20Sopenharmony_ci#define PIN_FUNC_SEL_4			PIN_FUNC_MASK
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define AP_SLEEP_MODE			BIT(13)
418c2ecf20Sopenharmony_ci#define PUBCP_SLEEP_MODE		BIT(14)
428c2ecf20Sopenharmony_ci#define TGLDSP_SLEEP_MODE		BIT(15)
438c2ecf20Sopenharmony_ci#define AGDSP_SLEEP_MODE		BIT(16)
448c2ecf20Sopenharmony_ci#define CM4_SLEEP_MODE			BIT(17)
458c2ecf20Sopenharmony_ci#define SLEEP_MODE_MASK			GENMASK(5, 0)
468c2ecf20Sopenharmony_ci#define SLEEP_MODE_SHIFT		13
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#define SLEEP_INPUT			BIT(1)
498c2ecf20Sopenharmony_ci#define SLEEP_INPUT_MASK		0x1
508c2ecf20Sopenharmony_ci#define SLEEP_INPUT_SHIFT		1
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define SLEEP_OUTPUT			BIT(0)
538c2ecf20Sopenharmony_ci#define SLEEP_OUTPUT_MASK		0x1
548c2ecf20Sopenharmony_ci#define SLEEP_OUTPUT_SHIFT		0
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define DRIVE_STRENGTH_MASK		GENMASK(3, 0)
578c2ecf20Sopenharmony_ci#define DRIVE_STRENGTH_SHIFT		19
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#define SLEEP_PULL_DOWN			BIT(2)
608c2ecf20Sopenharmony_ci#define SLEEP_PULL_DOWN_MASK		0x1
618c2ecf20Sopenharmony_ci#define SLEEP_PULL_DOWN_SHIFT		2
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci#define PULL_DOWN			BIT(6)
648c2ecf20Sopenharmony_ci#define PULL_DOWN_MASK			0x1
658c2ecf20Sopenharmony_ci#define PULL_DOWN_SHIFT			6
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#define SLEEP_PULL_UP			BIT(3)
688c2ecf20Sopenharmony_ci#define SLEEP_PULL_UP_MASK		0x1
698c2ecf20Sopenharmony_ci#define SLEEP_PULL_UP_SHIFT		3
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#define PULL_UP_4_7K			(BIT(12) | BIT(7))
728c2ecf20Sopenharmony_ci#define PULL_UP_20K			BIT(7)
738c2ecf20Sopenharmony_ci#define PULL_UP_MASK			0x21
748c2ecf20Sopenharmony_ci#define PULL_UP_SHIFT			7
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci#define INPUT_SCHMITT			BIT(11)
778c2ecf20Sopenharmony_ci#define INPUT_SCHMITT_MASK		0x1
788c2ecf20Sopenharmony_ci#define INPUT_SCHMITT_SHIFT		11
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cienum pin_sleep_mode {
818c2ecf20Sopenharmony_ci	AP_SLEEP = BIT(0),
828c2ecf20Sopenharmony_ci	PUBCP_SLEEP = BIT(1),
838c2ecf20Sopenharmony_ci	TGLDSP_SLEEP = BIT(2),
848c2ecf20Sopenharmony_ci	AGDSP_SLEEP = BIT(3),
858c2ecf20Sopenharmony_ci	CM4_SLEEP = BIT(4),
868c2ecf20Sopenharmony_ci};
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cienum pin_func_sel {
898c2ecf20Sopenharmony_ci	PIN_FUNC_1,
908c2ecf20Sopenharmony_ci	PIN_FUNC_2,
918c2ecf20Sopenharmony_ci	PIN_FUNC_3,
928c2ecf20Sopenharmony_ci	PIN_FUNC_4,
938c2ecf20Sopenharmony_ci	PIN_FUNC_MAX,
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/**
978c2ecf20Sopenharmony_ci * struct sprd_pin: represent one pin's description
988c2ecf20Sopenharmony_ci * @name: pin name
998c2ecf20Sopenharmony_ci * @number: pin number
1008c2ecf20Sopenharmony_ci * @type: pin type, can be GLOBAL_CTRL_PIN/COMMON_PIN/MISC_PIN
1018c2ecf20Sopenharmony_ci * @reg: pin register address
1028c2ecf20Sopenharmony_ci * @bit_offset: bit offset in pin register
1038c2ecf20Sopenharmony_ci * @bit_width: bit width in pin register
1048c2ecf20Sopenharmony_ci */
1058c2ecf20Sopenharmony_cistruct sprd_pin {
1068c2ecf20Sopenharmony_ci	const char *name;
1078c2ecf20Sopenharmony_ci	unsigned int number;
1088c2ecf20Sopenharmony_ci	enum pin_type type;
1098c2ecf20Sopenharmony_ci	unsigned long reg;
1108c2ecf20Sopenharmony_ci	unsigned long bit_offset;
1118c2ecf20Sopenharmony_ci	unsigned long bit_width;
1128c2ecf20Sopenharmony_ci};
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci/**
1158c2ecf20Sopenharmony_ci * struct sprd_pin_group: represent one group's description
1168c2ecf20Sopenharmony_ci * @name: group name
1178c2ecf20Sopenharmony_ci * @npins: pin numbers of this group
1188c2ecf20Sopenharmony_ci * @pins: pointer to pins array
1198c2ecf20Sopenharmony_ci */
1208c2ecf20Sopenharmony_cistruct sprd_pin_group {
1218c2ecf20Sopenharmony_ci	const char *name;
1228c2ecf20Sopenharmony_ci	unsigned int npins;
1238c2ecf20Sopenharmony_ci	unsigned int *pins;
1248c2ecf20Sopenharmony_ci};
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci/**
1278c2ecf20Sopenharmony_ci * struct sprd_pinctrl_soc_info: represent the SoC's pins description
1288c2ecf20Sopenharmony_ci * @groups: pointer to groups of pins
1298c2ecf20Sopenharmony_ci * @ngroups: group numbers of the whole SoC
1308c2ecf20Sopenharmony_ci * @pins: pointer to pins description
1318c2ecf20Sopenharmony_ci * @npins: pin numbers of the whole SoC
1328c2ecf20Sopenharmony_ci * @grp_names: pointer to group names array
1338c2ecf20Sopenharmony_ci */
1348c2ecf20Sopenharmony_cistruct sprd_pinctrl_soc_info {
1358c2ecf20Sopenharmony_ci	struct sprd_pin_group *groups;
1368c2ecf20Sopenharmony_ci	unsigned int ngroups;
1378c2ecf20Sopenharmony_ci	struct sprd_pin *pins;
1388c2ecf20Sopenharmony_ci	unsigned int npins;
1398c2ecf20Sopenharmony_ci	const char **grp_names;
1408c2ecf20Sopenharmony_ci};
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci/**
1438c2ecf20Sopenharmony_ci * struct sprd_pinctrl: represent the pin controller device
1448c2ecf20Sopenharmony_ci * @dev: pointer to the device structure
1458c2ecf20Sopenharmony_ci * @pctl: pointer to the pinctrl handle
1468c2ecf20Sopenharmony_ci * @base: base address of the controller
1478c2ecf20Sopenharmony_ci * @info: pointer to SoC's pins description information
1488c2ecf20Sopenharmony_ci */
1498c2ecf20Sopenharmony_cistruct sprd_pinctrl {
1508c2ecf20Sopenharmony_ci	struct device *dev;
1518c2ecf20Sopenharmony_ci	struct pinctrl_dev *pctl;
1528c2ecf20Sopenharmony_ci	void __iomem *base;
1538c2ecf20Sopenharmony_ci	struct sprd_pinctrl_soc_info *info;
1548c2ecf20Sopenharmony_ci};
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci#define SPRD_PIN_CONFIG_CONTROL		(PIN_CONFIG_END + 1)
1578c2ecf20Sopenharmony_ci#define SPRD_PIN_CONFIG_SLEEP_MODE	(PIN_CONFIG_END + 2)
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic int sprd_pinctrl_get_id_by_name(struct sprd_pinctrl *sprd_pctl,
1608c2ecf20Sopenharmony_ci				       const char *name)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct sprd_pinctrl_soc_info *info = sprd_pctl->info;
1638c2ecf20Sopenharmony_ci	int i;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	for (i = 0; i < info->npins; i++) {
1668c2ecf20Sopenharmony_ci		if (!strcmp(info->pins[i].name, name))
1678c2ecf20Sopenharmony_ci			return info->pins[i].number;
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	return -ENODEV;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic struct sprd_pin *
1748c2ecf20Sopenharmony_cisprd_pinctrl_get_pin_by_id(struct sprd_pinctrl *sprd_pctl, unsigned int id)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	struct sprd_pinctrl_soc_info *info = sprd_pctl->info;
1778c2ecf20Sopenharmony_ci	struct sprd_pin *pin = NULL;
1788c2ecf20Sopenharmony_ci	int i;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	for (i = 0; i < info->npins; i++) {
1818c2ecf20Sopenharmony_ci		if (info->pins[i].number == id) {
1828c2ecf20Sopenharmony_ci			pin = &info->pins[i];
1838c2ecf20Sopenharmony_ci			break;
1848c2ecf20Sopenharmony_ci		}
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	return pin;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic const struct sprd_pin_group *
1918c2ecf20Sopenharmony_cisprd_pinctrl_find_group_by_name(struct sprd_pinctrl *sprd_pctl,
1928c2ecf20Sopenharmony_ci				const char *name)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	struct sprd_pinctrl_soc_info *info = sprd_pctl->info;
1958c2ecf20Sopenharmony_ci	const struct sprd_pin_group *grp = NULL;
1968c2ecf20Sopenharmony_ci	int i;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	for (i = 0; i < info->ngroups; i++) {
1998c2ecf20Sopenharmony_ci		if (!strcmp(info->groups[i].name, name)) {
2008c2ecf20Sopenharmony_ci			grp = &info->groups[i];
2018c2ecf20Sopenharmony_ci			break;
2028c2ecf20Sopenharmony_ci		}
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	return grp;
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic int sprd_pctrl_group_count(struct pinctrl_dev *pctldev)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
2118c2ecf20Sopenharmony_ci	struct sprd_pinctrl_soc_info *info = pctl->info;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	return info->ngroups;
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic const char *sprd_pctrl_group_name(struct pinctrl_dev *pctldev,
2178c2ecf20Sopenharmony_ci					 unsigned int selector)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
2208c2ecf20Sopenharmony_ci	struct sprd_pinctrl_soc_info *info = pctl->info;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	return info->groups[selector].name;
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic int sprd_pctrl_group_pins(struct pinctrl_dev *pctldev,
2268c2ecf20Sopenharmony_ci				 unsigned int selector,
2278c2ecf20Sopenharmony_ci				 const unsigned int **pins,
2288c2ecf20Sopenharmony_ci				 unsigned int *npins)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
2318c2ecf20Sopenharmony_ci	struct sprd_pinctrl_soc_info *info = pctl->info;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	if (selector >= info->ngroups)
2348c2ecf20Sopenharmony_ci		return -EINVAL;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	*pins = info->groups[selector].pins;
2378c2ecf20Sopenharmony_ci	*npins = info->groups[selector].npins;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	return 0;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic int sprd_dt_node_to_map(struct pinctrl_dev *pctldev,
2438c2ecf20Sopenharmony_ci			       struct device_node *np,
2448c2ecf20Sopenharmony_ci			       struct pinctrl_map **map,
2458c2ecf20Sopenharmony_ci			       unsigned int *num_maps)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
2488c2ecf20Sopenharmony_ci	const struct sprd_pin_group *grp;
2498c2ecf20Sopenharmony_ci	unsigned long *configs = NULL;
2508c2ecf20Sopenharmony_ci	unsigned int num_configs = 0;
2518c2ecf20Sopenharmony_ci	unsigned int reserved_maps = 0;
2528c2ecf20Sopenharmony_ci	unsigned int reserve = 0;
2538c2ecf20Sopenharmony_ci	const char *function;
2548c2ecf20Sopenharmony_ci	enum pinctrl_map_type type;
2558c2ecf20Sopenharmony_ci	int ret;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	grp = sprd_pinctrl_find_group_by_name(pctl, np->name);
2588c2ecf20Sopenharmony_ci	if (!grp) {
2598c2ecf20Sopenharmony_ci		dev_err(pctl->dev, "unable to find group for node %s\n",
2608c2ecf20Sopenharmony_ci			of_node_full_name(np));
2618c2ecf20Sopenharmony_ci		return -EINVAL;
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	ret = of_property_count_strings(np, "pins");
2658c2ecf20Sopenharmony_ci	if (ret < 0)
2668c2ecf20Sopenharmony_ci		return ret;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (ret == 1)
2698c2ecf20Sopenharmony_ci		type = PIN_MAP_TYPE_CONFIGS_PIN;
2708c2ecf20Sopenharmony_ci	else
2718c2ecf20Sopenharmony_ci		type = PIN_MAP_TYPE_CONFIGS_GROUP;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	ret = of_property_read_string(np, "function", &function);
2748c2ecf20Sopenharmony_ci	if (ret < 0) {
2758c2ecf20Sopenharmony_ci		if (ret != -EINVAL)
2768c2ecf20Sopenharmony_ci			dev_err(pctl->dev,
2778c2ecf20Sopenharmony_ci				"%s: could not parse property function\n",
2788c2ecf20Sopenharmony_ci				of_node_full_name(np));
2798c2ecf20Sopenharmony_ci		function = NULL;
2808c2ecf20Sopenharmony_ci	}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	ret = pinconf_generic_parse_dt_config(np, pctldev, &configs,
2838c2ecf20Sopenharmony_ci					      &num_configs);
2848c2ecf20Sopenharmony_ci	if (ret < 0) {
2858c2ecf20Sopenharmony_ci		dev_err(pctl->dev, "%s: could not parse node property\n",
2868c2ecf20Sopenharmony_ci			of_node_full_name(np));
2878c2ecf20Sopenharmony_ci		return ret;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	*map = NULL;
2918c2ecf20Sopenharmony_ci	*num_maps = 0;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (function != NULL)
2948c2ecf20Sopenharmony_ci		reserve++;
2958c2ecf20Sopenharmony_ci	if (num_configs)
2968c2ecf20Sopenharmony_ci		reserve++;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	ret = pinctrl_utils_reserve_map(pctldev, map, &reserved_maps,
2998c2ecf20Sopenharmony_ci					num_maps, reserve);
3008c2ecf20Sopenharmony_ci	if (ret < 0)
3018c2ecf20Sopenharmony_ci		goto out;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	if (function) {
3048c2ecf20Sopenharmony_ci		ret = pinctrl_utils_add_map_mux(pctldev, map,
3058c2ecf20Sopenharmony_ci						&reserved_maps, num_maps,
3068c2ecf20Sopenharmony_ci						grp->name, function);
3078c2ecf20Sopenharmony_ci		if (ret < 0)
3088c2ecf20Sopenharmony_ci			goto out;
3098c2ecf20Sopenharmony_ci	}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	if (num_configs) {
3128c2ecf20Sopenharmony_ci		const char *group_or_pin;
3138c2ecf20Sopenharmony_ci		unsigned int pin_id;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci		if (type == PIN_MAP_TYPE_CONFIGS_PIN) {
3168c2ecf20Sopenharmony_ci			pin_id = grp->pins[0];
3178c2ecf20Sopenharmony_ci			group_or_pin = pin_get_name(pctldev, pin_id);
3188c2ecf20Sopenharmony_ci		} else {
3198c2ecf20Sopenharmony_ci			group_or_pin = grp->name;
3208c2ecf20Sopenharmony_ci		}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci		ret = pinctrl_utils_add_map_configs(pctldev, map,
3238c2ecf20Sopenharmony_ci						    &reserved_maps, num_maps,
3248c2ecf20Sopenharmony_ci						    group_or_pin, configs,
3258c2ecf20Sopenharmony_ci						    num_configs, type);
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ciout:
3298c2ecf20Sopenharmony_ci	kfree(configs);
3308c2ecf20Sopenharmony_ci	return ret;
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic void sprd_pctrl_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
3348c2ecf20Sopenharmony_ci				unsigned int offset)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	seq_printf(s, "%s", dev_name(pctldev->dev));
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic const struct pinctrl_ops sprd_pctrl_ops = {
3408c2ecf20Sopenharmony_ci	.get_groups_count = sprd_pctrl_group_count,
3418c2ecf20Sopenharmony_ci	.get_group_name = sprd_pctrl_group_name,
3428c2ecf20Sopenharmony_ci	.get_group_pins = sprd_pctrl_group_pins,
3438c2ecf20Sopenharmony_ci	.pin_dbg_show = sprd_pctrl_dbg_show,
3448c2ecf20Sopenharmony_ci	.dt_node_to_map = sprd_dt_node_to_map,
3458c2ecf20Sopenharmony_ci	.dt_free_map = pinctrl_utils_free_map,
3468c2ecf20Sopenharmony_ci};
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic int sprd_pmx_get_function_count(struct pinctrl_dev *pctldev)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	return PIN_FUNC_MAX;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic const char *sprd_pmx_get_function_name(struct pinctrl_dev *pctldev,
3548c2ecf20Sopenharmony_ci					      unsigned int selector)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	switch (selector) {
3578c2ecf20Sopenharmony_ci	case PIN_FUNC_1:
3588c2ecf20Sopenharmony_ci		return "func1";
3598c2ecf20Sopenharmony_ci	case PIN_FUNC_2:
3608c2ecf20Sopenharmony_ci		return "func2";
3618c2ecf20Sopenharmony_ci	case PIN_FUNC_3:
3628c2ecf20Sopenharmony_ci		return "func3";
3638c2ecf20Sopenharmony_ci	case PIN_FUNC_4:
3648c2ecf20Sopenharmony_ci		return "func4";
3658c2ecf20Sopenharmony_ci	default:
3668c2ecf20Sopenharmony_ci		return "null";
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cistatic int sprd_pmx_get_function_groups(struct pinctrl_dev *pctldev,
3718c2ecf20Sopenharmony_ci					unsigned int selector,
3728c2ecf20Sopenharmony_ci					const char * const **groups,
3738c2ecf20Sopenharmony_ci					unsigned int * const num_groups)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
3768c2ecf20Sopenharmony_ci	struct sprd_pinctrl_soc_info *info = pctl->info;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	*groups = info->grp_names;
3798c2ecf20Sopenharmony_ci	*num_groups = info->ngroups;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	return 0;
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_cistatic int sprd_pmx_set_mux(struct pinctrl_dev *pctldev,
3858c2ecf20Sopenharmony_ci			    unsigned int func_selector,
3868c2ecf20Sopenharmony_ci			    unsigned int group_selector)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
3898c2ecf20Sopenharmony_ci	struct sprd_pinctrl_soc_info *info = pctl->info;
3908c2ecf20Sopenharmony_ci	struct sprd_pin_group *grp = &info->groups[group_selector];
3918c2ecf20Sopenharmony_ci	unsigned int i, grp_pins = grp->npins;
3928c2ecf20Sopenharmony_ci	unsigned long reg;
3938c2ecf20Sopenharmony_ci	unsigned int val = 0;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (group_selector >= info->ngroups)
3968c2ecf20Sopenharmony_ci		return -EINVAL;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	switch (func_selector) {
3998c2ecf20Sopenharmony_ci	case PIN_FUNC_1:
4008c2ecf20Sopenharmony_ci		val &= PIN_FUNC_SEL_1;
4018c2ecf20Sopenharmony_ci		break;
4028c2ecf20Sopenharmony_ci	case PIN_FUNC_2:
4038c2ecf20Sopenharmony_ci		val |= PIN_FUNC_SEL_2;
4048c2ecf20Sopenharmony_ci		break;
4058c2ecf20Sopenharmony_ci	case PIN_FUNC_3:
4068c2ecf20Sopenharmony_ci		val |= PIN_FUNC_SEL_3;
4078c2ecf20Sopenharmony_ci		break;
4088c2ecf20Sopenharmony_ci	case PIN_FUNC_4:
4098c2ecf20Sopenharmony_ci		val |= PIN_FUNC_SEL_4;
4108c2ecf20Sopenharmony_ci		break;
4118c2ecf20Sopenharmony_ci	default:
4128c2ecf20Sopenharmony_ci		break;
4138c2ecf20Sopenharmony_ci	}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	for (i = 0; i < grp_pins; i++) {
4168c2ecf20Sopenharmony_ci		unsigned int pin_id = grp->pins[i];
4178c2ecf20Sopenharmony_ci		struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci		if (!pin || pin->type != COMMON_PIN)
4208c2ecf20Sopenharmony_ci			continue;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		reg = readl((void __iomem *)pin->reg);
4238c2ecf20Sopenharmony_ci		reg &= ~PIN_FUNC_MASK;
4248c2ecf20Sopenharmony_ci		reg |= val;
4258c2ecf20Sopenharmony_ci		writel(reg, (void __iomem *)pin->reg);
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	return 0;
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_cistatic const struct pinmux_ops sprd_pmx_ops = {
4328c2ecf20Sopenharmony_ci	.get_functions_count = sprd_pmx_get_function_count,
4338c2ecf20Sopenharmony_ci	.get_function_name = sprd_pmx_get_function_name,
4348c2ecf20Sopenharmony_ci	.get_function_groups = sprd_pmx_get_function_groups,
4358c2ecf20Sopenharmony_ci	.set_mux = sprd_pmx_set_mux,
4368c2ecf20Sopenharmony_ci};
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic int sprd_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin_id,
4398c2ecf20Sopenharmony_ci			    unsigned long *config)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
4428c2ecf20Sopenharmony_ci	struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id);
4438c2ecf20Sopenharmony_ci	unsigned int param = pinconf_to_config_param(*config);
4448c2ecf20Sopenharmony_ci	unsigned int reg, arg;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	if (!pin)
4478c2ecf20Sopenharmony_ci		return -EINVAL;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	if (pin->type == GLOBAL_CTRL_PIN) {
4508c2ecf20Sopenharmony_ci		reg = (readl((void __iomem *)pin->reg) >>
4518c2ecf20Sopenharmony_ci			   pin->bit_offset) & PINCTRL_BIT_MASK(pin->bit_width);
4528c2ecf20Sopenharmony_ci	} else {
4538c2ecf20Sopenharmony_ci		reg = readl((void __iomem *)pin->reg);
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	if (pin->type == GLOBAL_CTRL_PIN &&
4578c2ecf20Sopenharmony_ci	    param == SPRD_PIN_CONFIG_CONTROL) {
4588c2ecf20Sopenharmony_ci		arg = reg;
4598c2ecf20Sopenharmony_ci	} else if (pin->type == COMMON_PIN || pin->type == MISC_PIN) {
4608c2ecf20Sopenharmony_ci		switch (param) {
4618c2ecf20Sopenharmony_ci		case SPRD_PIN_CONFIG_SLEEP_MODE:
4628c2ecf20Sopenharmony_ci			arg = (reg >> SLEEP_MODE_SHIFT) & SLEEP_MODE_MASK;
4638c2ecf20Sopenharmony_ci			break;
4648c2ecf20Sopenharmony_ci		case PIN_CONFIG_INPUT_ENABLE:
4658c2ecf20Sopenharmony_ci			arg = (reg >> SLEEP_INPUT_SHIFT) & SLEEP_INPUT_MASK;
4668c2ecf20Sopenharmony_ci			break;
4678c2ecf20Sopenharmony_ci		case PIN_CONFIG_OUTPUT_ENABLE:
4688c2ecf20Sopenharmony_ci			arg = reg & SLEEP_OUTPUT_MASK;
4698c2ecf20Sopenharmony_ci			break;
4708c2ecf20Sopenharmony_ci		case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
4718c2ecf20Sopenharmony_ci			if ((reg & SLEEP_OUTPUT) || (reg & SLEEP_INPUT))
4728c2ecf20Sopenharmony_ci				return -EINVAL;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci			arg = 1;
4758c2ecf20Sopenharmony_ci			break;
4768c2ecf20Sopenharmony_ci		case PIN_CONFIG_DRIVE_STRENGTH:
4778c2ecf20Sopenharmony_ci			arg = (reg >> DRIVE_STRENGTH_SHIFT) &
4788c2ecf20Sopenharmony_ci				DRIVE_STRENGTH_MASK;
4798c2ecf20Sopenharmony_ci			break;
4808c2ecf20Sopenharmony_ci		case PIN_CONFIG_BIAS_PULL_DOWN:
4818c2ecf20Sopenharmony_ci			/* combine sleep pull down and pull down config */
4828c2ecf20Sopenharmony_ci			arg = ((reg >> SLEEP_PULL_DOWN_SHIFT) &
4838c2ecf20Sopenharmony_ci			       SLEEP_PULL_DOWN_MASK) << 16;
4848c2ecf20Sopenharmony_ci			arg |= (reg >> PULL_DOWN_SHIFT) & PULL_DOWN_MASK;
4858c2ecf20Sopenharmony_ci			break;
4868c2ecf20Sopenharmony_ci		case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
4878c2ecf20Sopenharmony_ci			arg = (reg >> INPUT_SCHMITT_SHIFT) & INPUT_SCHMITT_MASK;
4888c2ecf20Sopenharmony_ci			break;
4898c2ecf20Sopenharmony_ci		case PIN_CONFIG_BIAS_PULL_UP:
4908c2ecf20Sopenharmony_ci			/* combine sleep pull up and pull up config */
4918c2ecf20Sopenharmony_ci			arg = ((reg >> SLEEP_PULL_UP_SHIFT) &
4928c2ecf20Sopenharmony_ci			       SLEEP_PULL_UP_MASK) << 16;
4938c2ecf20Sopenharmony_ci			arg |= (reg >> PULL_UP_SHIFT) & PULL_UP_MASK;
4948c2ecf20Sopenharmony_ci			break;
4958c2ecf20Sopenharmony_ci		case PIN_CONFIG_BIAS_DISABLE:
4968c2ecf20Sopenharmony_ci			if ((reg & (SLEEP_PULL_DOWN | SLEEP_PULL_UP)) ||
4978c2ecf20Sopenharmony_ci			    (reg & (PULL_DOWN | PULL_UP_4_7K | PULL_UP_20K)))
4988c2ecf20Sopenharmony_ci				return -EINVAL;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci			arg = 1;
5018c2ecf20Sopenharmony_ci			break;
5028c2ecf20Sopenharmony_ci		case PIN_CONFIG_SLEEP_HARDWARE_STATE:
5038c2ecf20Sopenharmony_ci			arg = 0;
5048c2ecf20Sopenharmony_ci			break;
5058c2ecf20Sopenharmony_ci		default:
5068c2ecf20Sopenharmony_ci			return -ENOTSUPP;
5078c2ecf20Sopenharmony_ci		}
5088c2ecf20Sopenharmony_ci	} else {
5098c2ecf20Sopenharmony_ci		return -ENOTSUPP;
5108c2ecf20Sopenharmony_ci	}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	*config = pinconf_to_config_packed(param, arg);
5138c2ecf20Sopenharmony_ci	return 0;
5148c2ecf20Sopenharmony_ci}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_cistatic unsigned int sprd_pinconf_drive(unsigned int mA)
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	unsigned int val = 0;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	switch (mA) {
5218c2ecf20Sopenharmony_ci	case 2:
5228c2ecf20Sopenharmony_ci		break;
5238c2ecf20Sopenharmony_ci	case 4:
5248c2ecf20Sopenharmony_ci		val |= BIT(19);
5258c2ecf20Sopenharmony_ci		break;
5268c2ecf20Sopenharmony_ci	case 6:
5278c2ecf20Sopenharmony_ci		val |= BIT(20);
5288c2ecf20Sopenharmony_ci		break;
5298c2ecf20Sopenharmony_ci	case 8:
5308c2ecf20Sopenharmony_ci		val |= BIT(19) | BIT(20);
5318c2ecf20Sopenharmony_ci		break;
5328c2ecf20Sopenharmony_ci	case 10:
5338c2ecf20Sopenharmony_ci		val |= BIT(21);
5348c2ecf20Sopenharmony_ci		break;
5358c2ecf20Sopenharmony_ci	case 12:
5368c2ecf20Sopenharmony_ci		val |= BIT(21) | BIT(19);
5378c2ecf20Sopenharmony_ci		break;
5388c2ecf20Sopenharmony_ci	case 14:
5398c2ecf20Sopenharmony_ci		val |= BIT(21) | BIT(20);
5408c2ecf20Sopenharmony_ci		break;
5418c2ecf20Sopenharmony_ci	case 16:
5428c2ecf20Sopenharmony_ci		val |= BIT(19) | BIT(20) | BIT(21);
5438c2ecf20Sopenharmony_ci		break;
5448c2ecf20Sopenharmony_ci	case 20:
5458c2ecf20Sopenharmony_ci		val |= BIT(22);
5468c2ecf20Sopenharmony_ci		break;
5478c2ecf20Sopenharmony_ci	case 21:
5488c2ecf20Sopenharmony_ci		val |= BIT(22) | BIT(19);
5498c2ecf20Sopenharmony_ci		break;
5508c2ecf20Sopenharmony_ci	case 24:
5518c2ecf20Sopenharmony_ci		val |= BIT(22) | BIT(20);
5528c2ecf20Sopenharmony_ci		break;
5538c2ecf20Sopenharmony_ci	case 25:
5548c2ecf20Sopenharmony_ci		val |= BIT(22) | BIT(20) | BIT(19);
5558c2ecf20Sopenharmony_ci		break;
5568c2ecf20Sopenharmony_ci	case 27:
5578c2ecf20Sopenharmony_ci		val |= BIT(22) | BIT(21);
5588c2ecf20Sopenharmony_ci		break;
5598c2ecf20Sopenharmony_ci	case 29:
5608c2ecf20Sopenharmony_ci		val |= BIT(22) | BIT(21) | BIT(19);
5618c2ecf20Sopenharmony_ci		break;
5628c2ecf20Sopenharmony_ci	case 31:
5638c2ecf20Sopenharmony_ci		val |= BIT(22) | BIT(21) | BIT(20);
5648c2ecf20Sopenharmony_ci		break;
5658c2ecf20Sopenharmony_ci	case 33:
5668c2ecf20Sopenharmony_ci		val |= BIT(22) | BIT(21) | BIT(20) | BIT(19);
5678c2ecf20Sopenharmony_ci		break;
5688c2ecf20Sopenharmony_ci	default:
5698c2ecf20Sopenharmony_ci		break;
5708c2ecf20Sopenharmony_ci	}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	return val;
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_cistatic bool sprd_pinctrl_check_sleep_config(unsigned long *configs,
5768c2ecf20Sopenharmony_ci					    unsigned int num_configs)
5778c2ecf20Sopenharmony_ci{
5788c2ecf20Sopenharmony_ci	unsigned int param;
5798c2ecf20Sopenharmony_ci	int i;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	for (i = 0; i < num_configs; i++) {
5828c2ecf20Sopenharmony_ci		param = pinconf_to_config_param(configs[i]);
5838c2ecf20Sopenharmony_ci		if (param == PIN_CONFIG_SLEEP_HARDWARE_STATE)
5848c2ecf20Sopenharmony_ci			return true;
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	return false;
5888c2ecf20Sopenharmony_ci}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_cistatic int sprd_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin_id,
5918c2ecf20Sopenharmony_ci			    unsigned long *configs, unsigned int num_configs)
5928c2ecf20Sopenharmony_ci{
5938c2ecf20Sopenharmony_ci	struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
5948c2ecf20Sopenharmony_ci	struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id);
5958c2ecf20Sopenharmony_ci	bool is_sleep_config;
5968c2ecf20Sopenharmony_ci	unsigned long reg;
5978c2ecf20Sopenharmony_ci	int i;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	if (!pin)
6008c2ecf20Sopenharmony_ci		return -EINVAL;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	is_sleep_config = sprd_pinctrl_check_sleep_config(configs, num_configs);
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	for (i = 0; i < num_configs; i++) {
6058c2ecf20Sopenharmony_ci		unsigned int param, arg, shift, mask, val;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci		param = pinconf_to_config_param(configs[i]);
6088c2ecf20Sopenharmony_ci		arg = pinconf_to_config_argument(configs[i]);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci		val = 0;
6118c2ecf20Sopenharmony_ci		shift = 0;
6128c2ecf20Sopenharmony_ci		mask = 0;
6138c2ecf20Sopenharmony_ci		if (pin->type == GLOBAL_CTRL_PIN &&
6148c2ecf20Sopenharmony_ci		    param == SPRD_PIN_CONFIG_CONTROL) {
6158c2ecf20Sopenharmony_ci			val = arg;
6168c2ecf20Sopenharmony_ci		} else if (pin->type == COMMON_PIN || pin->type == MISC_PIN) {
6178c2ecf20Sopenharmony_ci			switch (param) {
6188c2ecf20Sopenharmony_ci			case SPRD_PIN_CONFIG_SLEEP_MODE:
6198c2ecf20Sopenharmony_ci				if (arg & AP_SLEEP)
6208c2ecf20Sopenharmony_ci					val |= AP_SLEEP_MODE;
6218c2ecf20Sopenharmony_ci				if (arg & PUBCP_SLEEP)
6228c2ecf20Sopenharmony_ci					val |= PUBCP_SLEEP_MODE;
6238c2ecf20Sopenharmony_ci				if (arg & TGLDSP_SLEEP)
6248c2ecf20Sopenharmony_ci					val |= TGLDSP_SLEEP_MODE;
6258c2ecf20Sopenharmony_ci				if (arg & AGDSP_SLEEP)
6268c2ecf20Sopenharmony_ci					val |= AGDSP_SLEEP_MODE;
6278c2ecf20Sopenharmony_ci				if (arg & CM4_SLEEP)
6288c2ecf20Sopenharmony_ci					val |= CM4_SLEEP_MODE;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci				mask = SLEEP_MODE_MASK;
6318c2ecf20Sopenharmony_ci				shift = SLEEP_MODE_SHIFT;
6328c2ecf20Sopenharmony_ci				break;
6338c2ecf20Sopenharmony_ci			case PIN_CONFIG_INPUT_ENABLE:
6348c2ecf20Sopenharmony_ci				if (is_sleep_config == true) {
6358c2ecf20Sopenharmony_ci					if (arg > 0)
6368c2ecf20Sopenharmony_ci						val |= SLEEP_INPUT;
6378c2ecf20Sopenharmony_ci					else
6388c2ecf20Sopenharmony_ci						val &= ~SLEEP_INPUT;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci					mask = SLEEP_INPUT_MASK;
6418c2ecf20Sopenharmony_ci					shift = SLEEP_INPUT_SHIFT;
6428c2ecf20Sopenharmony_ci				}
6438c2ecf20Sopenharmony_ci				break;
6448c2ecf20Sopenharmony_ci			case PIN_CONFIG_OUTPUT_ENABLE:
6458c2ecf20Sopenharmony_ci				if (is_sleep_config == true) {
6468c2ecf20Sopenharmony_ci					if (arg > 0)
6478c2ecf20Sopenharmony_ci						val |= SLEEP_OUTPUT;
6488c2ecf20Sopenharmony_ci					else
6498c2ecf20Sopenharmony_ci						val &= ~SLEEP_OUTPUT;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci					mask = SLEEP_OUTPUT_MASK;
6528c2ecf20Sopenharmony_ci					shift = SLEEP_OUTPUT_SHIFT;
6538c2ecf20Sopenharmony_ci				}
6548c2ecf20Sopenharmony_ci				break;
6558c2ecf20Sopenharmony_ci			case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
6568c2ecf20Sopenharmony_ci				if (is_sleep_config == true) {
6578c2ecf20Sopenharmony_ci					val = shift = 0;
6588c2ecf20Sopenharmony_ci					mask = SLEEP_OUTPUT | SLEEP_INPUT;
6598c2ecf20Sopenharmony_ci				}
6608c2ecf20Sopenharmony_ci				break;
6618c2ecf20Sopenharmony_ci			case PIN_CONFIG_DRIVE_STRENGTH:
6628c2ecf20Sopenharmony_ci				if (arg < 2 || arg > 60)
6638c2ecf20Sopenharmony_ci					return -EINVAL;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci				val = sprd_pinconf_drive(arg);
6668c2ecf20Sopenharmony_ci				mask = DRIVE_STRENGTH_MASK;
6678c2ecf20Sopenharmony_ci				shift = DRIVE_STRENGTH_SHIFT;
6688c2ecf20Sopenharmony_ci				break;
6698c2ecf20Sopenharmony_ci			case PIN_CONFIG_BIAS_PULL_DOWN:
6708c2ecf20Sopenharmony_ci				if (is_sleep_config == true) {
6718c2ecf20Sopenharmony_ci					val |= SLEEP_PULL_DOWN;
6728c2ecf20Sopenharmony_ci					mask = SLEEP_PULL_DOWN_MASK;
6738c2ecf20Sopenharmony_ci					shift = SLEEP_PULL_DOWN_SHIFT;
6748c2ecf20Sopenharmony_ci				} else {
6758c2ecf20Sopenharmony_ci					val |= PULL_DOWN;
6768c2ecf20Sopenharmony_ci					mask = PULL_DOWN_MASK;
6778c2ecf20Sopenharmony_ci					shift = PULL_DOWN_SHIFT;
6788c2ecf20Sopenharmony_ci				}
6798c2ecf20Sopenharmony_ci				break;
6808c2ecf20Sopenharmony_ci			case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
6818c2ecf20Sopenharmony_ci				if (arg > 0)
6828c2ecf20Sopenharmony_ci					val |= INPUT_SCHMITT;
6838c2ecf20Sopenharmony_ci				else
6848c2ecf20Sopenharmony_ci					val &= ~INPUT_SCHMITT;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci				mask = INPUT_SCHMITT_MASK;
6878c2ecf20Sopenharmony_ci				shift = INPUT_SCHMITT_SHIFT;
6888c2ecf20Sopenharmony_ci				break;
6898c2ecf20Sopenharmony_ci			case PIN_CONFIG_BIAS_PULL_UP:
6908c2ecf20Sopenharmony_ci				if (is_sleep_config == true) {
6918c2ecf20Sopenharmony_ci					val |= SLEEP_PULL_UP;
6928c2ecf20Sopenharmony_ci					mask = SLEEP_PULL_UP_MASK;
6938c2ecf20Sopenharmony_ci					shift = SLEEP_PULL_UP_SHIFT;
6948c2ecf20Sopenharmony_ci				} else {
6958c2ecf20Sopenharmony_ci					if (arg == 20000)
6968c2ecf20Sopenharmony_ci						val |= PULL_UP_20K;
6978c2ecf20Sopenharmony_ci					else if (arg == 4700)
6988c2ecf20Sopenharmony_ci						val |= PULL_UP_4_7K;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci					mask = PULL_UP_MASK;
7018c2ecf20Sopenharmony_ci					shift = PULL_UP_SHIFT;
7028c2ecf20Sopenharmony_ci				}
7038c2ecf20Sopenharmony_ci				break;
7048c2ecf20Sopenharmony_ci			case PIN_CONFIG_BIAS_DISABLE:
7058c2ecf20Sopenharmony_ci				if (is_sleep_config == true) {
7068c2ecf20Sopenharmony_ci					val = shift = 0;
7078c2ecf20Sopenharmony_ci					mask = SLEEP_PULL_DOWN | SLEEP_PULL_UP;
7088c2ecf20Sopenharmony_ci				} else {
7098c2ecf20Sopenharmony_ci					val = shift = 0;
7108c2ecf20Sopenharmony_ci					mask = PULL_DOWN | PULL_UP_20K |
7118c2ecf20Sopenharmony_ci						PULL_UP_4_7K;
7128c2ecf20Sopenharmony_ci				}
7138c2ecf20Sopenharmony_ci				break;
7148c2ecf20Sopenharmony_ci			case PIN_CONFIG_SLEEP_HARDWARE_STATE:
7158c2ecf20Sopenharmony_ci				continue;
7168c2ecf20Sopenharmony_ci			default:
7178c2ecf20Sopenharmony_ci				return -ENOTSUPP;
7188c2ecf20Sopenharmony_ci			}
7198c2ecf20Sopenharmony_ci		} else {
7208c2ecf20Sopenharmony_ci			return -ENOTSUPP;
7218c2ecf20Sopenharmony_ci		}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci		if (pin->type == GLOBAL_CTRL_PIN) {
7248c2ecf20Sopenharmony_ci			reg = readl((void __iomem *)pin->reg);
7258c2ecf20Sopenharmony_ci			reg &= ~(PINCTRL_BIT_MASK(pin->bit_width)
7268c2ecf20Sopenharmony_ci				<< pin->bit_offset);
7278c2ecf20Sopenharmony_ci			reg |= (val & PINCTRL_BIT_MASK(pin->bit_width))
7288c2ecf20Sopenharmony_ci				<< pin->bit_offset;
7298c2ecf20Sopenharmony_ci			writel(reg, (void __iomem *)pin->reg);
7308c2ecf20Sopenharmony_ci		} else {
7318c2ecf20Sopenharmony_ci			reg = readl((void __iomem *)pin->reg);
7328c2ecf20Sopenharmony_ci			reg &= ~(mask << shift);
7338c2ecf20Sopenharmony_ci			reg |= val;
7348c2ecf20Sopenharmony_ci			writel(reg, (void __iomem *)pin->reg);
7358c2ecf20Sopenharmony_ci		}
7368c2ecf20Sopenharmony_ci	}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	return 0;
7398c2ecf20Sopenharmony_ci}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_cistatic int sprd_pinconf_group_get(struct pinctrl_dev *pctldev,
7428c2ecf20Sopenharmony_ci				  unsigned int selector, unsigned long *config)
7438c2ecf20Sopenharmony_ci{
7448c2ecf20Sopenharmony_ci	struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
7458c2ecf20Sopenharmony_ci	struct sprd_pinctrl_soc_info *info = pctl->info;
7468c2ecf20Sopenharmony_ci	struct sprd_pin_group *grp;
7478c2ecf20Sopenharmony_ci	unsigned int pin_id;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	if (selector >= info->ngroups)
7508c2ecf20Sopenharmony_ci		return -EINVAL;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	grp = &info->groups[selector];
7538c2ecf20Sopenharmony_ci	pin_id = grp->pins[0];
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	return sprd_pinconf_get(pctldev, pin_id, config);
7568c2ecf20Sopenharmony_ci}
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_cistatic int sprd_pinconf_group_set(struct pinctrl_dev *pctldev,
7598c2ecf20Sopenharmony_ci				  unsigned int selector,
7608c2ecf20Sopenharmony_ci				  unsigned long *configs,
7618c2ecf20Sopenharmony_ci				  unsigned int num_configs)
7628c2ecf20Sopenharmony_ci{
7638c2ecf20Sopenharmony_ci	struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
7648c2ecf20Sopenharmony_ci	struct sprd_pinctrl_soc_info *info = pctl->info;
7658c2ecf20Sopenharmony_ci	struct sprd_pin_group *grp;
7668c2ecf20Sopenharmony_ci	int ret, i;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	if (selector >= info->ngroups)
7698c2ecf20Sopenharmony_ci		return -EINVAL;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	grp = &info->groups[selector];
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	for (i = 0; i < grp->npins; i++) {
7748c2ecf20Sopenharmony_ci		unsigned int pin_id = grp->pins[i];
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci		ret = sprd_pinconf_set(pctldev, pin_id, configs, num_configs);
7778c2ecf20Sopenharmony_ci		if (ret)
7788c2ecf20Sopenharmony_ci			return ret;
7798c2ecf20Sopenharmony_ci	}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	return 0;
7828c2ecf20Sopenharmony_ci}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_cistatic int sprd_pinconf_get_config(struct pinctrl_dev *pctldev,
7858c2ecf20Sopenharmony_ci				   unsigned int pin_id,
7868c2ecf20Sopenharmony_ci				   unsigned long *config)
7878c2ecf20Sopenharmony_ci{
7888c2ecf20Sopenharmony_ci	struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
7898c2ecf20Sopenharmony_ci	struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	if (!pin)
7928c2ecf20Sopenharmony_ci		return -EINVAL;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	if (pin->type == GLOBAL_CTRL_PIN) {
7958c2ecf20Sopenharmony_ci		*config = (readl((void __iomem *)pin->reg) >>
7968c2ecf20Sopenharmony_ci			   pin->bit_offset) & PINCTRL_BIT_MASK(pin->bit_width);
7978c2ecf20Sopenharmony_ci	} else {
7988c2ecf20Sopenharmony_ci		*config = readl((void __iomem *)pin->reg);
7998c2ecf20Sopenharmony_ci	}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	return 0;
8028c2ecf20Sopenharmony_ci}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_cistatic void sprd_pinconf_dbg_show(struct pinctrl_dev *pctldev,
8058c2ecf20Sopenharmony_ci				  struct seq_file *s, unsigned int pin_id)
8068c2ecf20Sopenharmony_ci{
8078c2ecf20Sopenharmony_ci	unsigned long config;
8088c2ecf20Sopenharmony_ci	int ret;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	ret = sprd_pinconf_get_config(pctldev, pin_id, &config);
8118c2ecf20Sopenharmony_ci	if (ret)
8128c2ecf20Sopenharmony_ci		return;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	seq_printf(s, "0x%lx", config);
8158c2ecf20Sopenharmony_ci}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_cistatic void sprd_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
8188c2ecf20Sopenharmony_ci					struct seq_file *s,
8198c2ecf20Sopenharmony_ci					unsigned int selector)
8208c2ecf20Sopenharmony_ci{
8218c2ecf20Sopenharmony_ci	struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
8228c2ecf20Sopenharmony_ci	struct sprd_pinctrl_soc_info *info = pctl->info;
8238c2ecf20Sopenharmony_ci	struct sprd_pin_group *grp;
8248c2ecf20Sopenharmony_ci	unsigned long config;
8258c2ecf20Sopenharmony_ci	const char *name;
8268c2ecf20Sopenharmony_ci	int i, ret;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	if (selector >= info->ngroups)
8298c2ecf20Sopenharmony_ci		return;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	grp = &info->groups[selector];
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	seq_putc(s, '\n');
8348c2ecf20Sopenharmony_ci	for (i = 0; i < grp->npins; i++, config++) {
8358c2ecf20Sopenharmony_ci		unsigned int pin_id = grp->pins[i];
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci		name = pin_get_name(pctldev, pin_id);
8388c2ecf20Sopenharmony_ci		ret = sprd_pinconf_get_config(pctldev, pin_id, &config);
8398c2ecf20Sopenharmony_ci		if (ret)
8408c2ecf20Sopenharmony_ci			return;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci		seq_printf(s, "%s: 0x%lx ", name, config);
8438c2ecf20Sopenharmony_ci	}
8448c2ecf20Sopenharmony_ci}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_cistatic const struct pinconf_ops sprd_pinconf_ops = {
8478c2ecf20Sopenharmony_ci	.is_generic = true,
8488c2ecf20Sopenharmony_ci	.pin_config_get = sprd_pinconf_get,
8498c2ecf20Sopenharmony_ci	.pin_config_set = sprd_pinconf_set,
8508c2ecf20Sopenharmony_ci	.pin_config_group_get = sprd_pinconf_group_get,
8518c2ecf20Sopenharmony_ci	.pin_config_group_set = sprd_pinconf_group_set,
8528c2ecf20Sopenharmony_ci	.pin_config_dbg_show = sprd_pinconf_dbg_show,
8538c2ecf20Sopenharmony_ci	.pin_config_group_dbg_show = sprd_pinconf_group_dbg_show,
8548c2ecf20Sopenharmony_ci};
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_cistatic const struct pinconf_generic_params sprd_dt_params[] = {
8578c2ecf20Sopenharmony_ci	{"sprd,control", SPRD_PIN_CONFIG_CONTROL, 0},
8588c2ecf20Sopenharmony_ci	{"sprd,sleep-mode", SPRD_PIN_CONFIG_SLEEP_MODE, 0},
8598c2ecf20Sopenharmony_ci};
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
8628c2ecf20Sopenharmony_cistatic const struct pin_config_item sprd_conf_items[] = {
8638c2ecf20Sopenharmony_ci	PCONFDUMP(SPRD_PIN_CONFIG_CONTROL, "global control", NULL, true),
8648c2ecf20Sopenharmony_ci	PCONFDUMP(SPRD_PIN_CONFIG_SLEEP_MODE, "sleep mode", NULL, true),
8658c2ecf20Sopenharmony_ci};
8668c2ecf20Sopenharmony_ci#endif
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_cistatic struct pinctrl_desc sprd_pinctrl_desc = {
8698c2ecf20Sopenharmony_ci	.pctlops = &sprd_pctrl_ops,
8708c2ecf20Sopenharmony_ci	.pmxops = &sprd_pmx_ops,
8718c2ecf20Sopenharmony_ci	.confops = &sprd_pinconf_ops,
8728c2ecf20Sopenharmony_ci	.num_custom_params = ARRAY_SIZE(sprd_dt_params),
8738c2ecf20Sopenharmony_ci	.custom_params = sprd_dt_params,
8748c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
8758c2ecf20Sopenharmony_ci	.custom_conf_items = sprd_conf_items,
8768c2ecf20Sopenharmony_ci#endif
8778c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
8788c2ecf20Sopenharmony_ci};
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_cistatic int sprd_pinctrl_parse_groups(struct device_node *np,
8818c2ecf20Sopenharmony_ci				     struct sprd_pinctrl *sprd_pctl,
8828c2ecf20Sopenharmony_ci				     struct sprd_pin_group *grp)
8838c2ecf20Sopenharmony_ci{
8848c2ecf20Sopenharmony_ci	struct property *prop;
8858c2ecf20Sopenharmony_ci	const char *pin_name;
8868c2ecf20Sopenharmony_ci	int ret, i = 0;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	ret = of_property_count_strings(np, "pins");
8898c2ecf20Sopenharmony_ci	if (ret < 0)
8908c2ecf20Sopenharmony_ci		return ret;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	grp->name = np->name;
8938c2ecf20Sopenharmony_ci	grp->npins = ret;
8948c2ecf20Sopenharmony_ci	grp->pins = devm_kcalloc(sprd_pctl->dev,
8958c2ecf20Sopenharmony_ci				 grp->npins, sizeof(unsigned int),
8968c2ecf20Sopenharmony_ci				 GFP_KERNEL);
8978c2ecf20Sopenharmony_ci	if (!grp->pins)
8988c2ecf20Sopenharmony_ci		return -ENOMEM;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	of_property_for_each_string(np, "pins", prop, pin_name) {
9018c2ecf20Sopenharmony_ci		ret = sprd_pinctrl_get_id_by_name(sprd_pctl, pin_name);
9028c2ecf20Sopenharmony_ci		if (ret >= 0)
9038c2ecf20Sopenharmony_ci			grp->pins[i++] = ret;
9048c2ecf20Sopenharmony_ci	}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	for (i = 0; i < grp->npins; i++) {
9078c2ecf20Sopenharmony_ci		dev_dbg(sprd_pctl->dev,
9088c2ecf20Sopenharmony_ci			"Group[%s] contains [%d] pins: id = %d\n",
9098c2ecf20Sopenharmony_ci			grp->name, grp->npins, grp->pins[i]);
9108c2ecf20Sopenharmony_ci	}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	return 0;
9138c2ecf20Sopenharmony_ci}
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_cistatic unsigned int sprd_pinctrl_get_groups(struct device_node *np)
9168c2ecf20Sopenharmony_ci{
9178c2ecf20Sopenharmony_ci	struct device_node *child;
9188c2ecf20Sopenharmony_ci	unsigned int group_cnt, cnt;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	group_cnt = of_get_child_count(np);
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	for_each_child_of_node(np, child) {
9238c2ecf20Sopenharmony_ci		cnt = of_get_child_count(child);
9248c2ecf20Sopenharmony_ci		if (cnt > 0)
9258c2ecf20Sopenharmony_ci			group_cnt += cnt;
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	return group_cnt;
9298c2ecf20Sopenharmony_ci}
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_cistatic int sprd_pinctrl_parse_dt(struct sprd_pinctrl *sprd_pctl)
9328c2ecf20Sopenharmony_ci{
9338c2ecf20Sopenharmony_ci	struct sprd_pinctrl_soc_info *info = sprd_pctl->info;
9348c2ecf20Sopenharmony_ci	struct device_node *np = sprd_pctl->dev->of_node;
9358c2ecf20Sopenharmony_ci	struct device_node *child, *sub_child;
9368c2ecf20Sopenharmony_ci	struct sprd_pin_group *grp;
9378c2ecf20Sopenharmony_ci	const char **temp;
9388c2ecf20Sopenharmony_ci	int ret;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	if (!np)
9418c2ecf20Sopenharmony_ci		return -ENODEV;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	info->ngroups = sprd_pinctrl_get_groups(np);
9448c2ecf20Sopenharmony_ci	if (!info->ngroups)
9458c2ecf20Sopenharmony_ci		return 0;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	info->groups = devm_kcalloc(sprd_pctl->dev,
9488c2ecf20Sopenharmony_ci				    info->ngroups,
9498c2ecf20Sopenharmony_ci				    sizeof(struct sprd_pin_group),
9508c2ecf20Sopenharmony_ci				    GFP_KERNEL);
9518c2ecf20Sopenharmony_ci	if (!info->groups)
9528c2ecf20Sopenharmony_ci		return -ENOMEM;
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	info->grp_names = devm_kcalloc(sprd_pctl->dev,
9558c2ecf20Sopenharmony_ci				       info->ngroups, sizeof(char *),
9568c2ecf20Sopenharmony_ci				       GFP_KERNEL);
9578c2ecf20Sopenharmony_ci	if (!info->grp_names)
9588c2ecf20Sopenharmony_ci		return -ENOMEM;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	temp = info->grp_names;
9618c2ecf20Sopenharmony_ci	grp = info->groups;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	for_each_child_of_node(np, child) {
9648c2ecf20Sopenharmony_ci		ret = sprd_pinctrl_parse_groups(child, sprd_pctl, grp);
9658c2ecf20Sopenharmony_ci		if (ret) {
9668c2ecf20Sopenharmony_ci			of_node_put(child);
9678c2ecf20Sopenharmony_ci			return ret;
9688c2ecf20Sopenharmony_ci		}
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci		*temp++ = grp->name;
9718c2ecf20Sopenharmony_ci		grp++;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci		if (of_get_child_count(child) > 0) {
9748c2ecf20Sopenharmony_ci			for_each_child_of_node(child, sub_child) {
9758c2ecf20Sopenharmony_ci				ret = sprd_pinctrl_parse_groups(sub_child,
9768c2ecf20Sopenharmony_ci								sprd_pctl, grp);
9778c2ecf20Sopenharmony_ci				if (ret) {
9788c2ecf20Sopenharmony_ci					of_node_put(sub_child);
9798c2ecf20Sopenharmony_ci					of_node_put(child);
9808c2ecf20Sopenharmony_ci					return ret;
9818c2ecf20Sopenharmony_ci				}
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci				*temp++ = grp->name;
9848c2ecf20Sopenharmony_ci				grp++;
9858c2ecf20Sopenharmony_ci			}
9868c2ecf20Sopenharmony_ci		}
9878c2ecf20Sopenharmony_ci	}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	return 0;
9908c2ecf20Sopenharmony_ci}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_cistatic int sprd_pinctrl_add_pins(struct sprd_pinctrl *sprd_pctl,
9938c2ecf20Sopenharmony_ci				 struct sprd_pins_info *sprd_soc_pin_info,
9948c2ecf20Sopenharmony_ci				 int pins_cnt)
9958c2ecf20Sopenharmony_ci{
9968c2ecf20Sopenharmony_ci	struct sprd_pinctrl_soc_info *info = sprd_pctl->info;
9978c2ecf20Sopenharmony_ci	unsigned int ctrl_pin = 0, com_pin = 0;
9988c2ecf20Sopenharmony_ci	struct sprd_pin *pin;
9998c2ecf20Sopenharmony_ci	int i;
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	info->npins = pins_cnt;
10028c2ecf20Sopenharmony_ci	info->pins = devm_kcalloc(sprd_pctl->dev,
10038c2ecf20Sopenharmony_ci				  info->npins, sizeof(struct sprd_pin),
10048c2ecf20Sopenharmony_ci				  GFP_KERNEL);
10058c2ecf20Sopenharmony_ci	if (!info->pins)
10068c2ecf20Sopenharmony_ci		return -ENOMEM;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	for (i = 0, pin = info->pins; i < info->npins; i++, pin++) {
10098c2ecf20Sopenharmony_ci		unsigned int reg;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci		pin->name = sprd_soc_pin_info[i].name;
10128c2ecf20Sopenharmony_ci		pin->type = sprd_soc_pin_info[i].type;
10138c2ecf20Sopenharmony_ci		pin->number = sprd_soc_pin_info[i].num;
10148c2ecf20Sopenharmony_ci		reg = sprd_soc_pin_info[i].reg;
10158c2ecf20Sopenharmony_ci		if (pin->type == GLOBAL_CTRL_PIN) {
10168c2ecf20Sopenharmony_ci			pin->reg = (unsigned long)sprd_pctl->base +
10178c2ecf20Sopenharmony_ci				PINCTRL_REG_LEN * reg;
10188c2ecf20Sopenharmony_ci			pin->bit_offset = sprd_soc_pin_info[i].bit_offset;
10198c2ecf20Sopenharmony_ci			pin->bit_width = sprd_soc_pin_info[i].bit_width;
10208c2ecf20Sopenharmony_ci			ctrl_pin++;
10218c2ecf20Sopenharmony_ci		} else if (pin->type == COMMON_PIN) {
10228c2ecf20Sopenharmony_ci			pin->reg = (unsigned long)sprd_pctl->base +
10238c2ecf20Sopenharmony_ci				PINCTRL_REG_OFFSET + PINCTRL_REG_LEN *
10248c2ecf20Sopenharmony_ci				(i - ctrl_pin);
10258c2ecf20Sopenharmony_ci			com_pin++;
10268c2ecf20Sopenharmony_ci		} else if (pin->type == MISC_PIN) {
10278c2ecf20Sopenharmony_ci			pin->reg = (unsigned long)sprd_pctl->base +
10288c2ecf20Sopenharmony_ci				PINCTRL_REG_MISC_OFFSET + PINCTRL_REG_LEN *
10298c2ecf20Sopenharmony_ci				(i - ctrl_pin - com_pin);
10308c2ecf20Sopenharmony_ci		}
10318c2ecf20Sopenharmony_ci	}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	for (i = 0, pin = info->pins; i < info->npins; pin++, i++) {
10348c2ecf20Sopenharmony_ci		dev_dbg(sprd_pctl->dev, "pin name[%s-%d], type = %d, "
10358c2ecf20Sopenharmony_ci			"bit offset = %ld, bit width = %ld, reg = 0x%lx\n",
10368c2ecf20Sopenharmony_ci			pin->name, pin->number, pin->type,
10378c2ecf20Sopenharmony_ci			pin->bit_offset, pin->bit_width, pin->reg);
10388c2ecf20Sopenharmony_ci	}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	return 0;
10418c2ecf20Sopenharmony_ci}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ciint sprd_pinctrl_core_probe(struct platform_device *pdev,
10448c2ecf20Sopenharmony_ci			    struct sprd_pins_info *sprd_soc_pin_info,
10458c2ecf20Sopenharmony_ci			    int pins_cnt)
10468c2ecf20Sopenharmony_ci{
10478c2ecf20Sopenharmony_ci	struct sprd_pinctrl *sprd_pctl;
10488c2ecf20Sopenharmony_ci	struct sprd_pinctrl_soc_info *pinctrl_info;
10498c2ecf20Sopenharmony_ci	struct pinctrl_pin_desc *pin_desc;
10508c2ecf20Sopenharmony_ci	int ret, i;
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	sprd_pctl = devm_kzalloc(&pdev->dev, sizeof(struct sprd_pinctrl),
10538c2ecf20Sopenharmony_ci				 GFP_KERNEL);
10548c2ecf20Sopenharmony_ci	if (!sprd_pctl)
10558c2ecf20Sopenharmony_ci		return -ENOMEM;
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	sprd_pctl->base = devm_platform_ioremap_resource(pdev, 0);
10588c2ecf20Sopenharmony_ci	if (IS_ERR(sprd_pctl->base))
10598c2ecf20Sopenharmony_ci		return PTR_ERR(sprd_pctl->base);
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	pinctrl_info = devm_kzalloc(&pdev->dev,
10628c2ecf20Sopenharmony_ci				    sizeof(struct sprd_pinctrl_soc_info),
10638c2ecf20Sopenharmony_ci				    GFP_KERNEL);
10648c2ecf20Sopenharmony_ci	if (!pinctrl_info)
10658c2ecf20Sopenharmony_ci		return -ENOMEM;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	sprd_pctl->info = pinctrl_info;
10688c2ecf20Sopenharmony_ci	sprd_pctl->dev = &pdev->dev;
10698c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, sprd_pctl);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	ret = sprd_pinctrl_add_pins(sprd_pctl, sprd_soc_pin_info, pins_cnt);
10728c2ecf20Sopenharmony_ci	if (ret) {
10738c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "fail to add pins information\n");
10748c2ecf20Sopenharmony_ci		return ret;
10758c2ecf20Sopenharmony_ci	}
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	ret = sprd_pinctrl_parse_dt(sprd_pctl);
10788c2ecf20Sopenharmony_ci	if (ret) {
10798c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "fail to parse dt properties\n");
10808c2ecf20Sopenharmony_ci		return ret;
10818c2ecf20Sopenharmony_ci	}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	pin_desc = devm_kcalloc(&pdev->dev,
10848c2ecf20Sopenharmony_ci				pinctrl_info->npins,
10858c2ecf20Sopenharmony_ci				sizeof(struct pinctrl_pin_desc),
10868c2ecf20Sopenharmony_ci				GFP_KERNEL);
10878c2ecf20Sopenharmony_ci	if (!pin_desc)
10888c2ecf20Sopenharmony_ci		return -ENOMEM;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	for (i = 0; i < pinctrl_info->npins; i++) {
10918c2ecf20Sopenharmony_ci		pin_desc[i].number = pinctrl_info->pins[i].number;
10928c2ecf20Sopenharmony_ci		pin_desc[i].name = pinctrl_info->pins[i].name;
10938c2ecf20Sopenharmony_ci		pin_desc[i].drv_data = pinctrl_info;
10948c2ecf20Sopenharmony_ci	}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	sprd_pinctrl_desc.pins = pin_desc;
10978c2ecf20Sopenharmony_ci	sprd_pinctrl_desc.name = dev_name(&pdev->dev);
10988c2ecf20Sopenharmony_ci	sprd_pinctrl_desc.npins = pinctrl_info->npins;
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	sprd_pctl->pctl = pinctrl_register(&sprd_pinctrl_desc,
11018c2ecf20Sopenharmony_ci					   &pdev->dev, (void *)sprd_pctl);
11028c2ecf20Sopenharmony_ci	if (IS_ERR(sprd_pctl->pctl)) {
11038c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "could not register pinctrl driver\n");
11048c2ecf20Sopenharmony_ci		return PTR_ERR(sprd_pctl->pctl);
11058c2ecf20Sopenharmony_ci	}
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	return 0;
11088c2ecf20Sopenharmony_ci}
11098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sprd_pinctrl_core_probe);
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ciint sprd_pinctrl_remove(struct platform_device *pdev)
11128c2ecf20Sopenharmony_ci{
11138c2ecf20Sopenharmony_ci	struct sprd_pinctrl *sprd_pctl = platform_get_drvdata(pdev);
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	pinctrl_unregister(sprd_pctl->pctl);
11168c2ecf20Sopenharmony_ci	return 0;
11178c2ecf20Sopenharmony_ci}
11188c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sprd_pinctrl_remove);
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_civoid sprd_pinctrl_shutdown(struct platform_device *pdev)
11218c2ecf20Sopenharmony_ci{
11228c2ecf20Sopenharmony_ci	struct pinctrl *pinctl;
11238c2ecf20Sopenharmony_ci	struct pinctrl_state *state;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	pinctl = devm_pinctrl_get(&pdev->dev);
11268c2ecf20Sopenharmony_ci	if (IS_ERR(pinctl))
11278c2ecf20Sopenharmony_ci		return;
11288c2ecf20Sopenharmony_ci	state = pinctrl_lookup_state(pinctl, "shutdown");
11298c2ecf20Sopenharmony_ci	if (IS_ERR(state))
11308c2ecf20Sopenharmony_ci		return;
11318c2ecf20Sopenharmony_ci	pinctrl_select_state(pinctl, state);
11328c2ecf20Sopenharmony_ci}
11338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sprd_pinctrl_shutdown);
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SPREADTRUM Pin Controller Driver");
11368c2ecf20Sopenharmony_ciMODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>");
11378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1138