xref: /OK3568_Linux_fs/kernel/drivers/pinctrl/samsung/pinctrl-samsung.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's.
4*4882a593Smuzhiyun //
5*4882a593Smuzhiyun // Copyright (c) 2012 Samsung Electronics Co., Ltd.
6*4882a593Smuzhiyun //		http://www.samsung.com
7*4882a593Smuzhiyun // Copyright (c) 2012 Linaro Ltd
8*4882a593Smuzhiyun //		http://www.linaro.org
9*4882a593Smuzhiyun //
10*4882a593Smuzhiyun // Author: Thomas Abraham <thomas.ab@samsung.com>
11*4882a593Smuzhiyun //
12*4882a593Smuzhiyun // This driver implements the Samsung pinctrl driver. It supports setting up of
13*4882a593Smuzhiyun // pinmux and pinconf configurations. The gpiolib interface is also included.
14*4882a593Smuzhiyun // External interrupt (gpio and wakeup) support are not included in this driver
15*4882a593Smuzhiyun // but provides extensions to which platform specific implementation of the gpio
16*4882a593Smuzhiyun // and wakeup interrupts can be hooked to.
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <linux/init.h>
19*4882a593Smuzhiyun #include <linux/platform_device.h>
20*4882a593Smuzhiyun #include <linux/io.h>
21*4882a593Smuzhiyun #include <linux/slab.h>
22*4882a593Smuzhiyun #include <linux/err.h>
23*4882a593Smuzhiyun #include <linux/gpio/driver.h>
24*4882a593Smuzhiyun #include <linux/irqdomain.h>
25*4882a593Smuzhiyun #include <linux/of_device.h>
26*4882a593Smuzhiyun #include <linux/spinlock.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #include <dt-bindings/pinctrl/samsung.h>
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #include "../core.h"
31*4882a593Smuzhiyun #include "pinctrl-samsung.h"
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun /* maximum number of the memory resources */
34*4882a593Smuzhiyun #define	SAMSUNG_PINCTRL_NUM_RESOURCES	2
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun /* list of all possible config options supported */
37*4882a593Smuzhiyun static struct pin_config {
38*4882a593Smuzhiyun 	const char *property;
39*4882a593Smuzhiyun 	enum pincfg_type param;
40*4882a593Smuzhiyun } cfg_params[] = {
41*4882a593Smuzhiyun 	{ "samsung,pin-pud", PINCFG_TYPE_PUD },
42*4882a593Smuzhiyun 	{ "samsung,pin-drv", PINCFG_TYPE_DRV },
43*4882a593Smuzhiyun 	{ "samsung,pin-con-pdn", PINCFG_TYPE_CON_PDN },
44*4882a593Smuzhiyun 	{ "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN },
45*4882a593Smuzhiyun 	{ "samsung,pin-val", PINCFG_TYPE_DAT },
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun static unsigned int pin_base;
49*4882a593Smuzhiyun 
samsung_get_group_count(struct pinctrl_dev * pctldev)50*4882a593Smuzhiyun static int samsung_get_group_count(struct pinctrl_dev *pctldev)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun 	struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev);
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	return pmx->nr_groups;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun 
samsung_get_group_name(struct pinctrl_dev * pctldev,unsigned group)57*4882a593Smuzhiyun static const char *samsung_get_group_name(struct pinctrl_dev *pctldev,
58*4882a593Smuzhiyun 						unsigned group)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	return pmx->pin_groups[group].name;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
samsung_get_group_pins(struct pinctrl_dev * pctldev,unsigned group,const unsigned ** pins,unsigned * num_pins)65*4882a593Smuzhiyun static int samsung_get_group_pins(struct pinctrl_dev *pctldev,
66*4882a593Smuzhiyun 					unsigned group,
67*4882a593Smuzhiyun 					const unsigned **pins,
68*4882a593Smuzhiyun 					unsigned *num_pins)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev);
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	*pins = pmx->pin_groups[group].pins;
73*4882a593Smuzhiyun 	*num_pins = pmx->pin_groups[group].num_pins;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	return 0;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun 
reserve_map(struct device * dev,struct pinctrl_map ** map,unsigned * reserved_maps,unsigned * num_maps,unsigned reserve)78*4882a593Smuzhiyun static int reserve_map(struct device *dev, struct pinctrl_map **map,
79*4882a593Smuzhiyun 		       unsigned *reserved_maps, unsigned *num_maps,
80*4882a593Smuzhiyun 		       unsigned reserve)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	unsigned old_num = *reserved_maps;
83*4882a593Smuzhiyun 	unsigned new_num = *num_maps + reserve;
84*4882a593Smuzhiyun 	struct pinctrl_map *new_map;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	if (old_num >= new_num)
87*4882a593Smuzhiyun 		return 0;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
90*4882a593Smuzhiyun 	if (!new_map)
91*4882a593Smuzhiyun 		return -ENOMEM;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	*map = new_map;
96*4882a593Smuzhiyun 	*reserved_maps = new_num;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	return 0;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
add_map_mux(struct pinctrl_map ** map,unsigned * reserved_maps,unsigned * num_maps,const char * group,const char * function)101*4882a593Smuzhiyun static int add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps,
102*4882a593Smuzhiyun 		       unsigned *num_maps, const char *group,
103*4882a593Smuzhiyun 		       const char *function)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	if (WARN_ON(*num_maps == *reserved_maps))
106*4882a593Smuzhiyun 		return -ENOSPC;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	(*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
109*4882a593Smuzhiyun 	(*map)[*num_maps].data.mux.group = group;
110*4882a593Smuzhiyun 	(*map)[*num_maps].data.mux.function = function;
111*4882a593Smuzhiyun 	(*num_maps)++;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	return 0;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun 
add_map_configs(struct device * dev,struct pinctrl_map ** map,unsigned * reserved_maps,unsigned * num_maps,const char * group,unsigned long * configs,unsigned num_configs)116*4882a593Smuzhiyun static int add_map_configs(struct device *dev, struct pinctrl_map **map,
117*4882a593Smuzhiyun 			   unsigned *reserved_maps, unsigned *num_maps,
118*4882a593Smuzhiyun 			   const char *group, unsigned long *configs,
119*4882a593Smuzhiyun 			   unsigned num_configs)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	unsigned long *dup_configs;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	if (WARN_ON(*num_maps == *reserved_maps))
124*4882a593Smuzhiyun 		return -ENOSPC;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
127*4882a593Smuzhiyun 			      GFP_KERNEL);
128*4882a593Smuzhiyun 	if (!dup_configs)
129*4882a593Smuzhiyun 		return -ENOMEM;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	(*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
132*4882a593Smuzhiyun 	(*map)[*num_maps].data.configs.group_or_pin = group;
133*4882a593Smuzhiyun 	(*map)[*num_maps].data.configs.configs = dup_configs;
134*4882a593Smuzhiyun 	(*map)[*num_maps].data.configs.num_configs = num_configs;
135*4882a593Smuzhiyun 	(*num_maps)++;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	return 0;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun 
add_config(struct device * dev,unsigned long ** configs,unsigned * num_configs,unsigned long config)140*4882a593Smuzhiyun static int add_config(struct device *dev, unsigned long **configs,
141*4882a593Smuzhiyun 		      unsigned *num_configs, unsigned long config)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	unsigned old_num = *num_configs;
144*4882a593Smuzhiyun 	unsigned new_num = old_num + 1;
145*4882a593Smuzhiyun 	unsigned long *new_configs;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
148*4882a593Smuzhiyun 			       GFP_KERNEL);
149*4882a593Smuzhiyun 	if (!new_configs)
150*4882a593Smuzhiyun 		return -ENOMEM;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	new_configs[old_num] = config;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	*configs = new_configs;
155*4882a593Smuzhiyun 	*num_configs = new_num;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	return 0;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
samsung_dt_free_map(struct pinctrl_dev * pctldev,struct pinctrl_map * map,unsigned num_maps)160*4882a593Smuzhiyun static void samsung_dt_free_map(struct pinctrl_dev *pctldev,
161*4882a593Smuzhiyun 				      struct pinctrl_map *map,
162*4882a593Smuzhiyun 				      unsigned num_maps)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun 	int i;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	for (i = 0; i < num_maps; i++)
167*4882a593Smuzhiyun 		if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
168*4882a593Smuzhiyun 			kfree(map[i].data.configs.configs);
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	kfree(map);
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun 
samsung_dt_subnode_to_map(struct samsung_pinctrl_drv_data * drvdata,struct device * dev,struct device_node * np,struct pinctrl_map ** map,unsigned * reserved_maps,unsigned * num_maps)173*4882a593Smuzhiyun static int samsung_dt_subnode_to_map(struct samsung_pinctrl_drv_data *drvdata,
174*4882a593Smuzhiyun 				     struct device *dev,
175*4882a593Smuzhiyun 				     struct device_node *np,
176*4882a593Smuzhiyun 				     struct pinctrl_map **map,
177*4882a593Smuzhiyun 				     unsigned *reserved_maps,
178*4882a593Smuzhiyun 				     unsigned *num_maps)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun 	int ret, i;
181*4882a593Smuzhiyun 	u32 val;
182*4882a593Smuzhiyun 	unsigned long config;
183*4882a593Smuzhiyun 	unsigned long *configs = NULL;
184*4882a593Smuzhiyun 	unsigned num_configs = 0;
185*4882a593Smuzhiyun 	unsigned reserve;
186*4882a593Smuzhiyun 	struct property *prop;
187*4882a593Smuzhiyun 	const char *group;
188*4882a593Smuzhiyun 	bool has_func = false;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "samsung,pin-function", &val);
191*4882a593Smuzhiyun 	if (!ret)
192*4882a593Smuzhiyun 		has_func = true;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(cfg_params); i++) {
195*4882a593Smuzhiyun 		ret = of_property_read_u32(np, cfg_params[i].property, &val);
196*4882a593Smuzhiyun 		if (!ret) {
197*4882a593Smuzhiyun 			config = PINCFG_PACK(cfg_params[i].param, val);
198*4882a593Smuzhiyun 			ret = add_config(dev, &configs, &num_configs, config);
199*4882a593Smuzhiyun 			if (ret < 0)
200*4882a593Smuzhiyun 				goto exit;
201*4882a593Smuzhiyun 		/* EINVAL=missing, which is fine since it's optional */
202*4882a593Smuzhiyun 		} else if (ret != -EINVAL) {
203*4882a593Smuzhiyun 			dev_err(dev, "could not parse property %s\n",
204*4882a593Smuzhiyun 				cfg_params[i].property);
205*4882a593Smuzhiyun 		}
206*4882a593Smuzhiyun 	}
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	reserve = 0;
209*4882a593Smuzhiyun 	if (has_func)
210*4882a593Smuzhiyun 		reserve++;
211*4882a593Smuzhiyun 	if (num_configs)
212*4882a593Smuzhiyun 		reserve++;
213*4882a593Smuzhiyun 	ret = of_property_count_strings(np, "samsung,pins");
214*4882a593Smuzhiyun 	if (ret < 0) {
215*4882a593Smuzhiyun 		dev_err(dev, "could not parse property samsung,pins\n");
216*4882a593Smuzhiyun 		goto exit;
217*4882a593Smuzhiyun 	}
218*4882a593Smuzhiyun 	reserve *= ret;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	ret = reserve_map(dev, map, reserved_maps, num_maps, reserve);
221*4882a593Smuzhiyun 	if (ret < 0)
222*4882a593Smuzhiyun 		goto exit;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	of_property_for_each_string(np, "samsung,pins", prop, group) {
225*4882a593Smuzhiyun 		if (has_func) {
226*4882a593Smuzhiyun 			ret = add_map_mux(map, reserved_maps,
227*4882a593Smuzhiyun 						num_maps, group, np->full_name);
228*4882a593Smuzhiyun 			if (ret < 0)
229*4882a593Smuzhiyun 				goto exit;
230*4882a593Smuzhiyun 		}
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 		if (num_configs) {
233*4882a593Smuzhiyun 			ret = add_map_configs(dev, map, reserved_maps,
234*4882a593Smuzhiyun 					      num_maps, group, configs,
235*4882a593Smuzhiyun 					      num_configs);
236*4882a593Smuzhiyun 			if (ret < 0)
237*4882a593Smuzhiyun 				goto exit;
238*4882a593Smuzhiyun 		}
239*4882a593Smuzhiyun 	}
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	ret = 0;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun exit:
244*4882a593Smuzhiyun 	kfree(configs);
245*4882a593Smuzhiyun 	return ret;
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun 
samsung_dt_node_to_map(struct pinctrl_dev * pctldev,struct device_node * np_config,struct pinctrl_map ** map,unsigned * num_maps)248*4882a593Smuzhiyun static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev,
249*4882a593Smuzhiyun 					struct device_node *np_config,
250*4882a593Smuzhiyun 					struct pinctrl_map **map,
251*4882a593Smuzhiyun 					unsigned *num_maps)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun 	struct samsung_pinctrl_drv_data *drvdata;
254*4882a593Smuzhiyun 	unsigned reserved_maps;
255*4882a593Smuzhiyun 	struct device_node *np;
256*4882a593Smuzhiyun 	int ret;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	drvdata = pinctrl_dev_get_drvdata(pctldev);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	reserved_maps = 0;
261*4882a593Smuzhiyun 	*map = NULL;
262*4882a593Smuzhiyun 	*num_maps = 0;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	if (!of_get_child_count(np_config))
265*4882a593Smuzhiyun 		return samsung_dt_subnode_to_map(drvdata, pctldev->dev,
266*4882a593Smuzhiyun 							np_config, map,
267*4882a593Smuzhiyun 							&reserved_maps,
268*4882a593Smuzhiyun 							num_maps);
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	for_each_child_of_node(np_config, np) {
271*4882a593Smuzhiyun 		ret = samsung_dt_subnode_to_map(drvdata, pctldev->dev, np, map,
272*4882a593Smuzhiyun 						&reserved_maps, num_maps);
273*4882a593Smuzhiyun 		if (ret < 0) {
274*4882a593Smuzhiyun 			samsung_dt_free_map(pctldev, *map, *num_maps);
275*4882a593Smuzhiyun 			of_node_put(np);
276*4882a593Smuzhiyun 			return ret;
277*4882a593Smuzhiyun 		}
278*4882a593Smuzhiyun 	}
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	return 0;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun #ifdef CONFIG_DEBUG_FS
284*4882a593Smuzhiyun /* Forward declaration which can be used by samsung_pin_dbg_show */
285*4882a593Smuzhiyun static int samsung_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
286*4882a593Smuzhiyun 					unsigned long *config);
287*4882a593Smuzhiyun static const char * const reg_names[] = {"CON", "DAT", "PUD", "DRV", "CON_PDN",
288*4882a593Smuzhiyun 					 "PUD_PDN"};
289*4882a593Smuzhiyun 
samsung_pin_dbg_show(struct pinctrl_dev * pctldev,struct seq_file * s,unsigned int pin)290*4882a593Smuzhiyun static void samsung_pin_dbg_show(struct pinctrl_dev *pctldev,
291*4882a593Smuzhiyun 				struct seq_file *s, unsigned int pin)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun 	enum pincfg_type cfg_type;
294*4882a593Smuzhiyun 	unsigned long config;
295*4882a593Smuzhiyun 	int ret;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	for (cfg_type = 0; cfg_type < PINCFG_TYPE_NUM; cfg_type++) {
298*4882a593Smuzhiyun 		config = PINCFG_PACK(cfg_type, 0);
299*4882a593Smuzhiyun 		ret = samsung_pinconf_get(pctldev, pin, &config);
300*4882a593Smuzhiyun 		if (ret < 0)
301*4882a593Smuzhiyun 			continue;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 		seq_printf(s, " %s(0x%lx)", reg_names[cfg_type],
304*4882a593Smuzhiyun 			   PINCFG_UNPACK_VALUE(config));
305*4882a593Smuzhiyun 	}
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun #endif
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun /* list of pinctrl callbacks for the pinctrl core */
310*4882a593Smuzhiyun static const struct pinctrl_ops samsung_pctrl_ops = {
311*4882a593Smuzhiyun 	.get_groups_count	= samsung_get_group_count,
312*4882a593Smuzhiyun 	.get_group_name		= samsung_get_group_name,
313*4882a593Smuzhiyun 	.get_group_pins		= samsung_get_group_pins,
314*4882a593Smuzhiyun 	.dt_node_to_map		= samsung_dt_node_to_map,
315*4882a593Smuzhiyun 	.dt_free_map		= samsung_dt_free_map,
316*4882a593Smuzhiyun #ifdef CONFIG_DEBUG_FS
317*4882a593Smuzhiyun 	.pin_dbg_show		= samsung_pin_dbg_show,
318*4882a593Smuzhiyun #endif
319*4882a593Smuzhiyun };
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun /* check if the selector is a valid pin function selector */
samsung_get_functions_count(struct pinctrl_dev * pctldev)322*4882a593Smuzhiyun static int samsung_get_functions_count(struct pinctrl_dev *pctldev)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun 	struct samsung_pinctrl_drv_data *drvdata;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	drvdata = pinctrl_dev_get_drvdata(pctldev);
327*4882a593Smuzhiyun 	return drvdata->nr_functions;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun /* return the name of the pin function specified */
samsung_pinmux_get_fname(struct pinctrl_dev * pctldev,unsigned selector)331*4882a593Smuzhiyun static const char *samsung_pinmux_get_fname(struct pinctrl_dev *pctldev,
332*4882a593Smuzhiyun 						unsigned selector)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun 	struct samsung_pinctrl_drv_data *drvdata;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	drvdata = pinctrl_dev_get_drvdata(pctldev);
337*4882a593Smuzhiyun 	return drvdata->pmx_functions[selector].name;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun /* return the groups associated for the specified function selector */
samsung_pinmux_get_groups(struct pinctrl_dev * pctldev,unsigned selector,const char * const ** groups,unsigned * const num_groups)341*4882a593Smuzhiyun static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev,
342*4882a593Smuzhiyun 		unsigned selector, const char * const **groups,
343*4882a593Smuzhiyun 		unsigned * const num_groups)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun 	struct samsung_pinctrl_drv_data *drvdata;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	drvdata = pinctrl_dev_get_drvdata(pctldev);
348*4882a593Smuzhiyun 	*groups = drvdata->pmx_functions[selector].groups;
349*4882a593Smuzhiyun 	*num_groups = drvdata->pmx_functions[selector].num_groups;
350*4882a593Smuzhiyun 	return 0;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun /*
354*4882a593Smuzhiyun  * given a pin number that is local to a pin controller, find out the pin bank
355*4882a593Smuzhiyun  * and the register base of the pin bank.
356*4882a593Smuzhiyun  */
pin_to_reg_bank(struct samsung_pinctrl_drv_data * drvdata,unsigned pin,void __iomem ** reg,u32 * offset,struct samsung_pin_bank ** bank)357*4882a593Smuzhiyun static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata,
358*4882a593Smuzhiyun 			unsigned pin, void __iomem **reg, u32 *offset,
359*4882a593Smuzhiyun 			struct samsung_pin_bank **bank)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun 	struct samsung_pin_bank *b;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	b = drvdata->pin_banks;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	while ((pin >= b->pin_base) &&
366*4882a593Smuzhiyun 			((b->pin_base + b->nr_pins - 1) < pin))
367*4882a593Smuzhiyun 		b++;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	*reg = b->pctl_base + b->pctl_offset;
370*4882a593Smuzhiyun 	*offset = pin - b->pin_base;
371*4882a593Smuzhiyun 	if (bank)
372*4882a593Smuzhiyun 		*bank = b;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun /* enable or disable a pinmux function */
samsung_pinmux_setup(struct pinctrl_dev * pctldev,unsigned selector,unsigned group)376*4882a593Smuzhiyun static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
377*4882a593Smuzhiyun 					unsigned group)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun 	struct samsung_pinctrl_drv_data *drvdata;
380*4882a593Smuzhiyun 	const struct samsung_pin_bank_type *type;
381*4882a593Smuzhiyun 	struct samsung_pin_bank *bank;
382*4882a593Smuzhiyun 	void __iomem *reg;
383*4882a593Smuzhiyun 	u32 mask, shift, data, pin_offset;
384*4882a593Smuzhiyun 	unsigned long flags;
385*4882a593Smuzhiyun 	const struct samsung_pmx_func *func;
386*4882a593Smuzhiyun 	const struct samsung_pin_group *grp;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	drvdata = pinctrl_dev_get_drvdata(pctldev);
389*4882a593Smuzhiyun 	func = &drvdata->pmx_functions[selector];
390*4882a593Smuzhiyun 	grp = &drvdata->pin_groups[group];
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	pin_to_reg_bank(drvdata, grp->pins[0] - drvdata->pin_base,
393*4882a593Smuzhiyun 			&reg, &pin_offset, &bank);
394*4882a593Smuzhiyun 	type = bank->type;
395*4882a593Smuzhiyun 	mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1;
396*4882a593Smuzhiyun 	shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC];
397*4882a593Smuzhiyun 	if (shift >= 32) {
398*4882a593Smuzhiyun 		/* Some banks have two config registers */
399*4882a593Smuzhiyun 		shift -= 32;
400*4882a593Smuzhiyun 		reg += 4;
401*4882a593Smuzhiyun 	}
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	spin_lock_irqsave(&bank->slock, flags);
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	data = readl(reg + type->reg_offset[PINCFG_TYPE_FUNC]);
406*4882a593Smuzhiyun 	data &= ~(mask << shift);
407*4882a593Smuzhiyun 	data |= func->val << shift;
408*4882a593Smuzhiyun 	writel(data, reg + type->reg_offset[PINCFG_TYPE_FUNC]);
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	spin_unlock_irqrestore(&bank->slock, flags);
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun /* enable a specified pinmux by writing to registers */
samsung_pinmux_set_mux(struct pinctrl_dev * pctldev,unsigned selector,unsigned group)414*4882a593Smuzhiyun static int samsung_pinmux_set_mux(struct pinctrl_dev *pctldev,
415*4882a593Smuzhiyun 				  unsigned selector,
416*4882a593Smuzhiyun 				  unsigned group)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun 	samsung_pinmux_setup(pctldev, selector, group);
419*4882a593Smuzhiyun 	return 0;
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun /* list of pinmux callbacks for the pinmux vertical in pinctrl core */
423*4882a593Smuzhiyun static const struct pinmux_ops samsung_pinmux_ops = {
424*4882a593Smuzhiyun 	.get_functions_count	= samsung_get_functions_count,
425*4882a593Smuzhiyun 	.get_function_name	= samsung_pinmux_get_fname,
426*4882a593Smuzhiyun 	.get_function_groups	= samsung_pinmux_get_groups,
427*4882a593Smuzhiyun 	.set_mux		= samsung_pinmux_set_mux,
428*4882a593Smuzhiyun };
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun /* set or get the pin config settings for a specified pin */
samsung_pinconf_rw(struct pinctrl_dev * pctldev,unsigned int pin,unsigned long * config,bool set)431*4882a593Smuzhiyun static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
432*4882a593Smuzhiyun 				unsigned long *config, bool set)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun 	struct samsung_pinctrl_drv_data *drvdata;
435*4882a593Smuzhiyun 	const struct samsung_pin_bank_type *type;
436*4882a593Smuzhiyun 	struct samsung_pin_bank *bank;
437*4882a593Smuzhiyun 	void __iomem *reg_base;
438*4882a593Smuzhiyun 	enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config);
439*4882a593Smuzhiyun 	u32 data, width, pin_offset, mask, shift;
440*4882a593Smuzhiyun 	u32 cfg_value, cfg_reg;
441*4882a593Smuzhiyun 	unsigned long flags;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	drvdata = pinctrl_dev_get_drvdata(pctldev);
444*4882a593Smuzhiyun 	pin_to_reg_bank(drvdata, pin - drvdata->pin_base, &reg_base,
445*4882a593Smuzhiyun 					&pin_offset, &bank);
446*4882a593Smuzhiyun 	type = bank->type;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	if (cfg_type >= PINCFG_TYPE_NUM || !type->fld_width[cfg_type])
449*4882a593Smuzhiyun 		return -EINVAL;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	width = type->fld_width[cfg_type];
452*4882a593Smuzhiyun 	cfg_reg = type->reg_offset[cfg_type];
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	spin_lock_irqsave(&bank->slock, flags);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	mask = (1 << width) - 1;
457*4882a593Smuzhiyun 	shift = pin_offset * width;
458*4882a593Smuzhiyun 	data = readl(reg_base + cfg_reg);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	if (set) {
461*4882a593Smuzhiyun 		cfg_value = PINCFG_UNPACK_VALUE(*config);
462*4882a593Smuzhiyun 		data &= ~(mask << shift);
463*4882a593Smuzhiyun 		data |= (cfg_value << shift);
464*4882a593Smuzhiyun 		writel(data, reg_base + cfg_reg);
465*4882a593Smuzhiyun 	} else {
466*4882a593Smuzhiyun 		data >>= shift;
467*4882a593Smuzhiyun 		data &= mask;
468*4882a593Smuzhiyun 		*config = PINCFG_PACK(cfg_type, data);
469*4882a593Smuzhiyun 	}
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	spin_unlock_irqrestore(&bank->slock, flags);
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	return 0;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun /* set the pin config settings for a specified pin */
samsung_pinconf_set(struct pinctrl_dev * pctldev,unsigned int pin,unsigned long * configs,unsigned num_configs)477*4882a593Smuzhiyun static int samsung_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
478*4882a593Smuzhiyun 				unsigned long *configs, unsigned num_configs)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun 	int i, ret;
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	for (i = 0; i < num_configs; i++) {
483*4882a593Smuzhiyun 		ret = samsung_pinconf_rw(pctldev, pin, &configs[i], true);
484*4882a593Smuzhiyun 		if (ret < 0)
485*4882a593Smuzhiyun 			return ret;
486*4882a593Smuzhiyun 	} /* for each config */
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	return 0;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun /* get the pin config settings for a specified pin */
samsung_pinconf_get(struct pinctrl_dev * pctldev,unsigned int pin,unsigned long * config)492*4882a593Smuzhiyun static int samsung_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
493*4882a593Smuzhiyun 					unsigned long *config)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun 	return samsung_pinconf_rw(pctldev, pin, config, false);
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun /* set the pin config settings for a specified pin group */
samsung_pinconf_group_set(struct pinctrl_dev * pctldev,unsigned group,unsigned long * configs,unsigned num_configs)499*4882a593Smuzhiyun static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev,
500*4882a593Smuzhiyun 			unsigned group, unsigned long *configs,
501*4882a593Smuzhiyun 			unsigned num_configs)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun 	struct samsung_pinctrl_drv_data *drvdata;
504*4882a593Smuzhiyun 	const unsigned int *pins;
505*4882a593Smuzhiyun 	unsigned int cnt;
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	drvdata = pinctrl_dev_get_drvdata(pctldev);
508*4882a593Smuzhiyun 	pins = drvdata->pin_groups[group].pins;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++)
511*4882a593Smuzhiyun 		samsung_pinconf_set(pctldev, pins[cnt], configs, num_configs);
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	return 0;
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun /* get the pin config settings for a specified pin group */
samsung_pinconf_group_get(struct pinctrl_dev * pctldev,unsigned int group,unsigned long * config)517*4882a593Smuzhiyun static int samsung_pinconf_group_get(struct pinctrl_dev *pctldev,
518*4882a593Smuzhiyun 				unsigned int group, unsigned long *config)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun 	struct samsung_pinctrl_drv_data *drvdata;
521*4882a593Smuzhiyun 	const unsigned int *pins;
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	drvdata = pinctrl_dev_get_drvdata(pctldev);
524*4882a593Smuzhiyun 	pins = drvdata->pin_groups[group].pins;
525*4882a593Smuzhiyun 	samsung_pinconf_get(pctldev, pins[0], config);
526*4882a593Smuzhiyun 	return 0;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun /* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */
530*4882a593Smuzhiyun static const struct pinconf_ops samsung_pinconf_ops = {
531*4882a593Smuzhiyun 	.pin_config_get		= samsung_pinconf_get,
532*4882a593Smuzhiyun 	.pin_config_set		= samsung_pinconf_set,
533*4882a593Smuzhiyun 	.pin_config_group_get	= samsung_pinconf_group_get,
534*4882a593Smuzhiyun 	.pin_config_group_set	= samsung_pinconf_group_set,
535*4882a593Smuzhiyun };
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun /*
538*4882a593Smuzhiyun  * The samsung_gpio_set_vlaue() should be called with "bank->slock" held
539*4882a593Smuzhiyun  * to avoid race condition.
540*4882a593Smuzhiyun  */
samsung_gpio_set_value(struct gpio_chip * gc,unsigned offset,int value)541*4882a593Smuzhiyun static void samsung_gpio_set_value(struct gpio_chip *gc,
542*4882a593Smuzhiyun 					  unsigned offset, int value)
543*4882a593Smuzhiyun {
544*4882a593Smuzhiyun 	struct samsung_pin_bank *bank = gpiochip_get_data(gc);
545*4882a593Smuzhiyun 	const struct samsung_pin_bank_type *type = bank->type;
546*4882a593Smuzhiyun 	void __iomem *reg;
547*4882a593Smuzhiyun 	u32 data;
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	reg = bank->pctl_base + bank->pctl_offset;
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]);
552*4882a593Smuzhiyun 	data &= ~(1 << offset);
553*4882a593Smuzhiyun 	if (value)
554*4882a593Smuzhiyun 		data |= 1 << offset;
555*4882a593Smuzhiyun 	writel(data, reg + type->reg_offset[PINCFG_TYPE_DAT]);
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun /* gpiolib gpio_set callback function */
samsung_gpio_set(struct gpio_chip * gc,unsigned offset,int value)559*4882a593Smuzhiyun static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun 	struct samsung_pin_bank *bank = gpiochip_get_data(gc);
562*4882a593Smuzhiyun 	unsigned long flags;
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	spin_lock_irqsave(&bank->slock, flags);
565*4882a593Smuzhiyun 	samsung_gpio_set_value(gc, offset, value);
566*4882a593Smuzhiyun 	spin_unlock_irqrestore(&bank->slock, flags);
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun /* gpiolib gpio_get callback function */
samsung_gpio_get(struct gpio_chip * gc,unsigned offset)570*4882a593Smuzhiyun static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun 	void __iomem *reg;
573*4882a593Smuzhiyun 	u32 data;
574*4882a593Smuzhiyun 	struct samsung_pin_bank *bank = gpiochip_get_data(gc);
575*4882a593Smuzhiyun 	const struct samsung_pin_bank_type *type = bank->type;
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	reg = bank->pctl_base + bank->pctl_offset;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]);
580*4882a593Smuzhiyun 	data >>= offset;
581*4882a593Smuzhiyun 	data &= 1;
582*4882a593Smuzhiyun 	return data;
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun /*
586*4882a593Smuzhiyun  * The samsung_gpio_set_direction() should be called with "bank->slock" held
587*4882a593Smuzhiyun  * to avoid race condition.
588*4882a593Smuzhiyun  * The calls to gpio_direction_output() and gpio_direction_input()
589*4882a593Smuzhiyun  * leads to this function call.
590*4882a593Smuzhiyun  */
samsung_gpio_set_direction(struct gpio_chip * gc,unsigned offset,bool input)591*4882a593Smuzhiyun static int samsung_gpio_set_direction(struct gpio_chip *gc,
592*4882a593Smuzhiyun 					     unsigned offset, bool input)
593*4882a593Smuzhiyun {
594*4882a593Smuzhiyun 	const struct samsung_pin_bank_type *type;
595*4882a593Smuzhiyun 	struct samsung_pin_bank *bank;
596*4882a593Smuzhiyun 	void __iomem *reg;
597*4882a593Smuzhiyun 	u32 data, mask, shift;
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	bank = gpiochip_get_data(gc);
600*4882a593Smuzhiyun 	type = bank->type;
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	reg = bank->pctl_base + bank->pctl_offset
603*4882a593Smuzhiyun 			+ type->reg_offset[PINCFG_TYPE_FUNC];
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1;
606*4882a593Smuzhiyun 	shift = offset * type->fld_width[PINCFG_TYPE_FUNC];
607*4882a593Smuzhiyun 	if (shift >= 32) {
608*4882a593Smuzhiyun 		/* Some banks have two config registers */
609*4882a593Smuzhiyun 		shift -= 32;
610*4882a593Smuzhiyun 		reg += 4;
611*4882a593Smuzhiyun 	}
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	data = readl(reg);
614*4882a593Smuzhiyun 	data &= ~(mask << shift);
615*4882a593Smuzhiyun 	if (!input)
616*4882a593Smuzhiyun 		data |= EXYNOS_PIN_FUNC_OUTPUT << shift;
617*4882a593Smuzhiyun 	writel(data, reg);
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	return 0;
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun /* gpiolib gpio_direction_input callback function. */
samsung_gpio_direction_input(struct gpio_chip * gc,unsigned offset)623*4882a593Smuzhiyun static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
624*4882a593Smuzhiyun {
625*4882a593Smuzhiyun 	struct samsung_pin_bank *bank = gpiochip_get_data(gc);
626*4882a593Smuzhiyun 	unsigned long flags;
627*4882a593Smuzhiyun 	int ret;
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	spin_lock_irqsave(&bank->slock, flags);
630*4882a593Smuzhiyun 	ret = samsung_gpio_set_direction(gc, offset, true);
631*4882a593Smuzhiyun 	spin_unlock_irqrestore(&bank->slock, flags);
632*4882a593Smuzhiyun 	return ret;
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun /* gpiolib gpio_direction_output callback function. */
samsung_gpio_direction_output(struct gpio_chip * gc,unsigned offset,int value)636*4882a593Smuzhiyun static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
637*4882a593Smuzhiyun 							int value)
638*4882a593Smuzhiyun {
639*4882a593Smuzhiyun 	struct samsung_pin_bank *bank = gpiochip_get_data(gc);
640*4882a593Smuzhiyun 	unsigned long flags;
641*4882a593Smuzhiyun 	int ret;
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	spin_lock_irqsave(&bank->slock, flags);
644*4882a593Smuzhiyun 	samsung_gpio_set_value(gc, offset, value);
645*4882a593Smuzhiyun 	ret = samsung_gpio_set_direction(gc, offset, false);
646*4882a593Smuzhiyun 	spin_unlock_irqrestore(&bank->slock, flags);
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	return ret;
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun /*
652*4882a593Smuzhiyun  * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin
653*4882a593Smuzhiyun  * and a virtual IRQ, if not already present.
654*4882a593Smuzhiyun  */
samsung_gpio_to_irq(struct gpio_chip * gc,unsigned offset)655*4882a593Smuzhiyun static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
656*4882a593Smuzhiyun {
657*4882a593Smuzhiyun 	struct samsung_pin_bank *bank = gpiochip_get_data(gc);
658*4882a593Smuzhiyun 	unsigned int virq;
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	if (!bank->irq_domain)
661*4882a593Smuzhiyun 		return -ENXIO;
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun 	virq = irq_create_mapping(bank->irq_domain, offset);
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 	return (virq) ? : -ENXIO;
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun 
samsung_pinctrl_create_groups(struct device * dev,struct samsung_pinctrl_drv_data * drvdata,unsigned int * cnt)668*4882a593Smuzhiyun static struct samsung_pin_group *samsung_pinctrl_create_groups(
669*4882a593Smuzhiyun 				struct device *dev,
670*4882a593Smuzhiyun 				struct samsung_pinctrl_drv_data *drvdata,
671*4882a593Smuzhiyun 				unsigned int *cnt)
672*4882a593Smuzhiyun {
673*4882a593Smuzhiyun 	struct pinctrl_desc *ctrldesc = &drvdata->pctl;
674*4882a593Smuzhiyun 	struct samsung_pin_group *groups, *grp;
675*4882a593Smuzhiyun 	const struct pinctrl_pin_desc *pdesc;
676*4882a593Smuzhiyun 	int i;
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	groups = devm_kcalloc(dev, ctrldesc->npins, sizeof(*groups),
679*4882a593Smuzhiyun 				GFP_KERNEL);
680*4882a593Smuzhiyun 	if (!groups)
681*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
682*4882a593Smuzhiyun 	grp = groups;
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	pdesc = ctrldesc->pins;
685*4882a593Smuzhiyun 	for (i = 0; i < ctrldesc->npins; ++i, ++pdesc, ++grp) {
686*4882a593Smuzhiyun 		grp->name = pdesc->name;
687*4882a593Smuzhiyun 		grp->pins = &pdesc->number;
688*4882a593Smuzhiyun 		grp->num_pins = 1;
689*4882a593Smuzhiyun 	}
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	*cnt = ctrldesc->npins;
692*4882a593Smuzhiyun 	return groups;
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun 
samsung_pinctrl_create_function(struct device * dev,struct samsung_pinctrl_drv_data * drvdata,struct device_node * func_np,struct samsung_pmx_func * func)695*4882a593Smuzhiyun static int samsung_pinctrl_create_function(struct device *dev,
696*4882a593Smuzhiyun 				struct samsung_pinctrl_drv_data *drvdata,
697*4882a593Smuzhiyun 				struct device_node *func_np,
698*4882a593Smuzhiyun 				struct samsung_pmx_func *func)
699*4882a593Smuzhiyun {
700*4882a593Smuzhiyun 	int npins;
701*4882a593Smuzhiyun 	int ret;
702*4882a593Smuzhiyun 	int i;
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun 	if (of_property_read_u32(func_np, "samsung,pin-function", &func->val))
705*4882a593Smuzhiyun 		return 0;
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	npins = of_property_count_strings(func_np, "samsung,pins");
708*4882a593Smuzhiyun 	if (npins < 1) {
709*4882a593Smuzhiyun 		dev_err(dev, "invalid pin list in %pOFn node", func_np);
710*4882a593Smuzhiyun 		return -EINVAL;
711*4882a593Smuzhiyun 	}
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	func->name = func_np->full_name;
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	func->groups = devm_kcalloc(dev, npins, sizeof(char *), GFP_KERNEL);
716*4882a593Smuzhiyun 	if (!func->groups)
717*4882a593Smuzhiyun 		return -ENOMEM;
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 	for (i = 0; i < npins; ++i) {
720*4882a593Smuzhiyun 		const char *gname;
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun 		ret = of_property_read_string_index(func_np, "samsung,pins",
723*4882a593Smuzhiyun 							i, &gname);
724*4882a593Smuzhiyun 		if (ret) {
725*4882a593Smuzhiyun 			dev_err(dev,
726*4882a593Smuzhiyun 				"failed to read pin name %d from %pOFn node\n",
727*4882a593Smuzhiyun 				i, func_np);
728*4882a593Smuzhiyun 			return ret;
729*4882a593Smuzhiyun 		}
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 		func->groups[i] = gname;
732*4882a593Smuzhiyun 	}
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	func->num_groups = npins;
735*4882a593Smuzhiyun 	return 1;
736*4882a593Smuzhiyun }
737*4882a593Smuzhiyun 
samsung_pinctrl_create_functions(struct device * dev,struct samsung_pinctrl_drv_data * drvdata,unsigned int * cnt)738*4882a593Smuzhiyun static struct samsung_pmx_func *samsung_pinctrl_create_functions(
739*4882a593Smuzhiyun 				struct device *dev,
740*4882a593Smuzhiyun 				struct samsung_pinctrl_drv_data *drvdata,
741*4882a593Smuzhiyun 				unsigned int *cnt)
742*4882a593Smuzhiyun {
743*4882a593Smuzhiyun 	struct samsung_pmx_func *functions, *func;
744*4882a593Smuzhiyun 	struct device_node *dev_np = dev->of_node;
745*4882a593Smuzhiyun 	struct device_node *cfg_np;
746*4882a593Smuzhiyun 	unsigned int func_cnt = 0;
747*4882a593Smuzhiyun 	int ret;
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	/*
750*4882a593Smuzhiyun 	 * Iterate over all the child nodes of the pin controller node
751*4882a593Smuzhiyun 	 * and create pin groups and pin function lists.
752*4882a593Smuzhiyun 	 */
753*4882a593Smuzhiyun 	for_each_child_of_node(dev_np, cfg_np) {
754*4882a593Smuzhiyun 		struct device_node *func_np;
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 		if (!of_get_child_count(cfg_np)) {
757*4882a593Smuzhiyun 			if (!of_find_property(cfg_np,
758*4882a593Smuzhiyun 			    "samsung,pin-function", NULL))
759*4882a593Smuzhiyun 				continue;
760*4882a593Smuzhiyun 			++func_cnt;
761*4882a593Smuzhiyun 			continue;
762*4882a593Smuzhiyun 		}
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 		for_each_child_of_node(cfg_np, func_np) {
765*4882a593Smuzhiyun 			if (!of_find_property(func_np,
766*4882a593Smuzhiyun 			    "samsung,pin-function", NULL))
767*4882a593Smuzhiyun 				continue;
768*4882a593Smuzhiyun 			++func_cnt;
769*4882a593Smuzhiyun 		}
770*4882a593Smuzhiyun 	}
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	functions = devm_kcalloc(dev, func_cnt, sizeof(*functions),
773*4882a593Smuzhiyun 					GFP_KERNEL);
774*4882a593Smuzhiyun 	if (!functions)
775*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
776*4882a593Smuzhiyun 	func = functions;
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	/*
779*4882a593Smuzhiyun 	 * Iterate over all the child nodes of the pin controller node
780*4882a593Smuzhiyun 	 * and create pin groups and pin function lists.
781*4882a593Smuzhiyun 	 */
782*4882a593Smuzhiyun 	func_cnt = 0;
783*4882a593Smuzhiyun 	for_each_child_of_node(dev_np, cfg_np) {
784*4882a593Smuzhiyun 		struct device_node *func_np;
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 		if (!of_get_child_count(cfg_np)) {
787*4882a593Smuzhiyun 			ret = samsung_pinctrl_create_function(dev, drvdata,
788*4882a593Smuzhiyun 							cfg_np, func);
789*4882a593Smuzhiyun 			if (ret < 0) {
790*4882a593Smuzhiyun 				of_node_put(cfg_np);
791*4882a593Smuzhiyun 				return ERR_PTR(ret);
792*4882a593Smuzhiyun 			}
793*4882a593Smuzhiyun 			if (ret > 0) {
794*4882a593Smuzhiyun 				++func;
795*4882a593Smuzhiyun 				++func_cnt;
796*4882a593Smuzhiyun 			}
797*4882a593Smuzhiyun 			continue;
798*4882a593Smuzhiyun 		}
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 		for_each_child_of_node(cfg_np, func_np) {
801*4882a593Smuzhiyun 			ret = samsung_pinctrl_create_function(dev, drvdata,
802*4882a593Smuzhiyun 						func_np, func);
803*4882a593Smuzhiyun 			if (ret < 0) {
804*4882a593Smuzhiyun 				of_node_put(func_np);
805*4882a593Smuzhiyun 				of_node_put(cfg_np);
806*4882a593Smuzhiyun 				return ERR_PTR(ret);
807*4882a593Smuzhiyun 			}
808*4882a593Smuzhiyun 			if (ret > 0) {
809*4882a593Smuzhiyun 				++func;
810*4882a593Smuzhiyun 				++func_cnt;
811*4882a593Smuzhiyun 			}
812*4882a593Smuzhiyun 		}
813*4882a593Smuzhiyun 	}
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 	*cnt = func_cnt;
816*4882a593Smuzhiyun 	return functions;
817*4882a593Smuzhiyun }
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun /*
820*4882a593Smuzhiyun  * Parse the information about all the available pin groups and pin functions
821*4882a593Smuzhiyun  * from device node of the pin-controller. A pin group is formed with all
822*4882a593Smuzhiyun  * the pins listed in the "samsung,pins" property.
823*4882a593Smuzhiyun  */
824*4882a593Smuzhiyun 
samsung_pinctrl_parse_dt(struct platform_device * pdev,struct samsung_pinctrl_drv_data * drvdata)825*4882a593Smuzhiyun static int samsung_pinctrl_parse_dt(struct platform_device *pdev,
826*4882a593Smuzhiyun 				    struct samsung_pinctrl_drv_data *drvdata)
827*4882a593Smuzhiyun {
828*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
829*4882a593Smuzhiyun 	struct samsung_pin_group *groups;
830*4882a593Smuzhiyun 	struct samsung_pmx_func *functions;
831*4882a593Smuzhiyun 	unsigned int grp_cnt = 0, func_cnt = 0;
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	groups = samsung_pinctrl_create_groups(dev, drvdata, &grp_cnt);
834*4882a593Smuzhiyun 	if (IS_ERR(groups)) {
835*4882a593Smuzhiyun 		dev_err(dev, "failed to parse pin groups\n");
836*4882a593Smuzhiyun 		return PTR_ERR(groups);
837*4882a593Smuzhiyun 	}
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 	functions = samsung_pinctrl_create_functions(dev, drvdata, &func_cnt);
840*4882a593Smuzhiyun 	if (IS_ERR(functions)) {
841*4882a593Smuzhiyun 		dev_err(dev, "failed to parse pin functions\n");
842*4882a593Smuzhiyun 		return PTR_ERR(functions);
843*4882a593Smuzhiyun 	}
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 	drvdata->pin_groups = groups;
846*4882a593Smuzhiyun 	drvdata->nr_groups = grp_cnt;
847*4882a593Smuzhiyun 	drvdata->pmx_functions = functions;
848*4882a593Smuzhiyun 	drvdata->nr_functions = func_cnt;
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun 	return 0;
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun /* register the pinctrl interface with the pinctrl subsystem */
samsung_pinctrl_register(struct platform_device * pdev,struct samsung_pinctrl_drv_data * drvdata)854*4882a593Smuzhiyun static int samsung_pinctrl_register(struct platform_device *pdev,
855*4882a593Smuzhiyun 				    struct samsung_pinctrl_drv_data *drvdata)
856*4882a593Smuzhiyun {
857*4882a593Smuzhiyun 	struct pinctrl_desc *ctrldesc = &drvdata->pctl;
858*4882a593Smuzhiyun 	struct pinctrl_pin_desc *pindesc, *pdesc;
859*4882a593Smuzhiyun 	struct samsung_pin_bank *pin_bank;
860*4882a593Smuzhiyun 	char *pin_names;
861*4882a593Smuzhiyun 	int pin, bank, ret;
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	ctrldesc->name = "samsung-pinctrl";
864*4882a593Smuzhiyun 	ctrldesc->owner = THIS_MODULE;
865*4882a593Smuzhiyun 	ctrldesc->pctlops = &samsung_pctrl_ops;
866*4882a593Smuzhiyun 	ctrldesc->pmxops = &samsung_pinmux_ops;
867*4882a593Smuzhiyun 	ctrldesc->confops = &samsung_pinconf_ops;
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 	pindesc = devm_kcalloc(&pdev->dev,
870*4882a593Smuzhiyun 			       drvdata->nr_pins, sizeof(*pindesc),
871*4882a593Smuzhiyun 			       GFP_KERNEL);
872*4882a593Smuzhiyun 	if (!pindesc)
873*4882a593Smuzhiyun 		return -ENOMEM;
874*4882a593Smuzhiyun 	ctrldesc->pins = pindesc;
875*4882a593Smuzhiyun 	ctrldesc->npins = drvdata->nr_pins;
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun 	/* dynamically populate the pin number and pin name for pindesc */
878*4882a593Smuzhiyun 	for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++)
879*4882a593Smuzhiyun 		pdesc->number = pin + drvdata->pin_base;
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 	/*
882*4882a593Smuzhiyun 	 * allocate space for storing the dynamically generated names for all
883*4882a593Smuzhiyun 	 * the pins which belong to this pin-controller.
884*4882a593Smuzhiyun 	 */
885*4882a593Smuzhiyun 	pin_names = devm_kzalloc(&pdev->dev,
886*4882a593Smuzhiyun 				 array3_size(sizeof(char), PIN_NAME_LENGTH,
887*4882a593Smuzhiyun 					     drvdata->nr_pins),
888*4882a593Smuzhiyun 				 GFP_KERNEL);
889*4882a593Smuzhiyun 	if (!pin_names)
890*4882a593Smuzhiyun 		return -ENOMEM;
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun 	/* for each pin, the name of the pin is pin-bank name + pin number */
893*4882a593Smuzhiyun 	for (bank = 0; bank < drvdata->nr_banks; bank++) {
894*4882a593Smuzhiyun 		pin_bank = &drvdata->pin_banks[bank];
895*4882a593Smuzhiyun 		for (pin = 0; pin < pin_bank->nr_pins; pin++) {
896*4882a593Smuzhiyun 			sprintf(pin_names, "%s-%d", pin_bank->name, pin);
897*4882a593Smuzhiyun 			pdesc = pindesc + pin_bank->pin_base + pin;
898*4882a593Smuzhiyun 			pdesc->name = pin_names;
899*4882a593Smuzhiyun 			pin_names += PIN_NAME_LENGTH;
900*4882a593Smuzhiyun 		}
901*4882a593Smuzhiyun 	}
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun 	ret = samsung_pinctrl_parse_dt(pdev, drvdata);
904*4882a593Smuzhiyun 	if (ret)
905*4882a593Smuzhiyun 		return ret;
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	drvdata->pctl_dev = devm_pinctrl_register(&pdev->dev, ctrldesc,
908*4882a593Smuzhiyun 						  drvdata);
909*4882a593Smuzhiyun 	if (IS_ERR(drvdata->pctl_dev)) {
910*4882a593Smuzhiyun 		dev_err(&pdev->dev, "could not register pinctrl driver\n");
911*4882a593Smuzhiyun 		return PTR_ERR(drvdata->pctl_dev);
912*4882a593Smuzhiyun 	}
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun 	for (bank = 0; bank < drvdata->nr_banks; ++bank) {
915*4882a593Smuzhiyun 		pin_bank = &drvdata->pin_banks[bank];
916*4882a593Smuzhiyun 		pin_bank->grange.name = pin_bank->name;
917*4882a593Smuzhiyun 		pin_bank->grange.id = bank;
918*4882a593Smuzhiyun 		pin_bank->grange.pin_base = drvdata->pin_base
919*4882a593Smuzhiyun 						+ pin_bank->pin_base;
920*4882a593Smuzhiyun 		pin_bank->grange.base = pin_bank->grange.pin_base;
921*4882a593Smuzhiyun 		pin_bank->grange.npins = pin_bank->nr_pins;
922*4882a593Smuzhiyun 		pin_bank->grange.gc = &pin_bank->gpio_chip;
923*4882a593Smuzhiyun 		pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange);
924*4882a593Smuzhiyun 	}
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	return 0;
927*4882a593Smuzhiyun }
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun /* unregister the pinctrl interface with the pinctrl subsystem */
samsung_pinctrl_unregister(struct platform_device * pdev,struct samsung_pinctrl_drv_data * drvdata)930*4882a593Smuzhiyun static int samsung_pinctrl_unregister(struct platform_device *pdev,
931*4882a593Smuzhiyun 				      struct samsung_pinctrl_drv_data *drvdata)
932*4882a593Smuzhiyun {
933*4882a593Smuzhiyun 	struct samsung_pin_bank *bank = drvdata->pin_banks;
934*4882a593Smuzhiyun 	int i;
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun 	for (i = 0; i < drvdata->nr_banks; ++i, ++bank)
937*4882a593Smuzhiyun 		pinctrl_remove_gpio_range(drvdata->pctl_dev, &bank->grange);
938*4882a593Smuzhiyun 
939*4882a593Smuzhiyun 	return 0;
940*4882a593Smuzhiyun }
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun static const struct gpio_chip samsung_gpiolib_chip = {
943*4882a593Smuzhiyun 	.request = gpiochip_generic_request,
944*4882a593Smuzhiyun 	.free = gpiochip_generic_free,
945*4882a593Smuzhiyun 	.set = samsung_gpio_set,
946*4882a593Smuzhiyun 	.get = samsung_gpio_get,
947*4882a593Smuzhiyun 	.direction_input = samsung_gpio_direction_input,
948*4882a593Smuzhiyun 	.direction_output = samsung_gpio_direction_output,
949*4882a593Smuzhiyun 	.to_irq = samsung_gpio_to_irq,
950*4882a593Smuzhiyun 	.owner = THIS_MODULE,
951*4882a593Smuzhiyun };
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun /* register the gpiolib interface with the gpiolib subsystem */
samsung_gpiolib_register(struct platform_device * pdev,struct samsung_pinctrl_drv_data * drvdata)954*4882a593Smuzhiyun static int samsung_gpiolib_register(struct platform_device *pdev,
955*4882a593Smuzhiyun 				    struct samsung_pinctrl_drv_data *drvdata)
956*4882a593Smuzhiyun {
957*4882a593Smuzhiyun 	struct samsung_pin_bank *bank = drvdata->pin_banks;
958*4882a593Smuzhiyun 	struct gpio_chip *gc;
959*4882a593Smuzhiyun 	int ret;
960*4882a593Smuzhiyun 	int i;
961*4882a593Smuzhiyun 
962*4882a593Smuzhiyun 	for (i = 0; i < drvdata->nr_banks; ++i, ++bank) {
963*4882a593Smuzhiyun 		bank->gpio_chip = samsung_gpiolib_chip;
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 		gc = &bank->gpio_chip;
966*4882a593Smuzhiyun 		gc->base = bank->grange.base;
967*4882a593Smuzhiyun 		gc->ngpio = bank->nr_pins;
968*4882a593Smuzhiyun 		gc->parent = &pdev->dev;
969*4882a593Smuzhiyun 		gc->of_node = bank->of_node;
970*4882a593Smuzhiyun 		gc->label = bank->name;
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 		ret = devm_gpiochip_add_data(&pdev->dev, gc, bank);
973*4882a593Smuzhiyun 		if (ret) {
974*4882a593Smuzhiyun 			dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n",
975*4882a593Smuzhiyun 							gc->label, ret);
976*4882a593Smuzhiyun 			return ret;
977*4882a593Smuzhiyun 		}
978*4882a593Smuzhiyun 	}
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun 	return 0;
981*4882a593Smuzhiyun }
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun static const struct samsung_pin_ctrl *
samsung_pinctrl_get_soc_data_for_of_alias(struct platform_device * pdev)984*4882a593Smuzhiyun samsung_pinctrl_get_soc_data_for_of_alias(struct platform_device *pdev)
985*4882a593Smuzhiyun {
986*4882a593Smuzhiyun 	struct device_node *node = pdev->dev.of_node;
987*4882a593Smuzhiyun 	const struct samsung_pinctrl_of_match_data *of_data;
988*4882a593Smuzhiyun 	int id;
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 	id = of_alias_get_id(node, "pinctrl");
991*4882a593Smuzhiyun 	if (id < 0) {
992*4882a593Smuzhiyun 		dev_err(&pdev->dev, "failed to get alias id\n");
993*4882a593Smuzhiyun 		return NULL;
994*4882a593Smuzhiyun 	}
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun 	of_data = of_device_get_match_data(&pdev->dev);
997*4882a593Smuzhiyun 	if (id >= of_data->num_ctrl) {
998*4882a593Smuzhiyun 		dev_err(&pdev->dev, "invalid alias id %d\n", id);
999*4882a593Smuzhiyun 		return NULL;
1000*4882a593Smuzhiyun 	}
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun 	return &(of_data->ctrl[id]);
1003*4882a593Smuzhiyun }
1004*4882a593Smuzhiyun 
samsung_banks_of_node_put(struct samsung_pinctrl_drv_data * d)1005*4882a593Smuzhiyun static void samsung_banks_of_node_put(struct samsung_pinctrl_drv_data *d)
1006*4882a593Smuzhiyun {
1007*4882a593Smuzhiyun 	struct samsung_pin_bank *bank;
1008*4882a593Smuzhiyun 	unsigned int i;
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun 	bank = d->pin_banks;
1011*4882a593Smuzhiyun 	for (i = 0; i < d->nr_banks; ++i, ++bank)
1012*4882a593Smuzhiyun 		of_node_put(bank->of_node);
1013*4882a593Smuzhiyun }
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun /* retrieve the soc specific data */
1016*4882a593Smuzhiyun static const struct samsung_pin_ctrl *
samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data * d,struct platform_device * pdev)1017*4882a593Smuzhiyun samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d,
1018*4882a593Smuzhiyun 			     struct platform_device *pdev)
1019*4882a593Smuzhiyun {
1020*4882a593Smuzhiyun 	struct device_node *node = pdev->dev.of_node;
1021*4882a593Smuzhiyun 	struct device_node *np;
1022*4882a593Smuzhiyun 	const struct samsung_pin_bank_data *bdata;
1023*4882a593Smuzhiyun 	const struct samsung_pin_ctrl *ctrl;
1024*4882a593Smuzhiyun 	struct samsung_pin_bank *bank;
1025*4882a593Smuzhiyun 	struct resource *res;
1026*4882a593Smuzhiyun 	void __iomem *virt_base[SAMSUNG_PINCTRL_NUM_RESOURCES];
1027*4882a593Smuzhiyun 	unsigned int i;
1028*4882a593Smuzhiyun 
1029*4882a593Smuzhiyun 	ctrl = samsung_pinctrl_get_soc_data_for_of_alias(pdev);
1030*4882a593Smuzhiyun 	if (!ctrl)
1031*4882a593Smuzhiyun 		return ERR_PTR(-ENOENT);
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun 	d->suspend = ctrl->suspend;
1034*4882a593Smuzhiyun 	d->resume = ctrl->resume;
1035*4882a593Smuzhiyun 	d->nr_banks = ctrl->nr_banks;
1036*4882a593Smuzhiyun 	d->pin_banks = devm_kcalloc(&pdev->dev, d->nr_banks,
1037*4882a593Smuzhiyun 					sizeof(*d->pin_banks), GFP_KERNEL);
1038*4882a593Smuzhiyun 	if (!d->pin_banks)
1039*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
1040*4882a593Smuzhiyun 
1041*4882a593Smuzhiyun 	if (ctrl->nr_ext_resources + 1 > SAMSUNG_PINCTRL_NUM_RESOURCES)
1042*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
1043*4882a593Smuzhiyun 
1044*4882a593Smuzhiyun 	for (i = 0; i < ctrl->nr_ext_resources + 1; i++) {
1045*4882a593Smuzhiyun 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
1046*4882a593Smuzhiyun 		if (!res) {
1047*4882a593Smuzhiyun 			dev_err(&pdev->dev, "failed to get mem%d resource\n", i);
1048*4882a593Smuzhiyun 			return ERR_PTR(-EINVAL);
1049*4882a593Smuzhiyun 		}
1050*4882a593Smuzhiyun 		virt_base[i] = devm_ioremap(&pdev->dev, res->start,
1051*4882a593Smuzhiyun 						resource_size(res));
1052*4882a593Smuzhiyun 		if (!virt_base[i]) {
1053*4882a593Smuzhiyun 			dev_err(&pdev->dev, "failed to ioremap %pR\n", res);
1054*4882a593Smuzhiyun 			return ERR_PTR(-EIO);
1055*4882a593Smuzhiyun 		}
1056*4882a593Smuzhiyun 	}
1057*4882a593Smuzhiyun 
1058*4882a593Smuzhiyun 	bank = d->pin_banks;
1059*4882a593Smuzhiyun 	bdata = ctrl->pin_banks;
1060*4882a593Smuzhiyun 	for (i = 0; i < ctrl->nr_banks; ++i, ++bdata, ++bank) {
1061*4882a593Smuzhiyun 		bank->type = bdata->type;
1062*4882a593Smuzhiyun 		bank->pctl_offset = bdata->pctl_offset;
1063*4882a593Smuzhiyun 		bank->nr_pins = bdata->nr_pins;
1064*4882a593Smuzhiyun 		bank->eint_func = bdata->eint_func;
1065*4882a593Smuzhiyun 		bank->eint_type = bdata->eint_type;
1066*4882a593Smuzhiyun 		bank->eint_mask = bdata->eint_mask;
1067*4882a593Smuzhiyun 		bank->eint_offset = bdata->eint_offset;
1068*4882a593Smuzhiyun 		bank->name = bdata->name;
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun 		spin_lock_init(&bank->slock);
1071*4882a593Smuzhiyun 		bank->drvdata = d;
1072*4882a593Smuzhiyun 		bank->pin_base = d->nr_pins;
1073*4882a593Smuzhiyun 		d->nr_pins += bank->nr_pins;
1074*4882a593Smuzhiyun 
1075*4882a593Smuzhiyun 		bank->eint_base = virt_base[0];
1076*4882a593Smuzhiyun 		bank->pctl_base = virt_base[bdata->pctl_res_idx];
1077*4882a593Smuzhiyun 	}
1078*4882a593Smuzhiyun 	/*
1079*4882a593Smuzhiyun 	 * Legacy platforms should provide only one resource with IO memory.
1080*4882a593Smuzhiyun 	 * Store it as virt_base because legacy driver needs to access it
1081*4882a593Smuzhiyun 	 * through samsung_pinctrl_drv_data.
1082*4882a593Smuzhiyun 	 */
1083*4882a593Smuzhiyun 	d->virt_base = virt_base[0];
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun 	for_each_child_of_node(node, np) {
1086*4882a593Smuzhiyun 		if (!of_find_property(np, "gpio-controller", NULL))
1087*4882a593Smuzhiyun 			continue;
1088*4882a593Smuzhiyun 		bank = d->pin_banks;
1089*4882a593Smuzhiyun 		for (i = 0; i < d->nr_banks; ++i, ++bank) {
1090*4882a593Smuzhiyun 			if (of_node_name_eq(np, bank->name)) {
1091*4882a593Smuzhiyun 				bank->of_node = np;
1092*4882a593Smuzhiyun 				break;
1093*4882a593Smuzhiyun 			}
1094*4882a593Smuzhiyun 		}
1095*4882a593Smuzhiyun 	}
1096*4882a593Smuzhiyun 
1097*4882a593Smuzhiyun 	d->pin_base = pin_base;
1098*4882a593Smuzhiyun 	pin_base += d->nr_pins;
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun 	return ctrl;
1101*4882a593Smuzhiyun }
1102*4882a593Smuzhiyun 
samsung_pinctrl_probe(struct platform_device * pdev)1103*4882a593Smuzhiyun static int samsung_pinctrl_probe(struct platform_device *pdev)
1104*4882a593Smuzhiyun {
1105*4882a593Smuzhiyun 	struct samsung_pinctrl_drv_data *drvdata;
1106*4882a593Smuzhiyun 	const struct samsung_pin_ctrl *ctrl;
1107*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
1108*4882a593Smuzhiyun 	struct resource *res;
1109*4882a593Smuzhiyun 	int ret;
1110*4882a593Smuzhiyun 
1111*4882a593Smuzhiyun 	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
1112*4882a593Smuzhiyun 	if (!drvdata)
1113*4882a593Smuzhiyun 		return -ENOMEM;
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun 	ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev);
1116*4882a593Smuzhiyun 	if (IS_ERR(ctrl)) {
1117*4882a593Smuzhiyun 		dev_err(&pdev->dev, "driver data not available\n");
1118*4882a593Smuzhiyun 		return PTR_ERR(ctrl);
1119*4882a593Smuzhiyun 	}
1120*4882a593Smuzhiyun 	drvdata->dev = dev;
1121*4882a593Smuzhiyun 
1122*4882a593Smuzhiyun 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1123*4882a593Smuzhiyun 	if (res)
1124*4882a593Smuzhiyun 		drvdata->irq = res->start;
1125*4882a593Smuzhiyun 
1126*4882a593Smuzhiyun 	if (ctrl->retention_data) {
1127*4882a593Smuzhiyun 		drvdata->retention_ctrl = ctrl->retention_data->init(drvdata,
1128*4882a593Smuzhiyun 							  ctrl->retention_data);
1129*4882a593Smuzhiyun 		if (IS_ERR(drvdata->retention_ctrl)) {
1130*4882a593Smuzhiyun 			ret = PTR_ERR(drvdata->retention_ctrl);
1131*4882a593Smuzhiyun 			goto err_put_banks;
1132*4882a593Smuzhiyun 		}
1133*4882a593Smuzhiyun 	}
1134*4882a593Smuzhiyun 
1135*4882a593Smuzhiyun 	ret = samsung_pinctrl_register(pdev, drvdata);
1136*4882a593Smuzhiyun 	if (ret)
1137*4882a593Smuzhiyun 		goto err_put_banks;
1138*4882a593Smuzhiyun 
1139*4882a593Smuzhiyun 	ret = samsung_gpiolib_register(pdev, drvdata);
1140*4882a593Smuzhiyun 	if (ret)
1141*4882a593Smuzhiyun 		goto err_unregister;
1142*4882a593Smuzhiyun 
1143*4882a593Smuzhiyun 	if (ctrl->eint_gpio_init)
1144*4882a593Smuzhiyun 		ctrl->eint_gpio_init(drvdata);
1145*4882a593Smuzhiyun 	if (ctrl->eint_wkup_init)
1146*4882a593Smuzhiyun 		ctrl->eint_wkup_init(drvdata);
1147*4882a593Smuzhiyun 
1148*4882a593Smuzhiyun 	platform_set_drvdata(pdev, drvdata);
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun 	return 0;
1151*4882a593Smuzhiyun 
1152*4882a593Smuzhiyun err_unregister:
1153*4882a593Smuzhiyun 	samsung_pinctrl_unregister(pdev, drvdata);
1154*4882a593Smuzhiyun err_put_banks:
1155*4882a593Smuzhiyun 	samsung_banks_of_node_put(drvdata);
1156*4882a593Smuzhiyun 	return ret;
1157*4882a593Smuzhiyun }
1158*4882a593Smuzhiyun 
1159*4882a593Smuzhiyun /*
1160*4882a593Smuzhiyun  * samsung_pinctrl_suspend - save pinctrl state for suspend
1161*4882a593Smuzhiyun  *
1162*4882a593Smuzhiyun  * Save data for all banks handled by this device.
1163*4882a593Smuzhiyun  */
samsung_pinctrl_suspend(struct device * dev)1164*4882a593Smuzhiyun static int __maybe_unused samsung_pinctrl_suspend(struct device *dev)
1165*4882a593Smuzhiyun {
1166*4882a593Smuzhiyun 	struct samsung_pinctrl_drv_data *drvdata = dev_get_drvdata(dev);
1167*4882a593Smuzhiyun 	int i;
1168*4882a593Smuzhiyun 
1169*4882a593Smuzhiyun 	for (i = 0; i < drvdata->nr_banks; i++) {
1170*4882a593Smuzhiyun 		struct samsung_pin_bank *bank = &drvdata->pin_banks[i];
1171*4882a593Smuzhiyun 		void __iomem *reg = bank->pctl_base + bank->pctl_offset;
1172*4882a593Smuzhiyun 		const u8 *offs = bank->type->reg_offset;
1173*4882a593Smuzhiyun 		const u8 *widths = bank->type->fld_width;
1174*4882a593Smuzhiyun 		enum pincfg_type type;
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun 		/* Registers without a powerdown config aren't lost */
1177*4882a593Smuzhiyun 		if (!widths[PINCFG_TYPE_CON_PDN])
1178*4882a593Smuzhiyun 			continue;
1179*4882a593Smuzhiyun 
1180*4882a593Smuzhiyun 		for (type = 0; type < PINCFG_TYPE_NUM; type++)
1181*4882a593Smuzhiyun 			if (widths[type])
1182*4882a593Smuzhiyun 				bank->pm_save[type] = readl(reg + offs[type]);
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun 		if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) {
1185*4882a593Smuzhiyun 			/* Some banks have two config registers */
1186*4882a593Smuzhiyun 			bank->pm_save[PINCFG_TYPE_NUM] =
1187*4882a593Smuzhiyun 				readl(reg + offs[PINCFG_TYPE_FUNC] + 4);
1188*4882a593Smuzhiyun 			pr_debug("Save %s @ %p (con %#010x %08x)\n",
1189*4882a593Smuzhiyun 				 bank->name, reg,
1190*4882a593Smuzhiyun 				 bank->pm_save[PINCFG_TYPE_FUNC],
1191*4882a593Smuzhiyun 				 bank->pm_save[PINCFG_TYPE_NUM]);
1192*4882a593Smuzhiyun 		} else {
1193*4882a593Smuzhiyun 			pr_debug("Save %s @ %p (con %#010x)\n", bank->name,
1194*4882a593Smuzhiyun 				 reg, bank->pm_save[PINCFG_TYPE_FUNC]);
1195*4882a593Smuzhiyun 		}
1196*4882a593Smuzhiyun 	}
1197*4882a593Smuzhiyun 
1198*4882a593Smuzhiyun 	if (drvdata->suspend)
1199*4882a593Smuzhiyun 		drvdata->suspend(drvdata);
1200*4882a593Smuzhiyun 	if (drvdata->retention_ctrl && drvdata->retention_ctrl->enable)
1201*4882a593Smuzhiyun 		drvdata->retention_ctrl->enable(drvdata);
1202*4882a593Smuzhiyun 
1203*4882a593Smuzhiyun 	return 0;
1204*4882a593Smuzhiyun }
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun /*
1207*4882a593Smuzhiyun  * samsung_pinctrl_resume - restore pinctrl state from suspend
1208*4882a593Smuzhiyun  *
1209*4882a593Smuzhiyun  * Restore one of the banks that was saved during suspend.
1210*4882a593Smuzhiyun  *
1211*4882a593Smuzhiyun  * We don't bother doing anything complicated to avoid glitching lines since
1212*4882a593Smuzhiyun  * we're called before pad retention is turned off.
1213*4882a593Smuzhiyun  */
samsung_pinctrl_resume(struct device * dev)1214*4882a593Smuzhiyun static int __maybe_unused samsung_pinctrl_resume(struct device *dev)
1215*4882a593Smuzhiyun {
1216*4882a593Smuzhiyun 	struct samsung_pinctrl_drv_data *drvdata = dev_get_drvdata(dev);
1217*4882a593Smuzhiyun 	int i;
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun 	if (drvdata->resume)
1220*4882a593Smuzhiyun 		drvdata->resume(drvdata);
1221*4882a593Smuzhiyun 
1222*4882a593Smuzhiyun 	for (i = 0; i < drvdata->nr_banks; i++) {
1223*4882a593Smuzhiyun 		struct samsung_pin_bank *bank = &drvdata->pin_banks[i];
1224*4882a593Smuzhiyun 		void __iomem *reg = bank->pctl_base + bank->pctl_offset;
1225*4882a593Smuzhiyun 		const u8 *offs = bank->type->reg_offset;
1226*4882a593Smuzhiyun 		const u8 *widths = bank->type->fld_width;
1227*4882a593Smuzhiyun 		enum pincfg_type type;
1228*4882a593Smuzhiyun 
1229*4882a593Smuzhiyun 		/* Registers without a powerdown config aren't lost */
1230*4882a593Smuzhiyun 		if (!widths[PINCFG_TYPE_CON_PDN])
1231*4882a593Smuzhiyun 			continue;
1232*4882a593Smuzhiyun 
1233*4882a593Smuzhiyun 		if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) {
1234*4882a593Smuzhiyun 			/* Some banks have two config registers */
1235*4882a593Smuzhiyun 			pr_debug("%s @ %p (con %#010x %08x => %#010x %08x)\n",
1236*4882a593Smuzhiyun 				 bank->name, reg,
1237*4882a593Smuzhiyun 				 readl(reg + offs[PINCFG_TYPE_FUNC]),
1238*4882a593Smuzhiyun 				 readl(reg + offs[PINCFG_TYPE_FUNC] + 4),
1239*4882a593Smuzhiyun 				 bank->pm_save[PINCFG_TYPE_FUNC],
1240*4882a593Smuzhiyun 				 bank->pm_save[PINCFG_TYPE_NUM]);
1241*4882a593Smuzhiyun 			writel(bank->pm_save[PINCFG_TYPE_NUM],
1242*4882a593Smuzhiyun 			       reg + offs[PINCFG_TYPE_FUNC] + 4);
1243*4882a593Smuzhiyun 		} else {
1244*4882a593Smuzhiyun 			pr_debug("%s @ %p (con %#010x => %#010x)\n", bank->name,
1245*4882a593Smuzhiyun 				 reg, readl(reg + offs[PINCFG_TYPE_FUNC]),
1246*4882a593Smuzhiyun 				 bank->pm_save[PINCFG_TYPE_FUNC]);
1247*4882a593Smuzhiyun 		}
1248*4882a593Smuzhiyun 		for (type = 0; type < PINCFG_TYPE_NUM; type++)
1249*4882a593Smuzhiyun 			if (widths[type])
1250*4882a593Smuzhiyun 				writel(bank->pm_save[type], reg + offs[type]);
1251*4882a593Smuzhiyun 	}
1252*4882a593Smuzhiyun 
1253*4882a593Smuzhiyun 	if (drvdata->retention_ctrl && drvdata->retention_ctrl->disable)
1254*4882a593Smuzhiyun 		drvdata->retention_ctrl->disable(drvdata);
1255*4882a593Smuzhiyun 
1256*4882a593Smuzhiyun 	return 0;
1257*4882a593Smuzhiyun }
1258*4882a593Smuzhiyun 
1259*4882a593Smuzhiyun static const struct of_device_id samsung_pinctrl_dt_match[] = {
1260*4882a593Smuzhiyun #ifdef CONFIG_PINCTRL_EXYNOS_ARM
1261*4882a593Smuzhiyun 	{ .compatible = "samsung,exynos3250-pinctrl",
1262*4882a593Smuzhiyun 		.data = &exynos3250_of_data },
1263*4882a593Smuzhiyun 	{ .compatible = "samsung,exynos4210-pinctrl",
1264*4882a593Smuzhiyun 		.data = &exynos4210_of_data },
1265*4882a593Smuzhiyun 	{ .compatible = "samsung,exynos4x12-pinctrl",
1266*4882a593Smuzhiyun 		.data = &exynos4x12_of_data },
1267*4882a593Smuzhiyun 	{ .compatible = "samsung,exynos5250-pinctrl",
1268*4882a593Smuzhiyun 		.data = &exynos5250_of_data },
1269*4882a593Smuzhiyun 	{ .compatible = "samsung,exynos5260-pinctrl",
1270*4882a593Smuzhiyun 		.data = &exynos5260_of_data },
1271*4882a593Smuzhiyun 	{ .compatible = "samsung,exynos5410-pinctrl",
1272*4882a593Smuzhiyun 		.data = &exynos5410_of_data },
1273*4882a593Smuzhiyun 	{ .compatible = "samsung,exynos5420-pinctrl",
1274*4882a593Smuzhiyun 		.data = &exynos5420_of_data },
1275*4882a593Smuzhiyun 	{ .compatible = "samsung,s5pv210-pinctrl",
1276*4882a593Smuzhiyun 		.data = &s5pv210_of_data },
1277*4882a593Smuzhiyun #endif
1278*4882a593Smuzhiyun #ifdef CONFIG_PINCTRL_EXYNOS_ARM64
1279*4882a593Smuzhiyun 	{ .compatible = "samsung,exynos5433-pinctrl",
1280*4882a593Smuzhiyun 		.data = &exynos5433_of_data },
1281*4882a593Smuzhiyun 	{ .compatible = "samsung,exynos7-pinctrl",
1282*4882a593Smuzhiyun 		.data = &exynos7_of_data },
1283*4882a593Smuzhiyun #endif
1284*4882a593Smuzhiyun #ifdef CONFIG_PINCTRL_S3C64XX
1285*4882a593Smuzhiyun 	{ .compatible = "samsung,s3c64xx-pinctrl",
1286*4882a593Smuzhiyun 		.data = &s3c64xx_of_data },
1287*4882a593Smuzhiyun #endif
1288*4882a593Smuzhiyun #ifdef CONFIG_PINCTRL_S3C24XX
1289*4882a593Smuzhiyun 	{ .compatible = "samsung,s3c2412-pinctrl",
1290*4882a593Smuzhiyun 		.data = &s3c2412_of_data },
1291*4882a593Smuzhiyun 	{ .compatible = "samsung,s3c2416-pinctrl",
1292*4882a593Smuzhiyun 		.data = &s3c2416_of_data },
1293*4882a593Smuzhiyun 	{ .compatible = "samsung,s3c2440-pinctrl",
1294*4882a593Smuzhiyun 		.data = &s3c2440_of_data },
1295*4882a593Smuzhiyun 	{ .compatible = "samsung,s3c2450-pinctrl",
1296*4882a593Smuzhiyun 		.data = &s3c2450_of_data },
1297*4882a593Smuzhiyun #endif
1298*4882a593Smuzhiyun 	{},
1299*4882a593Smuzhiyun };
1300*4882a593Smuzhiyun 
1301*4882a593Smuzhiyun static const struct dev_pm_ops samsung_pinctrl_pm_ops = {
1302*4882a593Smuzhiyun 	SET_LATE_SYSTEM_SLEEP_PM_OPS(samsung_pinctrl_suspend,
1303*4882a593Smuzhiyun 				     samsung_pinctrl_resume)
1304*4882a593Smuzhiyun };
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun static struct platform_driver samsung_pinctrl_driver = {
1307*4882a593Smuzhiyun 	.probe		= samsung_pinctrl_probe,
1308*4882a593Smuzhiyun 	.driver = {
1309*4882a593Smuzhiyun 		.name	= "samsung-pinctrl",
1310*4882a593Smuzhiyun 		.of_match_table = samsung_pinctrl_dt_match,
1311*4882a593Smuzhiyun 		.suppress_bind_attrs = true,
1312*4882a593Smuzhiyun 		.pm = &samsung_pinctrl_pm_ops,
1313*4882a593Smuzhiyun 	},
1314*4882a593Smuzhiyun };
1315*4882a593Smuzhiyun 
samsung_pinctrl_drv_register(void)1316*4882a593Smuzhiyun static int __init samsung_pinctrl_drv_register(void)
1317*4882a593Smuzhiyun {
1318*4882a593Smuzhiyun 	return platform_driver_register(&samsung_pinctrl_driver);
1319*4882a593Smuzhiyun }
1320*4882a593Smuzhiyun postcore_initcall(samsung_pinctrl_drv_register);
1321