xref: /linux/drivers/pinctrl/ultrarisc/pinctrl-ultrarisc.c (revision 3d5e48944e824bddc20d7b874e784f7b279636fe)
1*cb703792SJia Wang // SPDX-License-Identifier: GPL-2.0
2*cb703792SJia Wang /*
3*cb703792SJia Wang  * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
4*cb703792SJia Wang  *
5*cb703792SJia Wang  * Author: Jia Wang <wangjia@ultrarisc.com>
6*cb703792SJia Wang  */
7*cb703792SJia Wang 
8*cb703792SJia Wang #include <linux/bitfield.h>
9*cb703792SJia Wang #include <linux/io.h>
10*cb703792SJia Wang #include <linux/module.h>
11*cb703792SJia Wang #include <linux/pinctrl/pinconf.h>
12*cb703792SJia Wang #include <linux/pinctrl/pinconf-generic.h>
13*cb703792SJia Wang #include <linux/pinctrl/pinmux.h>
14*cb703792SJia Wang #include <linux/platform_device.h>
15*cb703792SJia Wang #include <linux/seq_file.h>
16*cb703792SJia Wang #include <linux/slab.h>
17*cb703792SJia Wang 
18*cb703792SJia Wang #include "../core.h"
19*cb703792SJia Wang #include "../devicetree.h"
20*cb703792SJia Wang #include "../pinconf.h"
21*cb703792SJia Wang #include "../pinmux.h"
22*cb703792SJia Wang 
23*cb703792SJia Wang #include "pinctrl-ultrarisc.h"
24*cb703792SJia Wang 
25*cb703792SJia Wang #define UR_CONF_BIT_PER_PIN	4
26*cb703792SJia Wang #define UR_CONF_PIN_PER_REG	(32 / UR_CONF_BIT_PER_PIN)
27*cb703792SJia Wang static const u32 ur_drive_strengths[] = { 20, 27, 33, 40 };
28*cb703792SJia Wang 
29*cb703792SJia Wang static const struct ur_port_desc *ur_get_pin_port(struct pinctrl_dev *pctldev,
30*cb703792SJia Wang 						  unsigned int pin)
31*cb703792SJia Wang {
32*cb703792SJia Wang 	const struct pin_desc *desc = pin_desc_get(pctldev, pin);
33*cb703792SJia Wang 
34*cb703792SJia Wang 	if (!desc || !desc->drv_data)
35*cb703792SJia Wang 		return NULL;
36*cb703792SJia Wang 
37*cb703792SJia Wang 	return desc->drv_data;
38*cb703792SJia Wang }
39*cb703792SJia Wang 
40*cb703792SJia Wang static u32 ur_get_pin_conf_offset(const struct ur_port_desc *port_desc, u32 pin)
41*cb703792SJia Wang {
42*cb703792SJia Wang 	return port_desc->conf_offset +
43*cb703792SJia Wang 	       (pin / UR_CONF_PIN_PER_REG) * sizeof(u32);
44*cb703792SJia Wang }
45*cb703792SJia Wang 
46*cb703792SJia Wang static int ur_read_pin_conf(struct ur_pinctrl *pctrl, unsigned int pin, u32 *conf)
47*cb703792SJia Wang {
48*cb703792SJia Wang 	const struct ur_port_desc *port_desc;
49*cb703792SJia Wang 	u32 pin_offset;
50*cb703792SJia Wang 	u32 reg_offset;
51*cb703792SJia Wang 	u32 shift;
52*cb703792SJia Wang 	u32 mask;
53*cb703792SJia Wang 
54*cb703792SJia Wang 	port_desc = ur_get_pin_port(pctrl->pctl_dev, pin);
55*cb703792SJia Wang 	if (!port_desc)
56*cb703792SJia Wang 		return -EINVAL;
57*cb703792SJia Wang 
58*cb703792SJia Wang 	pin_offset = pin - port_desc->pin_base;
59*cb703792SJia Wang 	reg_offset = ur_get_pin_conf_offset(port_desc, pin_offset);
60*cb703792SJia Wang 	shift = (pin_offset % UR_CONF_PIN_PER_REG) * UR_CONF_BIT_PER_PIN;
61*cb703792SJia Wang 	mask = GENMASK(UR_CONF_BIT_PER_PIN - 1, 0) << shift;
62*cb703792SJia Wang 	*conf = field_get(mask, readl_relaxed(pctrl->base + reg_offset));
63*cb703792SJia Wang 
64*cb703792SJia Wang 	return 0;
65*cb703792SJia Wang }
66*cb703792SJia Wang 
67*cb703792SJia Wang static int ur_write_pin_conf(struct ur_pinctrl *pctrl, unsigned int pin, u32 conf)
68*cb703792SJia Wang {
69*cb703792SJia Wang 	const struct ur_port_desc *port_desc;
70*cb703792SJia Wang 	void __iomem *reg;
71*cb703792SJia Wang 	u32 pin_offset;
72*cb703792SJia Wang 	u32 reg_offset;
73*cb703792SJia Wang 	u32 shift;
74*cb703792SJia Wang 	u32 mask;
75*cb703792SJia Wang 	u32 val;
76*cb703792SJia Wang 
77*cb703792SJia Wang 	port_desc = ur_get_pin_port(pctrl->pctl_dev, pin);
78*cb703792SJia Wang 	if (!port_desc)
79*cb703792SJia Wang 		return -EINVAL;
80*cb703792SJia Wang 
81*cb703792SJia Wang 	pin_offset = pin - port_desc->pin_base;
82*cb703792SJia Wang 	reg_offset = ur_get_pin_conf_offset(port_desc, pin_offset);
83*cb703792SJia Wang 	reg = pctrl->base + reg_offset;
84*cb703792SJia Wang 	shift = (pin_offset % UR_CONF_PIN_PER_REG) * UR_CONF_BIT_PER_PIN;
85*cb703792SJia Wang 	mask = GENMASK(UR_CONF_BIT_PER_PIN - 1, 0) << shift;
86*cb703792SJia Wang 
87*cb703792SJia Wang 	scoped_guard(raw_spinlock_irqsave, &pctrl->lock) {
88*cb703792SJia Wang 		val = readl_relaxed(reg);
89*cb703792SJia Wang 		val = (val & ~mask) | field_prep(mask, conf);
90*cb703792SJia Wang 		writel_relaxed(val, reg);
91*cb703792SJia Wang 	}
92*cb703792SJia Wang 
93*cb703792SJia Wang 	return 0;
94*cb703792SJia Wang }
95*cb703792SJia Wang 
96*cb703792SJia Wang static int ur_set_pin_mux(struct ur_pinctrl *pctrl,
97*cb703792SJia Wang 			  const struct ur_port_desc *port_desc,
98*cb703792SJia Wang 			  u32 pin_offset, u32 mode)
99*cb703792SJia Wang {
100*cb703792SJia Wang 	void __iomem *reg = pctrl->base + port_desc->func_offset;
101*cb703792SJia Wang 	u32 val;
102*cb703792SJia Wang 
103*cb703792SJia Wang 	if (WARN_ON(pin_offset >= UR_MAX_PINS_PER_PORT))
104*cb703792SJia Wang 		return -EINVAL;
105*cb703792SJia Wang 
106*cb703792SJia Wang 	scoped_guard(raw_spinlock_irqsave, &pctrl->lock) {
107*cb703792SJia Wang 		val = readl_relaxed(reg);
108*cb703792SJia Wang 		val &= ~((UR_FUNC_0 | UR_FUNC_1) << pin_offset);
109*cb703792SJia Wang 		val |= mode << pin_offset;
110*cb703792SJia Wang 		writel_relaxed(val, reg);
111*cb703792SJia Wang 	}
112*cb703792SJia Wang 
113*cb703792SJia Wang 	return 0;
114*cb703792SJia Wang }
115*cb703792SJia Wang 
116*cb703792SJia Wang static int ur_set_pin_mux_by_num(struct ur_pinctrl *pctrl, unsigned int pin, u32 mode)
117*cb703792SJia Wang {
118*cb703792SJia Wang 	const struct ur_port_desc *port_desc = ur_get_pin_port(pctrl->pctl_dev, pin);
119*cb703792SJia Wang 	u32 pin_offset;
120*cb703792SJia Wang 
121*cb703792SJia Wang 	if (!port_desc)
122*cb703792SJia Wang 		return -EINVAL;
123*cb703792SJia Wang 
124*cb703792SJia Wang 	if (mode != UR_FUNC_DEFAULT && !(port_desc->supported_modes & mode))
125*cb703792SJia Wang 		return -EINVAL;
126*cb703792SJia Wang 
127*cb703792SJia Wang 	pin_offset = pin - port_desc->pin_base;
128*cb703792SJia Wang 
129*cb703792SJia Wang 	return ur_set_pin_mux(pctrl, port_desc, pin_offset, mode);
130*cb703792SJia Wang }
131*cb703792SJia Wang 
132*cb703792SJia Wang static int ur_hw_to_config(unsigned long *config, u32 conf)
133*cb703792SJia Wang {
134*cb703792SJia Wang 	enum pin_config_param param = pinconf_to_config_param(*config);
135*cb703792SJia Wang 	u32 drive = FIELD_GET(UR_DRIVE_MASK, conf);
136*cb703792SJia Wang 	u32 pull = FIELD_GET(UR_PULL_MASK, conf);
137*cb703792SJia Wang 
138*cb703792SJia Wang 	switch (param) {
139*cb703792SJia Wang 	case PIN_CONFIG_BIAS_DISABLE:
140*cb703792SJia Wang 	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
141*cb703792SJia Wang 		if (pull != UR_PULL_DIS)
142*cb703792SJia Wang 			return -EINVAL;
143*cb703792SJia Wang 		*config = pinconf_to_config_packed(param, 1);
144*cb703792SJia Wang 		return 0;
145*cb703792SJia Wang 	case PIN_CONFIG_BIAS_PULL_UP:
146*cb703792SJia Wang 		if (pull != UR_PULL_UP)
147*cb703792SJia Wang 			return -EINVAL;
148*cb703792SJia Wang 		*config = pinconf_to_config_packed(param, 1);
149*cb703792SJia Wang 		return 0;
150*cb703792SJia Wang 	case PIN_CONFIG_BIAS_PULL_DOWN:
151*cb703792SJia Wang 	case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
152*cb703792SJia Wang 		if (pull != UR_PULL_DOWN)
153*cb703792SJia Wang 			return -EINVAL;
154*cb703792SJia Wang 		*config = pinconf_to_config_packed(param, 1);
155*cb703792SJia Wang 		return 0;
156*cb703792SJia Wang 	case PIN_CONFIG_DRIVE_STRENGTH:
157*cb703792SJia Wang 		if (drive >= ARRAY_SIZE(ur_drive_strengths))
158*cb703792SJia Wang 			return -EINVAL;
159*cb703792SJia Wang 		*config = pinconf_to_config_packed(param, ur_drive_strengths[drive]);
160*cb703792SJia Wang 		return 0;
161*cb703792SJia Wang 	default:
162*cb703792SJia Wang 		return -EINVAL;
163*cb703792SJia Wang 	}
164*cb703792SJia Wang }
165*cb703792SJia Wang 
166*cb703792SJia Wang static int ur_config_to_hw(unsigned long config, u32 *conf)
167*cb703792SJia Wang {
168*cb703792SJia Wang 	enum pin_config_param param = pinconf_to_config_param(config);
169*cb703792SJia Wang 	u32 arg = pinconf_to_config_argument(config);
170*cb703792SJia Wang 
171*cb703792SJia Wang 	switch (param) {
172*cb703792SJia Wang 	case PIN_CONFIG_BIAS_DISABLE:
173*cb703792SJia Wang 	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
174*cb703792SJia Wang 		FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_DIS);
175*cb703792SJia Wang 		return 0;
176*cb703792SJia Wang 	case PIN_CONFIG_BIAS_PULL_UP:
177*cb703792SJia Wang 		FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_UP);
178*cb703792SJia Wang 		return 0;
179*cb703792SJia Wang 	case PIN_CONFIG_BIAS_PULL_DOWN:
180*cb703792SJia Wang 	case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
181*cb703792SJia Wang 		FIELD_MODIFY(UR_PULL_MASK, conf, UR_PULL_DOWN);
182*cb703792SJia Wang 		return 0;
183*cb703792SJia Wang 	case PIN_CONFIG_DRIVE_STRENGTH:
184*cb703792SJia Wang 		for (u32 i = 0; i < ARRAY_SIZE(ur_drive_strengths); i++) {
185*cb703792SJia Wang 			if (ur_drive_strengths[i] != arg)
186*cb703792SJia Wang 				continue;
187*cb703792SJia Wang 			FIELD_MODIFY(UR_DRIVE_MASK, conf, i);
188*cb703792SJia Wang 			return 0;
189*cb703792SJia Wang 		}
190*cb703792SJia Wang 		return -EINVAL;
191*cb703792SJia Wang 	case PIN_CONFIG_PERSIST_STATE:
192*cb703792SJia Wang 		/*
193*cb703792SJia Wang 		 * For PIN_CONFIG_PERSIST_STATE, gpiolib only treats
194*cb703792SJia Wang 		 * -ENOTSUPP as an optional unsupported result.
195*cb703792SJia Wang 		 * Do not use -EOPNOTSUPP here.
196*cb703792SJia Wang 		 */
197*cb703792SJia Wang 		return -ENOTSUPP;
198*cb703792SJia Wang 	default:
199*cb703792SJia Wang 		return -EOPNOTSUPP;
200*cb703792SJia Wang 	}
201*cb703792SJia Wang }
202*cb703792SJia Wang 
203*cb703792SJia Wang /**
204*cb703792SJia Wang  * ur_find_group_route() - Find the route matching a function and pin set
205*cb703792SJia Wang  * @pctrl: pin controller instance
206*cb703792SJia Wang  * @function: mux function name
207*cb703792SJia Wang  * @group_mask: bitmap of pins in the selected group
208*cb703792SJia Wang  * @route_out: returned route entry on success
209*cb703792SJia Wang  *
210*cb703792SJia Wang  * A mux function may be associated with multiple hardware routing options,
211*cb703792SJia Wang  * each valid for a specific set of pins. This helper finds the unique route
212*cb703792SJia Wang  * whose valid_pins mask covers all pins in @group_mask.
213*cb703792SJia Wang  *
214*cb703792SJia Wang  * The routing table must guarantee that a given function plus pin set
215*cb703792SJia Wang  * resolves to exactly one route. If multiple routes match, the routing
216*cb703792SJia Wang  * description is considered ambiguous and the lookup fails.
217*cb703792SJia Wang  *
218*cb703792SJia Wang  * Return: 0 on success, or -EINVAL if no matching route exists or if the
219*cb703792SJia Wang  * routing table contains ambiguous entries.
220*cb703792SJia Wang  */
221*cb703792SJia Wang static int ur_find_group_route(struct ur_pinctrl *pctrl,
222*cb703792SJia Wang 			       const char *function,
223*cb703792SJia Wang 			       u64 group_mask,
224*cb703792SJia Wang 			       const struct ur_func_route **route_out)
225*cb703792SJia Wang {
226*cb703792SJia Wang 	const struct ur_func_route *match = NULL;
227*cb703792SJia Wang 
228*cb703792SJia Wang 	for (u32 i = 0; i < pctrl->data->num_routes; i++) {
229*cb703792SJia Wang 		const struct ur_func_route *route = &pctrl->data->routes[i];
230*cb703792SJia Wang 
231*cb703792SJia Wang 		if (strcmp(route->function, function))
232*cb703792SJia Wang 			continue;
233*cb703792SJia Wang 
234*cb703792SJia Wang 		if ((route->valid_pins & group_mask) != group_mask)
235*cb703792SJia Wang 			continue;
236*cb703792SJia Wang 
237*cb703792SJia Wang 		if (match) {
238*cb703792SJia Wang 			dev_err(pctrl->dev,
239*cb703792SJia Wang 				"ambiguous route for function %s group_mask=%#llx\n",
240*cb703792SJia Wang 				function, (unsigned long long)group_mask);
241*cb703792SJia Wang 			return -EINVAL;
242*cb703792SJia Wang 		}
243*cb703792SJia Wang 
244*cb703792SJia Wang 		match = route;
245*cb703792SJia Wang 	}
246*cb703792SJia Wang 
247*cb703792SJia Wang 	if (match) {
248*cb703792SJia Wang 		*route_out = match;
249*cb703792SJia Wang 		return 0;
250*cb703792SJia Wang 	}
251*cb703792SJia Wang 
252*cb703792SJia Wang 	return -EINVAL;
253*cb703792SJia Wang }
254*cb703792SJia Wang 
255*cb703792SJia Wang static const char *ur_get_group_function(struct pinctrl_dev *pctldev,
256*cb703792SJia Wang 					 unsigned int group_selector,
257*cb703792SJia Wang 					 unsigned int pin_index)
258*cb703792SJia Wang {
259*cb703792SJia Wang 	const struct group_desc *group;
260*cb703792SJia Wang 	const char * const *functions;
261*cb703792SJia Wang 
262*cb703792SJia Wang 	group = pinctrl_generic_get_group(pctldev, group_selector);
263*cb703792SJia Wang 	if (!group || pin_index >= group->grp.npins || !group->data)
264*cb703792SJia Wang 		return NULL;
265*cb703792SJia Wang 
266*cb703792SJia Wang 	functions = group->data;
267*cb703792SJia Wang 
268*cb703792SJia Wang 	return functions[pin_index];
269*cb703792SJia Wang }
270*cb703792SJia Wang 
271*cb703792SJia Wang static int ur_resolve_group_mux(struct pinctrl_dev *pctldev,
272*cb703792SJia Wang 				struct ur_pinctrl *pctrl,
273*cb703792SJia Wang 				unsigned int group_selector,
274*cb703792SJia Wang 				const unsigned int *pins,
275*cb703792SJia Wang 				unsigned int npins,
276*cb703792SJia Wang 				const struct ur_func_route **route_out)
277*cb703792SJia Wang {
278*cb703792SJia Wang 	const char *function;
279*cb703792SJia Wang 	u64 group_mask = 0;
280*cb703792SJia Wang 
281*cb703792SJia Wang 	if (!npins)
282*cb703792SJia Wang 		return -EINVAL;
283*cb703792SJia Wang 
284*cb703792SJia Wang 	function = ur_get_group_function(pctldev, group_selector, 0);
285*cb703792SJia Wang 	if (!function)
286*cb703792SJia Wang 		return -EINVAL;
287*cb703792SJia Wang 
288*cb703792SJia Wang 	for (u32 i = 0; i < npins; i++)
289*cb703792SJia Wang 		group_mask |= BIT_ULL(pins[i]);
290*cb703792SJia Wang 
291*cb703792SJia Wang 	return ur_find_group_route(pctrl, function, group_mask, route_out);
292*cb703792SJia Wang }
293*cb703792SJia Wang 
294*cb703792SJia Wang static bool ur_function_is_gpio(struct pinctrl_dev *pctldev,
295*cb703792SJia Wang 				unsigned int selector)
296*cb703792SJia Wang {
297*cb703792SJia Wang 	const struct function_desc *function;
298*cb703792SJia Wang 
299*cb703792SJia Wang 	function = pinmux_generic_get_function(pctldev, selector);
300*cb703792SJia Wang 	if (!function)
301*cb703792SJia Wang 		return false;
302*cb703792SJia Wang 
303*cb703792SJia Wang 	for (u32 i = 0; i < function->func->ngroups; i++) {
304*cb703792SJia Wang 		const char *func_name;
305*cb703792SJia Wang 		int group_selector;
306*cb703792SJia Wang 
307*cb703792SJia Wang 		group_selector = pinctrl_get_group_selector(pctldev,
308*cb703792SJia Wang 							    function->func->groups[i]);
309*cb703792SJia Wang 		if (group_selector < 0)
310*cb703792SJia Wang 			return false;
311*cb703792SJia Wang 
312*cb703792SJia Wang 		func_name = ur_get_group_function(pctldev, group_selector, 0);
313*cb703792SJia Wang 		if (!func_name || strcmp(func_name, "gpio"))
314*cb703792SJia Wang 			return false;
315*cb703792SJia Wang 	}
316*cb703792SJia Wang 
317*cb703792SJia Wang 	return true;
318*cb703792SJia Wang }
319*cb703792SJia Wang 
320*cb703792SJia Wang static const struct pinctrl_ops ur_pinctrl_ops = {
321*cb703792SJia Wang 	.get_groups_count = pinctrl_generic_get_group_count,
322*cb703792SJia Wang 	.get_group_name = pinctrl_generic_get_group_name,
323*cb703792SJia Wang 	.get_group_pins = pinctrl_generic_get_group_pins,
324*cb703792SJia Wang 	.dt_node_to_map = pinctrl_generic_pins_function_dt_node_to_map,
325*cb703792SJia Wang 	.dt_free_map = pinconf_generic_dt_free_map,
326*cb703792SJia Wang };
327*cb703792SJia Wang 
328*cb703792SJia Wang static int ur_gpio_request_enable(struct pinctrl_dev *pctldev,
329*cb703792SJia Wang 				  struct pinctrl_gpio_range *range,
330*cb703792SJia Wang 				  unsigned int offset)
331*cb703792SJia Wang {
332*cb703792SJia Wang 	struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
333*cb703792SJia Wang 	const struct ur_port_desc *port_desc;
334*cb703792SJia Wang 	const struct ur_func_route *route;
335*cb703792SJia Wang 	int ret;
336*cb703792SJia Wang 
337*cb703792SJia Wang 	(void)range;
338*cb703792SJia Wang 
339*cb703792SJia Wang 	port_desc = ur_get_pin_port(pctldev, offset);
340*cb703792SJia Wang 	if (!port_desc || !port_desc->supports_gpio)
341*cb703792SJia Wang 		return -EINVAL;
342*cb703792SJia Wang 
343*cb703792SJia Wang 	ret = ur_find_group_route(pctrl, "gpio", BIT_ULL(offset), &route);
344*cb703792SJia Wang 	if (ret)
345*cb703792SJia Wang 		return ret;
346*cb703792SJia Wang 
347*cb703792SJia Wang 	return ur_set_pin_mux_by_num(pctrl, offset, route->mode);
348*cb703792SJia Wang }
349*cb703792SJia Wang 
350*cb703792SJia Wang static int ur_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector,
351*cb703792SJia Wang 		      unsigned int group_selector)
352*cb703792SJia Wang {
353*cb703792SJia Wang 	struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
354*cb703792SJia Wang 	const struct ur_func_route *route;
355*cb703792SJia Wang 	const unsigned int *pins;
356*cb703792SJia Wang 	unsigned int npins;
357*cb703792SJia Wang 	int ret;
358*cb703792SJia Wang 
359*cb703792SJia Wang 	(void)func_selector;
360*cb703792SJia Wang 
361*cb703792SJia Wang 	ret = pinctrl_generic_get_group_pins(pctldev, group_selector, &pins, &npins);
362*cb703792SJia Wang 	if (ret)
363*cb703792SJia Wang 		return ret;
364*cb703792SJia Wang 
365*cb703792SJia Wang 	ret = ur_resolve_group_mux(pctldev, pctrl, group_selector, pins, npins,
366*cb703792SJia Wang 				   &route);
367*cb703792SJia Wang 	if (ret)
368*cb703792SJia Wang 		return ret;
369*cb703792SJia Wang 
370*cb703792SJia Wang 	for (u32 i = 0; i < npins; i++) {
371*cb703792SJia Wang 		ret = ur_set_pin_mux_by_num(pctrl, pins[i], route->mode);
372*cb703792SJia Wang 		if (ret)
373*cb703792SJia Wang 			return ret;
374*cb703792SJia Wang 	}
375*cb703792SJia Wang 
376*cb703792SJia Wang 	return 0;
377*cb703792SJia Wang }
378*cb703792SJia Wang 
379*cb703792SJia Wang static const struct pinmux_ops ur_pinmux_ops = {
380*cb703792SJia Wang 	.get_functions_count = pinmux_generic_get_function_count,
381*cb703792SJia Wang 	.get_function_name = pinmux_generic_get_function_name,
382*cb703792SJia Wang 	.get_function_groups = pinmux_generic_get_function_groups,
383*cb703792SJia Wang 	.function_is_gpio = ur_function_is_gpio,
384*cb703792SJia Wang 	.set_mux = ur_set_mux,
385*cb703792SJia Wang 	.gpio_request_enable = ur_gpio_request_enable,
386*cb703792SJia Wang 	.strict = true,
387*cb703792SJia Wang };
388*cb703792SJia Wang 
389*cb703792SJia Wang static int ur_pin_config_get(struct pinctrl_dev *pctldev,
390*cb703792SJia Wang 			     unsigned int pin,
391*cb703792SJia Wang 			     unsigned long *config)
392*cb703792SJia Wang {
393*cb703792SJia Wang 	struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
394*cb703792SJia Wang 	u32 conf;
395*cb703792SJia Wang 	int ret;
396*cb703792SJia Wang 
397*cb703792SJia Wang 	ret = ur_read_pin_conf(pctrl, pin, &conf);
398*cb703792SJia Wang 	if (ret)
399*cb703792SJia Wang 		return ret;
400*cb703792SJia Wang 
401*cb703792SJia Wang 	return ur_hw_to_config(config, conf);
402*cb703792SJia Wang }
403*cb703792SJia Wang 
404*cb703792SJia Wang static int ur_pin_config_set(struct pinctrl_dev *pctldev,
405*cb703792SJia Wang 			     unsigned int pin,
406*cb703792SJia Wang 			     unsigned long *configs,
407*cb703792SJia Wang 			     unsigned int num_configs)
408*cb703792SJia Wang {
409*cb703792SJia Wang 	struct ur_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
410*cb703792SJia Wang 	u32 conf;
411*cb703792SJia Wang 	int ret;
412*cb703792SJia Wang 
413*cb703792SJia Wang 	ret = ur_read_pin_conf(pctrl, pin, &conf);
414*cb703792SJia Wang 	if (ret)
415*cb703792SJia Wang 		return ret;
416*cb703792SJia Wang 
417*cb703792SJia Wang 	for (u32 i = 0; i < num_configs; i++) {
418*cb703792SJia Wang 		ret = ur_config_to_hw(configs[i], &conf);
419*cb703792SJia Wang 		if (ret)
420*cb703792SJia Wang 			return ret;
421*cb703792SJia Wang 	}
422*cb703792SJia Wang 
423*cb703792SJia Wang 	return ur_write_pin_conf(pctrl, pin, conf);
424*cb703792SJia Wang }
425*cb703792SJia Wang 
426*cb703792SJia Wang static int ur_pin_config_group_get(struct pinctrl_dev *pctldev,
427*cb703792SJia Wang 				   unsigned int selector,
428*cb703792SJia Wang 				   unsigned long *config)
429*cb703792SJia Wang {
430*cb703792SJia Wang 	const unsigned int *pins;
431*cb703792SJia Wang 	unsigned int npins;
432*cb703792SJia Wang 	int ret;
433*cb703792SJia Wang 
434*cb703792SJia Wang 	ret = pinctrl_generic_get_group_pins(pctldev, selector, &pins, &npins);
435*cb703792SJia Wang 	if (ret || !npins)
436*cb703792SJia Wang 		return ret ?: -EINVAL;
437*cb703792SJia Wang 
438*cb703792SJia Wang 	return ur_pin_config_get(pctldev, pins[0], config);
439*cb703792SJia Wang }
440*cb703792SJia Wang 
441*cb703792SJia Wang static int ur_pin_config_group_set(struct pinctrl_dev *pctldev,
442*cb703792SJia Wang 				   unsigned int selector,
443*cb703792SJia Wang 				   unsigned long *configs,
444*cb703792SJia Wang 				   unsigned int num_configs)
445*cb703792SJia Wang {
446*cb703792SJia Wang 	const unsigned int *pins;
447*cb703792SJia Wang 	unsigned int npins;
448*cb703792SJia Wang 	int ret;
449*cb703792SJia Wang 
450*cb703792SJia Wang 	ret = pinctrl_generic_get_group_pins(pctldev, selector, &pins, &npins);
451*cb703792SJia Wang 	if (ret)
452*cb703792SJia Wang 		return ret;
453*cb703792SJia Wang 
454*cb703792SJia Wang 	for (u32 i = 0; i < npins; i++) {
455*cb703792SJia Wang 		ret = ur_pin_config_set(pctldev, pins[i], configs, num_configs);
456*cb703792SJia Wang 		if (ret)
457*cb703792SJia Wang 			return ret;
458*cb703792SJia Wang 	}
459*cb703792SJia Wang 
460*cb703792SJia Wang 	return 0;
461*cb703792SJia Wang }
462*cb703792SJia Wang 
463*cb703792SJia Wang static const struct pinconf_ops ur_pinconf_ops = {
464*cb703792SJia Wang 	.pin_config_get = ur_pin_config_get,
465*cb703792SJia Wang 	.pin_config_set = ur_pin_config_set,
466*cb703792SJia Wang 	.pin_config_group_get = ur_pin_config_group_get,
467*cb703792SJia Wang 	.pin_config_group_set = ur_pin_config_group_set,
468*cb703792SJia Wang 	.is_generic = true,
469*cb703792SJia Wang 	.pin_config_config_dbg_show = pinconf_generic_dump_config,
470*cb703792SJia Wang };
471*cb703792SJia Wang 
472*cb703792SJia Wang int ur_pinctrl_probe(struct platform_device *pdev,
473*cb703792SJia Wang 		     const struct ur_pinctrl_data *data)
474*cb703792SJia Wang {
475*cb703792SJia Wang 	struct pinctrl_desc *desc;
476*cb703792SJia Wang 	struct ur_pinctrl *pctrl;
477*cb703792SJia Wang 	int ret;
478*cb703792SJia Wang 
479*cb703792SJia Wang 	if (!data)
480*cb703792SJia Wang 		return -ENODEV;
481*cb703792SJia Wang 
482*cb703792SJia Wang 	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
483*cb703792SJia Wang 	if (!desc)
484*cb703792SJia Wang 		return -ENOMEM;
485*cb703792SJia Wang 
486*cb703792SJia Wang 	pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
487*cb703792SJia Wang 	if (!pctrl)
488*cb703792SJia Wang 		return -ENOMEM;
489*cb703792SJia Wang 
490*cb703792SJia Wang 	pctrl->base = devm_platform_ioremap_resource(pdev, 0);
491*cb703792SJia Wang 	if (IS_ERR(pctrl->base))
492*cb703792SJia Wang 		return PTR_ERR(pctrl->base);
493*cb703792SJia Wang 	pctrl->dev = &pdev->dev;
494*cb703792SJia Wang 	pctrl->data = data;
495*cb703792SJia Wang 
496*cb703792SJia Wang 	raw_spin_lock_init(&pctrl->lock);
497*cb703792SJia Wang 
498*cb703792SJia Wang 	desc->name = dev_name(&pdev->dev);
499*cb703792SJia Wang 	desc->owner = THIS_MODULE;
500*cb703792SJia Wang 	desc->pins = data->pins;
501*cb703792SJia Wang 	desc->npins = data->npins;
502*cb703792SJia Wang 	desc->pctlops = &ur_pinctrl_ops;
503*cb703792SJia Wang 	desc->pmxops = &ur_pinmux_ops;
504*cb703792SJia Wang 	desc->confops = &ur_pinconf_ops;
505*cb703792SJia Wang 
506*cb703792SJia Wang 	ret = devm_pinctrl_register_and_init(&pdev->dev, desc, pctrl, &pctrl->pctl_dev);
507*cb703792SJia Wang 	if (ret)
508*cb703792SJia Wang 		return dev_err_probe(&pdev->dev, ret, "failed to register pinctrl\n");
509*cb703792SJia Wang 
510*cb703792SJia Wang 	platform_set_drvdata(pdev, pctrl);
511*cb703792SJia Wang 
512*cb703792SJia Wang 	return pinctrl_enable(pctrl->pctl_dev);
513*cb703792SJia Wang }
514*cb703792SJia Wang EXPORT_SYMBOL_GPL(ur_pinctrl_probe);
515*cb703792SJia Wang 
516*cb703792SJia Wang MODULE_DESCRIPTION("UltraRISC pinctrl core driver");
517*cb703792SJia Wang MODULE_LICENSE("GPL");
518