xref: /netbsd/sys/arch/arm/apple/apple_pinctrl.c (revision ddc177cf)
1 /*	$NetBSD: apple_pinctrl.c,v 1.1 2022/04/27 07:59:18 skrll Exp $	*/
2 /*	$OpenBSD: aplpinctrl.c,v 1.4 2022/04/06 18:59:26 naddy Exp $	*/
3 
4 /*-
5  * Copyright (c) 2022 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Nick Hudson
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
35  *
36  * Permission to use, copy, modify, and distribute this software for any
37  * purpose with or without fee is hereby granted, provided that the above
38  * copyright notice and this permission notice appear in all copies.
39  *
40  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
41  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
42  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
43  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
44  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
45  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
46  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
47  */
48 
49 #include <sys/cdefs.h>
50 __KERNEL_RCSID(0, "$NetBSD: apple_pinctrl.c,v 1.1 2022/04/27 07:59:18 skrll Exp $");
51 
52 #include <sys/param.h>
53 #include <sys/bus.h>
54 #include <sys/device.h>
55 #include <sys/kmem.h>
56 
57 #include <dev/fdt/fdtvar.h>
58 
59 #include <arm/pic/picvar.h>
60 
61 #define APPLE_PIN(pinmux)	__SHIFTOUT((pinmux), __BITS(15, 0))
62 #define APPLE_FUNC(pinmux)	__SHIFTOUT((pinmux), __BITS(31, 16))
63 
64 #define GPIO_PIN(pin)		((pin) * 4)
65 #define  GPIO_PIN_GROUP_MASK	__BITS(18, 16)
66 #define  GPIO_PIN_INPUT_ENABLE	__BIT(9)
67 #define  GPIO_PIN_FUNC_MASK	__BITS(6, 5)
68 #define  GPIO_PIN_MODE_MASK	__BITS(3, 1)
69 #define  GPIO_PIN_MODE_INPUT	 __SHIFTIN(0, GPIO_PIN_MODE_MASK);
70 #define  GPIO_PIN_MODE_OUTPUT	 __SHIFTIN(1, GPIO_PIN_MODE_MASK);
71 #define  GPIO_PIN_MODE_IRQ_HI	 __SHIFTIN(2, GPIO_PIN_MODE_MASK);
72 #define  GPIO_PIN_MODE_IRQ_LO	 __SHIFTIN(3, GPIO_PIN_MODE_MASK);
73 #define  GPIO_PIN_MODE_IRQ_UP	 __SHIFTIN(4, GPIO_PIN_MODE_MASK);
74 #define  GPIO_PIN_MODE_IRQ_DN	 __SHIFTIN(5, GPIO_PIN_MODE_MASK);
75 #define  GPIO_PIN_MODE_IRQ_ANY	 __SHIFTIN(6, GPIO_PIN_MODE_MASK);
76 #define  GPIO_PIN_MODE_IRQ_OFF	 __SHIFTIN(7, GPIO_PIN_MODE_MASK);
77 #define  GPIO_PIN_DATA		__BIT(0)
78 #define GPIO_IRQ(grp, pin)	(0x800 + (grp) * 64 + ((pin) >> 5) * 4)
79 
80 #define PINCTRL_READ(sc, reg)						\
81 	(bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)))
82 #define PINCTRL_WRITE(sc, reg, val)					\
83 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
84 #define PINCTRL_SET(sc, reg, bits)					\
85 	PINCTRL_WRITE((sc), (reg), PINCTRL_READ((sc), (reg)) | (bits))
86 #define PINCTRL_CLR(sc, reg, bits)					\
87 	PINCTRL_WRITE((sc), (reg), PINCTRL_READ((sc), (reg)) & ~(bits))
88 
89 
90 struct apple_pinctrl_softc {
91 	device_t sc_dev;
92 	int sc_phandle;
93 	bus_space_tag_t sc_bst;
94 	bus_space_handle_t sc_bsh;
95 	u_int sc_npins;
96 };
97 
98 struct apple_gpio_pin {
99 	int		pin_no;
100 	u_int		pin_flags;
101 	bool		pin_actlo;
102 };
103 
104 static const struct device_compatible_entry compat_data[] = {
105 	{ .compat = "apple,pinctrl" },
106 	DEVICE_COMPAT_EOL
107 };
108 
109 static void
apple_gpio_pin_ctl(void * cookie,int pin,int flags)110 apple_gpio_pin_ctl(void *cookie, int pin, int flags)
111 {
112 	struct apple_pinctrl_softc * const sc = cookie;
113 
114 	KASSERT(pin < sc->sc_npins);
115 
116 	uint32_t reg = PINCTRL_READ(sc, GPIO_PIN(pin));
117 	reg &= ~GPIO_PIN_FUNC_MASK;
118 	reg &= ~GPIO_PIN_MODE_MASK;
119 
120 	if (flags & (GPIO_PIN_OUTPUT | GPIO_PIN_INPUT)) {
121 		if (flags & GPIO_PIN_INPUT) {
122 			/* for safety INPUT will override output */
123 			reg |= GPIO_PIN_MODE_INPUT;
124 		} else {
125 			reg |= GPIO_PIN_MODE_OUTPUT;
126 		}
127 	}
128 	PINCTRL_WRITE(sc, GPIO_PIN(pin), reg);
129 }
130 
131 static void *
apple_pinctrl_gpio_acquire(device_t dev,const void * data,size_t len,int flags)132 apple_pinctrl_gpio_acquire(device_t dev, const void *data, size_t len, int flags)
133 {
134 	struct apple_pinctrl_softc * const sc = device_private(dev);
135 	struct apple_gpio_pin *pin;
136 	const u_int *gpio = data;
137 
138 	if (len != 12)
139 		return NULL;
140 
141 	const u_int pinno = be32toh(gpio[1]);
142 	const bool actlo = be32toh(gpio[2]) & 1;
143 
144 	if (pinno >= sc->sc_npins)
145 		return NULL;
146 
147 	pin = kmem_alloc(sizeof(*pin), KM_SLEEP);
148 	pin->pin_no = pinno;
149 	pin->pin_flags = flags;
150 	pin->pin_actlo = actlo;
151 
152 	apple_gpio_pin_ctl(sc, pin->pin_no, pin->pin_flags);
153 
154 	return pin;
155 }
156 
157 static void
apple_pinctrl_gpio_release(device_t dev,void * priv)158 apple_pinctrl_gpio_release(device_t dev, void *priv)
159 {
160 	struct apple_pinctrl_softc * const sc = device_private(dev);
161 	struct apple_gpio_pin *pin = priv;
162 
163 	apple_gpio_pin_ctl(sc, pin->pin_no, GPIO_PIN_INPUT);
164 	kmem_free(pin, sizeof(*pin));
165 }
166 
167 static int
apple_pinctrl_gpio_read(device_t dev,void * priv,bool raw)168 apple_pinctrl_gpio_read(device_t dev, void *priv, bool raw)
169 {
170 	struct apple_pinctrl_softc * const sc = device_private(dev);
171 	struct apple_gpio_pin *pin = priv;
172 
173 	KASSERT(pin->pin_no < sc->sc_npins);
174 
175 	uint32_t reg = PINCTRL_READ(sc, GPIO_PIN(pin->pin_no));
176 	int val = __SHIFTOUT(reg, GPIO_PIN_DATA);
177 	if (!raw && pin->pin_actlo)
178 		val = !val;
179 
180 	return val;
181 }
182 
183 static void
apple_pinctrl_gpio_write(device_t dev,void * priv,int val,bool raw)184 apple_pinctrl_gpio_write(device_t dev, void *priv, int val, bool raw)
185 {
186 	struct apple_pinctrl_softc * const sc = device_private(dev);
187 	struct apple_gpio_pin *pin = priv;
188 
189 	KASSERT(pin->pin_no < sc->sc_npins);
190 
191 	if (!raw && pin->pin_actlo)
192 		val = !val;
193 
194 	if (val)
195 		PINCTRL_SET(sc, GPIO_PIN(pin->pin_no), GPIO_PIN_DATA);
196 	else
197 		PINCTRL_CLR(sc, GPIO_PIN(pin->pin_no), GPIO_PIN_DATA);
198 }
199 
200 static int
apple_pinctrl_set_config(device_t dev,const void * data,size_t len)201 apple_pinctrl_set_config(device_t dev, const void *data, size_t len)
202 {
203 	struct apple_pinctrl_softc * const sc = device_private(dev);
204 
205 	if (len != 4)
206 		return -1;
207 
208 	int pins_len;
209 	const int phandle = fdtbus_get_phandle_from_native(be32dec(data));
210 	const u_int *pins = fdtbus_get_prop(phandle, "pinmux", &pins_len);
211 
212 	if (pins == NULL)
213 		return -1;
214 
215 	const u_int npins = pins_len / sizeof(uint32_t);
216 
217 	for (u_int i = 0; i < npins; i++) {
218 		uint32_t pinmux = be32dec(&pins[i]);
219 		u_int pinno = APPLE_PIN(pinmux);
220 		u_int func = APPLE_FUNC(pinmux);
221 
222 		uint32_t reg = PINCTRL_READ(sc, GPIO_PIN(pinno));
223 		reg &= ~GPIO_PIN_FUNC_MASK;
224 		reg |= __SHIFTIN(func, GPIO_PIN_FUNC_MASK);
225 
226 		PINCTRL_WRITE(sc, GPIO_PIN(pinno), reg);
227 	}
228 
229 	return 0;
230 }
231 
232 static struct fdtbus_gpio_controller_func apple_pinctrl_gpio_funcs = {
233 	.acquire = apple_pinctrl_gpio_acquire,
234 	.release = apple_pinctrl_gpio_release,
235 	.read = apple_pinctrl_gpio_read,
236 	.write = apple_pinctrl_gpio_write
237 };
238 
239 static struct fdtbus_pinctrl_controller_func apple_pinctrl_funcs = {
240 	.set_config = apple_pinctrl_set_config,
241 };
242 
243 static int
apple_pinctrl_match(device_t parent,cfdata_t cf,void * aux)244 apple_pinctrl_match(device_t parent, cfdata_t cf, void *aux)
245 {
246 	struct fdt_attach_args * const faa = aux;
247 
248 	return of_compatible_match(faa->faa_phandle, compat_data);
249 }
250 
251 static void
apple_pinctrl_attach(device_t parent,device_t self,void * aux)252 apple_pinctrl_attach(device_t parent, device_t self, void *aux)
253 {
254 	struct apple_pinctrl_softc * const sc = device_private(self);
255 	struct fdt_attach_args * const faa = aux;
256 	const int phandle = faa->faa_phandle;
257 	bus_addr_t addr;
258 	bus_size_t size;
259 
260 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
261 		aprint_error(": couldn't get registers\n");
262 		return;
263 	}
264 
265 	sc->sc_dev = self;
266 	sc->sc_bst = faa->faa_bst;
267 
268 	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
269 		aprint_error(": couldn't map registers\n");
270 		return;
271 	}
272 
273 	if (of_getprop_uint32(phandle, "apple,npins", &sc->sc_npins)) {
274 		aprint_error(": couldn't get number of pins\n");
275 		return;
276 	}
277 
278 	if (!of_hasprop(phandle, "gpio-controller")) {
279 		aprint_error(": no gpio controller");
280 		return;
281 	}
282 
283 	aprint_naive("\n");
284 	aprint_normal(": Apple Pinctrl\n");
285 
286 	fdtbus_register_gpio_controller(self, phandle, &apple_pinctrl_gpio_funcs);
287 
288 	for (int child = OF_child(phandle); child; child = OF_peer(child)) {
289 		if (!of_hasprop(child, "pinmux"))
290 			continue;
291 		fdtbus_register_pinctrl_config(self, child,
292 		    &apple_pinctrl_funcs);
293 
294 	}
295 }
296 
297 CFATTACH_DECL_NEW(apple_pinctrl, sizeof(struct apple_pinctrl_softc),
298     apple_pinctrl_match, apple_pinctrl_attach, NULL, NULL);
299 
300