xref: /linux/drivers/pinctrl/bcm/pinctrl-brcmstb.c (revision ec2e0fb07d789976c601bec19ecced7a501c3705)
1*657cbf9bSIvan T. Ivanov // SPDX-License-Identifier: GPL-2.0+
2*657cbf9bSIvan T. Ivanov /*
3*657cbf9bSIvan T. Ivanov  * Driver for Broadcom brcmstb GPIO units (pinctrl only)
4*657cbf9bSIvan T. Ivanov  *
5*657cbf9bSIvan T. Ivanov  * Copyright (C) 2024-2025 Ivan T. Ivanov, Andrea della Porta
6*657cbf9bSIvan T. Ivanov  * Copyright (C) 2021-3 Raspberry Pi Ltd.
7*657cbf9bSIvan T. Ivanov  * Copyright (C) 2012 Chris Boot, Simon Arlott, Stephen Warren
8*657cbf9bSIvan T. Ivanov  *
9*657cbf9bSIvan T. Ivanov  * Based heavily on the BCM2835 GPIO & pinctrl driver, which was inspired by:
10*657cbf9bSIvan T. Ivanov  * pinctrl-nomadik.c, please see original file for copyright information
11*657cbf9bSIvan T. Ivanov  * pinctrl-tegra.c, please see original file for copyright information
12*657cbf9bSIvan T. Ivanov  */
13*657cbf9bSIvan T. Ivanov 
14*657cbf9bSIvan T. Ivanov #include <linux/device.h>
15*657cbf9bSIvan T. Ivanov #include <linux/err.h>
16*657cbf9bSIvan T. Ivanov #include <linux/init.h>
17*657cbf9bSIvan T. Ivanov #include <linux/io.h>
18*657cbf9bSIvan T. Ivanov #include <linux/of.h>
19*657cbf9bSIvan T. Ivanov #include <linux/pinctrl/pinconf.h>
20*657cbf9bSIvan T. Ivanov #include <linux/pinctrl/pinctrl.h>
21*657cbf9bSIvan T. Ivanov #include <linux/pinctrl/pinmux.h>
22*657cbf9bSIvan T. Ivanov #include <linux/pinctrl/pinconf-generic.h>
23*657cbf9bSIvan T. Ivanov #include <linux/seq_file.h>
24*657cbf9bSIvan T. Ivanov #include <linux/slab.h>
25*657cbf9bSIvan T. Ivanov #include <linux/spinlock.h>
26*657cbf9bSIvan T. Ivanov #include <linux/cleanup.h>
27*657cbf9bSIvan T. Ivanov 
28*657cbf9bSIvan T. Ivanov #include "pinctrl-brcmstb.h"
29*657cbf9bSIvan T. Ivanov 
30*657cbf9bSIvan T. Ivanov #define BRCMSTB_PULL_NONE	0
31*657cbf9bSIvan T. Ivanov #define BRCMSTB_PULL_DOWN	1
32*657cbf9bSIvan T. Ivanov #define BRCMSTB_PULL_UP		2
33*657cbf9bSIvan T. Ivanov #define BRCMSTB_PULL_MASK	0x3
34*657cbf9bSIvan T. Ivanov 
35*657cbf9bSIvan T. Ivanov #define BIT_TO_REG(b)		(((b) >> 5) << 2)
36*657cbf9bSIvan T. Ivanov #define BIT_TO_SHIFT(b)		((b) & 0x1f)
37*657cbf9bSIvan T. Ivanov 
38*657cbf9bSIvan T. Ivanov struct brcmstb_pinctrl {
39*657cbf9bSIvan T. Ivanov 	struct device *dev;
40*657cbf9bSIvan T. Ivanov 	void __iomem *base;
41*657cbf9bSIvan T. Ivanov 	struct pinctrl_dev *pctl_dev;
42*657cbf9bSIvan T. Ivanov 	struct pinctrl_desc pctl_desc;
43*657cbf9bSIvan T. Ivanov 	const struct pin_regs *pin_regs;
44*657cbf9bSIvan T. Ivanov 	const struct brcmstb_pin_funcs *pin_funcs;
45*657cbf9bSIvan T. Ivanov 	const char * const *func_names;
46*657cbf9bSIvan T. Ivanov 	unsigned int func_count;
47*657cbf9bSIvan T. Ivanov 	unsigned int func_gpio;
48*657cbf9bSIvan T. Ivanov 	const char *const *gpio_groups;
49*657cbf9bSIvan T. Ivanov 	struct pinctrl_gpio_range gpio_range;
50*657cbf9bSIvan T. Ivanov 	/* Protect FSEL registers */
51*657cbf9bSIvan T. Ivanov 	spinlock_t fsel_lock;
52*657cbf9bSIvan T. Ivanov };
53*657cbf9bSIvan T. Ivanov 
54*657cbf9bSIvan T. Ivanov static unsigned int brcmstb_pinctrl_fsel_get(struct brcmstb_pinctrl *pc,
55*657cbf9bSIvan T. Ivanov 					     unsigned int pin)
56*657cbf9bSIvan T. Ivanov {
57*657cbf9bSIvan T. Ivanov 	u32 bit = pc->pin_regs[pin].mux_bit;
58*657cbf9bSIvan T. Ivanov 	unsigned int func;
59*657cbf9bSIvan T. Ivanov 	int fsel;
60*657cbf9bSIvan T. Ivanov 	u32 val;
61*657cbf9bSIvan T. Ivanov 
62*657cbf9bSIvan T. Ivanov 	if (!bit)
63*657cbf9bSIvan T. Ivanov 		return pc->func_gpio;
64*657cbf9bSIvan T. Ivanov 
65*657cbf9bSIvan T. Ivanov 	bit &= ~MUX_BIT_VALID;
66*657cbf9bSIvan T. Ivanov 
67*657cbf9bSIvan T. Ivanov 	val = readl(pc->base + BIT_TO_REG(bit));
68*657cbf9bSIvan T. Ivanov 	fsel = (val >> BIT_TO_SHIFT(bit)) & pc->pin_funcs[pin].func_mask;
69*657cbf9bSIvan T. Ivanov 	func = pc->pin_funcs[pin].funcs[fsel];
70*657cbf9bSIvan T. Ivanov 
71*657cbf9bSIvan T. Ivanov 	if (func >= pc->func_count)
72*657cbf9bSIvan T. Ivanov 		func = fsel;
73*657cbf9bSIvan T. Ivanov 
74*657cbf9bSIvan T. Ivanov 	dev_dbg(pc->dev, "get %04x: %08x (%u => %s)\n",
75*657cbf9bSIvan T. Ivanov 		BIT_TO_REG(bit), val, pin,
76*657cbf9bSIvan T. Ivanov 		pc->func_names[func]);
77*657cbf9bSIvan T. Ivanov 
78*657cbf9bSIvan T. Ivanov 	return func;
79*657cbf9bSIvan T. Ivanov }
80*657cbf9bSIvan T. Ivanov 
81*657cbf9bSIvan T. Ivanov static int brcmstb_pinctrl_fsel_set(struct brcmstb_pinctrl *pc,
82*657cbf9bSIvan T. Ivanov 				    unsigned int pin, unsigned int func)
83*657cbf9bSIvan T. Ivanov {
84*657cbf9bSIvan T. Ivanov 	u32 bit = pc->pin_regs[pin].mux_bit, val, fsel_mask;
85*657cbf9bSIvan T. Ivanov 	const u8 *pin_funcs;
86*657cbf9bSIvan T. Ivanov 	int fsel;
87*657cbf9bSIvan T. Ivanov 	int cur;
88*657cbf9bSIvan T. Ivanov 	int i;
89*657cbf9bSIvan T. Ivanov 
90*657cbf9bSIvan T. Ivanov 	if (!bit || func >= pc->func_count)
91*657cbf9bSIvan T. Ivanov 		return -EINVAL;
92*657cbf9bSIvan T. Ivanov 
93*657cbf9bSIvan T. Ivanov 	bit &= ~MUX_BIT_VALID;
94*657cbf9bSIvan T. Ivanov 
95*657cbf9bSIvan T. Ivanov 	fsel = pc->pin_funcs[pin].n_funcs + 1;
96*657cbf9bSIvan T. Ivanov 	fsel_mask = pc->pin_funcs[pin].func_mask;
97*657cbf9bSIvan T. Ivanov 
98*657cbf9bSIvan T. Ivanov 	if (func >= fsel) {
99*657cbf9bSIvan T. Ivanov 		/* Convert to an fsel number */
100*657cbf9bSIvan T. Ivanov 		pin_funcs = pc->pin_funcs[pin].funcs;
101*657cbf9bSIvan T. Ivanov 		for (i = 1; i < fsel; i++) {
102*657cbf9bSIvan T. Ivanov 			if (pin_funcs[i - 1] == func) {
103*657cbf9bSIvan T. Ivanov 				fsel = i;
104*657cbf9bSIvan T. Ivanov 				break;
105*657cbf9bSIvan T. Ivanov 			}
106*657cbf9bSIvan T. Ivanov 		}
107*657cbf9bSIvan T. Ivanov 	} else {
108*657cbf9bSIvan T. Ivanov 		fsel = func;
109*657cbf9bSIvan T. Ivanov 	}
110*657cbf9bSIvan T. Ivanov 
111*657cbf9bSIvan T. Ivanov 	if (fsel >= pc->pin_funcs[pin].n_funcs + 1)
112*657cbf9bSIvan T. Ivanov 		return -EINVAL;
113*657cbf9bSIvan T. Ivanov 
114*657cbf9bSIvan T. Ivanov 	guard(spinlock_irqsave)(&pc->fsel_lock);
115*657cbf9bSIvan T. Ivanov 
116*657cbf9bSIvan T. Ivanov 	val = readl(pc->base + BIT_TO_REG(bit));
117*657cbf9bSIvan T. Ivanov 	cur = (val >> BIT_TO_SHIFT(bit)) & fsel_mask;
118*657cbf9bSIvan T. Ivanov 
119*657cbf9bSIvan T. Ivanov 	dev_dbg(pc->dev, "read %04x: %08x (%u => %s)\n",
120*657cbf9bSIvan T. Ivanov 		BIT_TO_REG(bit), val, pin,
121*657cbf9bSIvan T. Ivanov 		pc->func_names[cur]);
122*657cbf9bSIvan T. Ivanov 
123*657cbf9bSIvan T. Ivanov 	if (cur != fsel) {
124*657cbf9bSIvan T. Ivanov 		val &= ~(fsel_mask << BIT_TO_SHIFT(bit));
125*657cbf9bSIvan T. Ivanov 		val |= fsel << BIT_TO_SHIFT(bit);
126*657cbf9bSIvan T. Ivanov 
127*657cbf9bSIvan T. Ivanov 		dev_dbg(pc->dev, "write %04x: %08x (%u <= %s)\n",
128*657cbf9bSIvan T. Ivanov 			BIT_TO_REG(bit), val, pin,
129*657cbf9bSIvan T. Ivanov 			pc->func_names[fsel]);
130*657cbf9bSIvan T. Ivanov 		writel(val, pc->base + BIT_TO_REG(bit));
131*657cbf9bSIvan T. Ivanov 	}
132*657cbf9bSIvan T. Ivanov 
133*657cbf9bSIvan T. Ivanov 	return 0;
134*657cbf9bSIvan T. Ivanov }
135*657cbf9bSIvan T. Ivanov 
136*657cbf9bSIvan T. Ivanov static int brcmstb_pctl_get_groups_count(struct pinctrl_dev *pctldev)
137*657cbf9bSIvan T. Ivanov {
138*657cbf9bSIvan T. Ivanov 	struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
139*657cbf9bSIvan T. Ivanov 
140*657cbf9bSIvan T. Ivanov 	return pc->pctl_desc.npins;
141*657cbf9bSIvan T. Ivanov }
142*657cbf9bSIvan T. Ivanov 
143*657cbf9bSIvan T. Ivanov static const char *brcmstb_pctl_get_group_name(struct pinctrl_dev *pctldev,
144*657cbf9bSIvan T. Ivanov 					       unsigned int selector)
145*657cbf9bSIvan T. Ivanov {
146*657cbf9bSIvan T. Ivanov 	struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
147*657cbf9bSIvan T. Ivanov 
148*657cbf9bSIvan T. Ivanov 	return pc->gpio_groups[selector];
149*657cbf9bSIvan T. Ivanov }
150*657cbf9bSIvan T. Ivanov 
151*657cbf9bSIvan T. Ivanov static int brcmstb_pctl_get_group_pins(struct pinctrl_dev *pctldev,
152*657cbf9bSIvan T. Ivanov 				       unsigned int selector,
153*657cbf9bSIvan T. Ivanov 				       const unsigned int **pins,
154*657cbf9bSIvan T. Ivanov 				       unsigned int *num_pins)
155*657cbf9bSIvan T. Ivanov {
156*657cbf9bSIvan T. Ivanov 	struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
157*657cbf9bSIvan T. Ivanov 
158*657cbf9bSIvan T. Ivanov 	*pins = &pc->pctl_desc.pins[selector].number;
159*657cbf9bSIvan T. Ivanov 	*num_pins = 1;
160*657cbf9bSIvan T. Ivanov 
161*657cbf9bSIvan T. Ivanov 	return 0;
162*657cbf9bSIvan T. Ivanov }
163*657cbf9bSIvan T. Ivanov 
164*657cbf9bSIvan T. Ivanov static void brcmstb_pctl_pin_dbg_show(struct pinctrl_dev *pctldev,
165*657cbf9bSIvan T. Ivanov 				      struct seq_file *s, unsigned int offset)
166*657cbf9bSIvan T. Ivanov {
167*657cbf9bSIvan T. Ivanov 	struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
168*657cbf9bSIvan T. Ivanov 	unsigned int fsel = brcmstb_pinctrl_fsel_get(pc, offset);
169*657cbf9bSIvan T. Ivanov 	const char *fname = pc->func_names[fsel];
170*657cbf9bSIvan T. Ivanov 
171*657cbf9bSIvan T. Ivanov 	seq_printf(s, "function %s", fname);
172*657cbf9bSIvan T. Ivanov }
173*657cbf9bSIvan T. Ivanov 
174*657cbf9bSIvan T. Ivanov static void brcmstb_pctl_dt_free_map(struct pinctrl_dev *pctldev,
175*657cbf9bSIvan T. Ivanov 				     struct pinctrl_map *maps,
176*657cbf9bSIvan T. Ivanov 				     unsigned int num_maps)
177*657cbf9bSIvan T. Ivanov {
178*657cbf9bSIvan T. Ivanov 	int i;
179*657cbf9bSIvan T. Ivanov 
180*657cbf9bSIvan T. Ivanov 	for (i = 0; i < num_maps; i++)
181*657cbf9bSIvan T. Ivanov 		if (maps[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
182*657cbf9bSIvan T. Ivanov 			kfree(maps[i].data.configs.configs);
183*657cbf9bSIvan T. Ivanov 
184*657cbf9bSIvan T. Ivanov 	kfree(maps);
185*657cbf9bSIvan T. Ivanov }
186*657cbf9bSIvan T. Ivanov 
187*657cbf9bSIvan T. Ivanov static const struct pinctrl_ops brcmstb_pctl_ops = {
188*657cbf9bSIvan T. Ivanov 	.get_groups_count = brcmstb_pctl_get_groups_count,
189*657cbf9bSIvan T. Ivanov 	.get_group_name = brcmstb_pctl_get_group_name,
190*657cbf9bSIvan T. Ivanov 	.get_group_pins = brcmstb_pctl_get_group_pins,
191*657cbf9bSIvan T. Ivanov 	.pin_dbg_show = brcmstb_pctl_pin_dbg_show,
192*657cbf9bSIvan T. Ivanov 	.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
193*657cbf9bSIvan T. Ivanov 	.dt_free_map = brcmstb_pctl_dt_free_map,
194*657cbf9bSIvan T. Ivanov };
195*657cbf9bSIvan T. Ivanov 
196*657cbf9bSIvan T. Ivanov static int brcmstb_pmx_free(struct pinctrl_dev *pctldev, unsigned int offset)
197*657cbf9bSIvan T. Ivanov {
198*657cbf9bSIvan T. Ivanov 	struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
199*657cbf9bSIvan T. Ivanov 
200*657cbf9bSIvan T. Ivanov 	/* disable by setting to GPIO */
201*657cbf9bSIvan T. Ivanov 	return brcmstb_pinctrl_fsel_set(pc, offset, pc->func_gpio);
202*657cbf9bSIvan T. Ivanov }
203*657cbf9bSIvan T. Ivanov 
204*657cbf9bSIvan T. Ivanov static int brcmstb_pmx_get_functions_count(struct pinctrl_dev *pctldev)
205*657cbf9bSIvan T. Ivanov {
206*657cbf9bSIvan T. Ivanov 	struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
207*657cbf9bSIvan T. Ivanov 
208*657cbf9bSIvan T. Ivanov 	return pc->func_count;
209*657cbf9bSIvan T. Ivanov }
210*657cbf9bSIvan T. Ivanov 
211*657cbf9bSIvan T. Ivanov static const char *brcmstb_pmx_get_function_name(struct pinctrl_dev *pctldev,
212*657cbf9bSIvan T. Ivanov 						 unsigned int selector)
213*657cbf9bSIvan T. Ivanov {
214*657cbf9bSIvan T. Ivanov 	struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
215*657cbf9bSIvan T. Ivanov 
216*657cbf9bSIvan T. Ivanov 	return (selector < pc->func_count) ? pc->func_names[selector] : NULL;
217*657cbf9bSIvan T. Ivanov }
218*657cbf9bSIvan T. Ivanov 
219*657cbf9bSIvan T. Ivanov static int brcmstb_pmx_get_function_groups(struct pinctrl_dev *pctldev,
220*657cbf9bSIvan T. Ivanov 					   unsigned int selector,
221*657cbf9bSIvan T. Ivanov 					   const char *const **groups,
222*657cbf9bSIvan T. Ivanov 					   unsigned *const num_groups)
223*657cbf9bSIvan T. Ivanov {
224*657cbf9bSIvan T. Ivanov 	struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
225*657cbf9bSIvan T. Ivanov 
226*657cbf9bSIvan T. Ivanov 	*groups = pc->gpio_groups;
227*657cbf9bSIvan T. Ivanov 	*num_groups = pc->pctl_desc.npins;
228*657cbf9bSIvan T. Ivanov 
229*657cbf9bSIvan T. Ivanov 	return 0;
230*657cbf9bSIvan T. Ivanov }
231*657cbf9bSIvan T. Ivanov 
232*657cbf9bSIvan T. Ivanov static int brcmstb_pmx_set(struct pinctrl_dev *pctldev,
233*657cbf9bSIvan T. Ivanov 			   unsigned int func_selector,
234*657cbf9bSIvan T. Ivanov 			   unsigned int group_selector)
235*657cbf9bSIvan T. Ivanov {
236*657cbf9bSIvan T. Ivanov 	struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
237*657cbf9bSIvan T. Ivanov 	const struct pinctrl_desc *pctldesc = &pc->pctl_desc;
238*657cbf9bSIvan T. Ivanov 	const struct pinctrl_pin_desc *pindesc;
239*657cbf9bSIvan T. Ivanov 
240*657cbf9bSIvan T. Ivanov 	if (group_selector >= pctldesc->npins)
241*657cbf9bSIvan T. Ivanov 		return -EINVAL;
242*657cbf9bSIvan T. Ivanov 
243*657cbf9bSIvan T. Ivanov 	pindesc = &pctldesc->pins[group_selector];
244*657cbf9bSIvan T. Ivanov 	return brcmstb_pinctrl_fsel_set(pc, pindesc->number, func_selector);
245*657cbf9bSIvan T. Ivanov }
246*657cbf9bSIvan T. Ivanov 
247*657cbf9bSIvan T. Ivanov static int brcmstb_pmx_gpio_request_enable(struct pinctrl_dev *pctldev,
248*657cbf9bSIvan T. Ivanov 					   struct pinctrl_gpio_range *range,
249*657cbf9bSIvan T. Ivanov 					   unsigned int pin)
250*657cbf9bSIvan T. Ivanov {
251*657cbf9bSIvan T. Ivanov 	struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
252*657cbf9bSIvan T. Ivanov 
253*657cbf9bSIvan T. Ivanov 	return brcmstb_pinctrl_fsel_set(pc, pin, pc->func_gpio);
254*657cbf9bSIvan T. Ivanov }
255*657cbf9bSIvan T. Ivanov 
256*657cbf9bSIvan T. Ivanov static void brcmstb_pmx_gpio_disable_free(struct pinctrl_dev *pctldev,
257*657cbf9bSIvan T. Ivanov 					  struct pinctrl_gpio_range *range,
258*657cbf9bSIvan T. Ivanov 					  unsigned int offset)
259*657cbf9bSIvan T. Ivanov {
260*657cbf9bSIvan T. Ivanov 	struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
261*657cbf9bSIvan T. Ivanov 
262*657cbf9bSIvan T. Ivanov 	/* disable by setting to GPIO */
263*657cbf9bSIvan T. Ivanov 	(void)brcmstb_pinctrl_fsel_set(pc, offset, pc->func_gpio);
264*657cbf9bSIvan T. Ivanov }
265*657cbf9bSIvan T. Ivanov 
266*657cbf9bSIvan T. Ivanov static bool brcmstb_pmx_function_is_gpio(struct pinctrl_dev *pctldev,
267*657cbf9bSIvan T. Ivanov 					 unsigned int selector)
268*657cbf9bSIvan T. Ivanov {
269*657cbf9bSIvan T. Ivanov 	struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
270*657cbf9bSIvan T. Ivanov 
271*657cbf9bSIvan T. Ivanov 	return pc->func_gpio == selector;
272*657cbf9bSIvan T. Ivanov }
273*657cbf9bSIvan T. Ivanov 
274*657cbf9bSIvan T. Ivanov static const struct pinmux_ops brcmstb_pmx_ops = {
275*657cbf9bSIvan T. Ivanov 	.free = brcmstb_pmx_free,
276*657cbf9bSIvan T. Ivanov 	.get_functions_count = brcmstb_pmx_get_functions_count,
277*657cbf9bSIvan T. Ivanov 	.get_function_name = brcmstb_pmx_get_function_name,
278*657cbf9bSIvan T. Ivanov 	.get_function_groups = brcmstb_pmx_get_function_groups,
279*657cbf9bSIvan T. Ivanov 	.set_mux = brcmstb_pmx_set,
280*657cbf9bSIvan T. Ivanov 	.gpio_request_enable = brcmstb_pmx_gpio_request_enable,
281*657cbf9bSIvan T. Ivanov 	.gpio_disable_free = brcmstb_pmx_gpio_disable_free,
282*657cbf9bSIvan T. Ivanov 	.function_is_gpio = brcmstb_pmx_function_is_gpio,
283*657cbf9bSIvan T. Ivanov 	.strict = true,
284*657cbf9bSIvan T. Ivanov };
285*657cbf9bSIvan T. Ivanov 
286*657cbf9bSIvan T. Ivanov static unsigned int brcmstb_pull_config_get(struct brcmstb_pinctrl *pc,
287*657cbf9bSIvan T. Ivanov 					    unsigned int pin)
288*657cbf9bSIvan T. Ivanov {
289*657cbf9bSIvan T. Ivanov 	u32 bit = pc->pin_regs[pin].pad_bit, val;
290*657cbf9bSIvan T. Ivanov 
291*657cbf9bSIvan T. Ivanov 	if (bit == PAD_BIT_INVALID)
292*657cbf9bSIvan T. Ivanov 		return BRCMSTB_PULL_NONE;
293*657cbf9bSIvan T. Ivanov 
294*657cbf9bSIvan T. Ivanov 	val = readl(pc->base + BIT_TO_REG(bit));
295*657cbf9bSIvan T. Ivanov 	return (val >> BIT_TO_SHIFT(bit)) & BRCMSTB_PULL_MASK;
296*657cbf9bSIvan T. Ivanov }
297*657cbf9bSIvan T. Ivanov 
298*657cbf9bSIvan T. Ivanov static int brcmstb_pull_config_set(struct brcmstb_pinctrl *pc,
299*657cbf9bSIvan T. Ivanov 				   unsigned int pin, unsigned int arg)
300*657cbf9bSIvan T. Ivanov {
301*657cbf9bSIvan T. Ivanov 	u32 bit = pc->pin_regs[pin].pad_bit, val;
302*657cbf9bSIvan T. Ivanov 
303*657cbf9bSIvan T. Ivanov 	if (bit == PAD_BIT_INVALID) {
304*657cbf9bSIvan T. Ivanov 		dev_warn(pc->dev, "Can't set pulls for %s\n",
305*657cbf9bSIvan T. Ivanov 			 pc->gpio_groups[pin]);
306*657cbf9bSIvan T. Ivanov 		return -EINVAL;
307*657cbf9bSIvan T. Ivanov 	}
308*657cbf9bSIvan T. Ivanov 
309*657cbf9bSIvan T. Ivanov 	guard(spinlock_irqsave)(&pc->fsel_lock);
310*657cbf9bSIvan T. Ivanov 
311*657cbf9bSIvan T. Ivanov 	val = readl(pc->base + BIT_TO_REG(bit));
312*657cbf9bSIvan T. Ivanov 	val &= ~(BRCMSTB_PULL_MASK << BIT_TO_SHIFT(bit));
313*657cbf9bSIvan T. Ivanov 	val |= (arg << BIT_TO_SHIFT(bit));
314*657cbf9bSIvan T. Ivanov 	writel(val, pc->base + BIT_TO_REG(bit));
315*657cbf9bSIvan T. Ivanov 
316*657cbf9bSIvan T. Ivanov 	return 0;
317*657cbf9bSIvan T. Ivanov }
318*657cbf9bSIvan T. Ivanov 
319*657cbf9bSIvan T. Ivanov static int brcmstb_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
320*657cbf9bSIvan T. Ivanov 			       unsigned long *config)
321*657cbf9bSIvan T. Ivanov {
322*657cbf9bSIvan T. Ivanov 	struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
323*657cbf9bSIvan T. Ivanov 	enum pin_config_param param = pinconf_to_config_param(*config);
324*657cbf9bSIvan T. Ivanov 	u32 arg;
325*657cbf9bSIvan T. Ivanov 
326*657cbf9bSIvan T. Ivanov 	switch (param) {
327*657cbf9bSIvan T. Ivanov 	case PIN_CONFIG_BIAS_DISABLE:
328*657cbf9bSIvan T. Ivanov 		arg = (brcmstb_pull_config_get(pc, pin) == BRCMSTB_PULL_NONE);
329*657cbf9bSIvan T. Ivanov 		break;
330*657cbf9bSIvan T. Ivanov 	case PIN_CONFIG_BIAS_PULL_DOWN:
331*657cbf9bSIvan T. Ivanov 		arg = (brcmstb_pull_config_get(pc, pin) == BRCMSTB_PULL_DOWN);
332*657cbf9bSIvan T. Ivanov 		break;
333*657cbf9bSIvan T. Ivanov 	case PIN_CONFIG_BIAS_PULL_UP:
334*657cbf9bSIvan T. Ivanov 		arg = (brcmstb_pull_config_get(pc, pin) == BRCMSTB_PULL_UP);
335*657cbf9bSIvan T. Ivanov 		break;
336*657cbf9bSIvan T. Ivanov 	default:
337*657cbf9bSIvan T. Ivanov 		return -ENOTSUPP;
338*657cbf9bSIvan T. Ivanov 	}
339*657cbf9bSIvan T. Ivanov 
340*657cbf9bSIvan T. Ivanov 	*config = pinconf_to_config_packed(param, arg);
341*657cbf9bSIvan T. Ivanov 
342*657cbf9bSIvan T. Ivanov 	return 0;
343*657cbf9bSIvan T. Ivanov }
344*657cbf9bSIvan T. Ivanov 
345*657cbf9bSIvan T. Ivanov static int brcmstb_pinconf_set(struct pinctrl_dev *pctldev,
346*657cbf9bSIvan T. Ivanov 			       unsigned int pin, unsigned long *configs,
347*657cbf9bSIvan T. Ivanov 			       unsigned int num_configs)
348*657cbf9bSIvan T. Ivanov {
349*657cbf9bSIvan T. Ivanov 	struct brcmstb_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
350*657cbf9bSIvan T. Ivanov 	int ret = 0;
351*657cbf9bSIvan T. Ivanov 	u32 param;
352*657cbf9bSIvan T. Ivanov 	int i;
353*657cbf9bSIvan T. Ivanov 
354*657cbf9bSIvan T. Ivanov 	for (i = 0; i < num_configs; i++) {
355*657cbf9bSIvan T. Ivanov 		param = pinconf_to_config_param(configs[i]);
356*657cbf9bSIvan T. Ivanov 
357*657cbf9bSIvan T. Ivanov 		switch (param) {
358*657cbf9bSIvan T. Ivanov 		case PIN_CONFIG_BIAS_DISABLE:
359*657cbf9bSIvan T. Ivanov 			ret = brcmstb_pull_config_set(pc, pin, BRCMSTB_PULL_NONE);
360*657cbf9bSIvan T. Ivanov 			break;
361*657cbf9bSIvan T. Ivanov 		case PIN_CONFIG_BIAS_PULL_DOWN:
362*657cbf9bSIvan T. Ivanov 			ret = brcmstb_pull_config_set(pc, pin, BRCMSTB_PULL_DOWN);
363*657cbf9bSIvan T. Ivanov 			break;
364*657cbf9bSIvan T. Ivanov 		case PIN_CONFIG_BIAS_PULL_UP:
365*657cbf9bSIvan T. Ivanov 			ret = brcmstb_pull_config_set(pc, pin, BRCMSTB_PULL_UP);
366*657cbf9bSIvan T. Ivanov 			break;
367*657cbf9bSIvan T. Ivanov 		default:
368*657cbf9bSIvan T. Ivanov 			return -ENOTSUPP;
369*657cbf9bSIvan T. Ivanov 		}
370*657cbf9bSIvan T. Ivanov 	}
371*657cbf9bSIvan T. Ivanov 
372*657cbf9bSIvan T. Ivanov 	return ret;
373*657cbf9bSIvan T. Ivanov }
374*657cbf9bSIvan T. Ivanov 
375*657cbf9bSIvan T. Ivanov static const struct pinconf_ops brcmstb_pinconf_ops = {
376*657cbf9bSIvan T. Ivanov 	.is_generic = true,
377*657cbf9bSIvan T. Ivanov 	.pin_config_get = brcmstb_pinconf_get,
378*657cbf9bSIvan T. Ivanov 	.pin_config_set = brcmstb_pinconf_set,
379*657cbf9bSIvan T. Ivanov };
380*657cbf9bSIvan T. Ivanov 
381*657cbf9bSIvan T. Ivanov int brcmstb_pinctrl_probe(struct platform_device *pdev)
382*657cbf9bSIvan T. Ivanov {
383*657cbf9bSIvan T. Ivanov 	struct device *dev = &pdev->dev;
384*657cbf9bSIvan T. Ivanov 	struct device_node *np = dev->of_node;
385*657cbf9bSIvan T. Ivanov 	const struct brcmstb_pdata *pdata;
386*657cbf9bSIvan T. Ivanov 	struct brcmstb_pinctrl *pc;
387*657cbf9bSIvan T. Ivanov 	const char **names;
388*657cbf9bSIvan T. Ivanov 	int num_pins, i;
389*657cbf9bSIvan T. Ivanov 
390*657cbf9bSIvan T. Ivanov 	pdata = of_device_get_match_data(dev);
391*657cbf9bSIvan T. Ivanov 
392*657cbf9bSIvan T. Ivanov 	pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
393*657cbf9bSIvan T. Ivanov 	if (!pc)
394*657cbf9bSIvan T. Ivanov 		return -ENOMEM;
395*657cbf9bSIvan T. Ivanov 
396*657cbf9bSIvan T. Ivanov 	platform_set_drvdata(pdev, pc);
397*657cbf9bSIvan T. Ivanov 	pc->dev = dev;
398*657cbf9bSIvan T. Ivanov 	spin_lock_init(&pc->fsel_lock);
399*657cbf9bSIvan T. Ivanov 
400*657cbf9bSIvan T. Ivanov 	pc->base = devm_of_iomap(dev, np, 0, NULL);
401*657cbf9bSIvan T. Ivanov 	if (IS_ERR(pc->base))
402*657cbf9bSIvan T. Ivanov 		return dev_err_probe(&pdev->dev, PTR_ERR(pc->base),
403*657cbf9bSIvan T. Ivanov 				     "Could not get IO memory\n");
404*657cbf9bSIvan T. Ivanov 
405*657cbf9bSIvan T. Ivanov 	pc->pctl_desc = *pdata->pctl_desc;
406*657cbf9bSIvan T. Ivanov 	pc->pctl_desc.pctlops = &brcmstb_pctl_ops;
407*657cbf9bSIvan T. Ivanov 	pc->pctl_desc.pmxops = &brcmstb_pmx_ops;
408*657cbf9bSIvan T. Ivanov 	pc->pctl_desc.confops = &brcmstb_pinconf_ops;
409*657cbf9bSIvan T. Ivanov 	pc->pctl_desc.owner = THIS_MODULE;
410*657cbf9bSIvan T. Ivanov 	num_pins = pc->pctl_desc.npins;
411*657cbf9bSIvan T. Ivanov 	names = devm_kmalloc_array(dev, num_pins, sizeof(const char *),
412*657cbf9bSIvan T. Ivanov 				   GFP_KERNEL);
413*657cbf9bSIvan T. Ivanov 	if (!names)
414*657cbf9bSIvan T. Ivanov 		return -ENOMEM;
415*657cbf9bSIvan T. Ivanov 
416*657cbf9bSIvan T. Ivanov 	for (i = 0; i < num_pins; i++)
417*657cbf9bSIvan T. Ivanov 		names[i] = pc->pctl_desc.pins[i].name;
418*657cbf9bSIvan T. Ivanov 
419*657cbf9bSIvan T. Ivanov 	pc->gpio_groups = names;
420*657cbf9bSIvan T. Ivanov 	pc->pin_regs = pdata->pin_regs;
421*657cbf9bSIvan T. Ivanov 	pc->pin_funcs = pdata->pin_funcs;
422*657cbf9bSIvan T. Ivanov 	pc->func_count = pdata->func_count;
423*657cbf9bSIvan T. Ivanov 	pc->func_names = pdata->func_names;
424*657cbf9bSIvan T. Ivanov 
425*657cbf9bSIvan T. Ivanov 	pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc);
426*657cbf9bSIvan T. Ivanov 	if (IS_ERR(pc->pctl_dev))
427*657cbf9bSIvan T. Ivanov 		return dev_err_probe(&pdev->dev, PTR_ERR(pc->pctl_dev),
428*657cbf9bSIvan T. Ivanov 				     "Failed to register pinctrl device\n");
429*657cbf9bSIvan T. Ivanov 
430*657cbf9bSIvan T. Ivanov 	pc->gpio_range = *pdata->gpio_range;
431*657cbf9bSIvan T. Ivanov 	pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
432*657cbf9bSIvan T. Ivanov 
433*657cbf9bSIvan T. Ivanov 	return 0;
434*657cbf9bSIvan T. Ivanov }
435*657cbf9bSIvan T. Ivanov EXPORT_SYMBOL(brcmstb_pinctrl_probe);
436*657cbf9bSIvan T. Ivanov 
437*657cbf9bSIvan T. Ivanov MODULE_AUTHOR("Phil Elwell");
438*657cbf9bSIvan T. Ivanov MODULE_AUTHOR("Jonathan Bell");
439*657cbf9bSIvan T. Ivanov MODULE_AUTHOR("Ivan T. Ivanov");
440*657cbf9bSIvan T. Ivanov MODULE_AUTHOR("Andrea della Porta");
441*657cbf9bSIvan T. Ivanov MODULE_DESCRIPTION("Broadcom brcmstb pinctrl driver");
442*657cbf9bSIvan T. Ivanov MODULE_LICENSE("GPL");
443