xref: /netbsd-src/sys/dev/ic/mcp23xxxgpio.c (revision 6690c9f22f3caebb101ec0e4aec2b09ee28fa80f)
1 /*      $NetBSD: mcp23xxxgpio.c,v 1.2 2022/01/17 19:38:14 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 2014, 2022 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Frank Kardel, and by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mcp23xxxgpio.c,v 1.2 2022/01/17 19:38:14 thorpej Exp $");
34 
35 /*
36  * Driver for Microchip serial I/O expansers:
37  *
38  *	MCP23008	8-bit, I2C interface
39  *	MCP23S08	8-bit, SPI interface
40  *	MCP23017	16-bit, I2C interface
41  *	MCP23S17	16-bit, SPI interface
42  *	MCP23018	16-bit (open-drain outputs), I2C interface
43  *	MCP23S18	16-bit (open-drain outputs), SPI interface
44  *
45  * Data sheet:
46  *
47  *	https://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf
48  */
49 
50 #include "gpio.h"
51 
52 #include <sys/types.h>
53 #include <sys/systm.h>
54 #include <sys/device.h>
55 #include <sys/kernel.h>
56 #include <sys/kmem.h>
57 
58 #include <dev/ic/mcp23xxxgpioreg.h>
59 #include <dev/ic/mcp23xxxgpiovar.h>
60 
61 #define	PIN_BANK(p)	((p) / MCPGPIO_PINS_PER_BANK)
62 #define	PIN_EPIN(p)	((p) % MCPGPIO_PINS_PER_BANK)
63 
64 static uint8_t
mcpgpio_regaddr(struct mcpgpio_softc * sc,uint8_t bank,uint8_t reg)65 mcpgpio_regaddr(struct mcpgpio_softc *sc, uint8_t bank, uint8_t reg)
66 {
67 
68 	if (sc->sc_variant->type == MCPGPIO_TYPE_23x08) {
69 		return reg;
70 	}
71 	if (sc->sc_iocon & IOCON_BANK) {
72 		return REGADDR_BANK1(bank & 1, reg);
73 	}
74 	return REGADDR_BANK0(bank & 1, reg);
75 }
76 
77 static const char *
mcpgpio_regname(uint8_t reg)78 mcpgpio_regname(uint8_t reg)
79 {
80 	static const char * const regnames[] = {
81 		[REG_IODIR]	=	"IODIR",
82 		[REG_IPOL]	=	"IPOL",
83 		[REG_GPINTEN]	=	"GPINTEN",
84 		[REG_DEFVAL]	=	"DEFVAL",
85 		[REG_INTCON]	=	"INTCON",
86 		[REG_IOCON]	=	"IOCON",
87 		[REG_GPPU]	=	"GPPU",
88 		[REG_INTF]	=	"INTF",
89 		[REG_INTCAP]	=	"INTCAP",
90 		[REG_GPIO]	=	"GPIO",
91 		[REG_OLAT]	=	"OLAT",
92 	};
93 	KASSERT(reg <= REG_OLAT);
94 	return regnames[reg];
95 }
96 
97 static const char *
mcpgpio_bankname(struct mcpgpio_softc * sc,uint8_t bank)98 mcpgpio_bankname(struct mcpgpio_softc *sc, uint8_t bank)
99 {
100 	static const char * const banknames[] = { "A", "B" };
101 
102 	if (sc->sc_variant->type == MCPGPIO_TYPE_23x08) {
103 		return "";
104 	}
105 	return banknames[bank & 1];
106 }
107 
108 static int
mcpgpio__lock(struct mcpgpio_softc * sc,const char * fn)109 mcpgpio__lock(struct mcpgpio_softc *sc, const char *fn)
110 {
111 	int error;
112 
113 	error = sc->sc_accessops->lock(sc);
114 	if (__predict_false(error != 0)) {
115 		aprint_error_dev(sc->sc_dev,
116 		    "%s: unable to lock device, error=%d\n", fn, error);
117 	}
118 	return error;
119 }
120 
121 #define	mcpgpio_lock(sc)						\
122 	mcpgpio__lock((sc), __func__)
123 
124 static void
mcpgpio_unlock(struct mcpgpio_softc * sc)125 mcpgpio_unlock(struct mcpgpio_softc *sc)
126 {
127 	sc->sc_accessops->unlock(sc);
128 }
129 
130 static int
mcpgpio__read(struct mcpgpio_softc * sc,const char * fn,uint8_t bank,uint8_t reg,uint8_t * valp)131 mcpgpio__read(struct mcpgpio_softc *sc, const char *fn,
132     uint8_t bank, uint8_t reg, uint8_t *valp)
133 {
134 	int error;
135 	uint8_t regaddr = mcpgpio_regaddr(sc, bank, reg);
136 
137 	error = sc->sc_accessops->read(sc, bank, regaddr, valp);
138 	if (__predict_false(error != 0)) {
139 		aprint_error_dev(sc->sc_dev,
140 		    "%s: unable to read %s%s[0x%02x], error=%d\n", fn,
141 		    mcpgpio_regname(reg), mcpgpio_bankname(sc, bank),
142 		    regaddr, error);
143 	}
144 	return error;
145 }
146 
147 #define	mcpgpio_read(sc, b, r, v)					\
148 	mcpgpio__read((sc), __func__, (b), (r), (v))
149 
150 static int
mcpgpio__write(struct mcpgpio_softc * sc,const char * fn,uint8_t bank,uint8_t reg,uint8_t val)151 mcpgpio__write(struct mcpgpio_softc *sc, const char *fn,
152     uint8_t bank, uint8_t reg, uint8_t val)
153 {
154 	int error;
155 	uint8_t regaddr = mcpgpio_regaddr(sc, bank, reg);
156 
157 	error = sc->sc_accessops->write(sc, bank, regaddr, val);
158 	if (__predict_false(error != 0)) {
159 		aprint_error_dev(sc->sc_dev,
160 		    "%s: unable to write %s%s[0x%02x], error=%d\n", fn,
161 		    mcpgpio_regname(reg), mcpgpio_bankname(sc, bank),
162 		    regaddr, error);
163 	}
164 	return error;
165 }
166 
167 #define	mcpgpio_write(sc, b, r, v)					\
168 	mcpgpio__write((sc), __func__, (b), (r), (v))
169 
170 #if NGPIO > 0
171 /* GPIO support functions */
172 static int
mcpgpio_gpio_pin_read(void * arg,int pin)173 mcpgpio_gpio_pin_read(void *arg, int pin)
174 {
175 	struct mcpgpio_softc *sc = arg;
176 	uint8_t data;
177 	int val;
178 	int error;
179 
180 	KASSERT(pin >= 0 && pin < sc->sc_npins);
181 
182 	const uint8_t bank = PIN_BANK(pin);
183 	const uint8_t epin = PIN_EPIN(pin);
184 
185 	error = mcpgpio_lock(sc);
186 	if (__predict_false(error != 0)) {
187 		return GPIO_PIN_LOW;
188 	}
189 	error = mcpgpio_read(sc, bank, REG_GPIO, &data);
190 	if (error) {
191 		data = 0;
192 	}
193 	mcpgpio_unlock(sc);
194 
195 	val = data & __BIT(epin) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
196 
197 	return val;
198 }
199 
200 static void
mcpgpio_gpio_pin_write(void * arg,int pin,int value)201 mcpgpio_gpio_pin_write(void *arg, int pin, int value)
202 {
203 	struct mcpgpio_softc *sc = arg;
204 	uint8_t data;
205 	int error;
206 
207 	KASSERT(pin >= 0 && pin < sc->sc_npins);
208 
209 	const uint8_t bank = PIN_BANK(pin);
210 	const uint8_t epin = PIN_EPIN(pin);
211 
212 	error = mcpgpio_lock(sc);
213 	if (__predict_false(error != 0)) {
214 		return;
215 	}
216 
217 	error = mcpgpio_read(sc, bank, REG_OLAT, &data);
218 	if (__predict_true(error == 0)) {
219 		if (value == GPIO_PIN_HIGH) {
220 			data |= __BIT(epin);
221 		} else {
222 			data &= ~__BIT(epin);
223 		}
224 		(void) mcpgpio_write(sc, bank, REG_OLAT, data);
225 	}
226 
227 	mcpgpio_unlock(sc);
228 }
229 
230 static void
mcpgpio_gpio_pin_ctl(void * arg,int pin,int flags)231 mcpgpio_gpio_pin_ctl(void *arg, int pin, int flags)
232 {
233 	struct mcpgpio_softc *sc = arg;
234 	uint8_t iodir, ipol, gppu;
235 	int error;
236 
237 	KASSERT(pin >= 0 && pin < sc->sc_npins);
238 
239 	const uint8_t bank = PIN_BANK(pin);
240 	const uint8_t epin = PIN_EPIN(pin);
241 	const uint8_t bit = __BIT(epin);
242 
243 	error = mcpgpio_lock(sc);
244 	if (__predict_false(error != 0)) {
245 		return;
246 	}
247 
248 	if ((error = mcpgpio_read(sc, bank, REG_IODIR, &iodir)) != 0 ||
249 	    (error = mcpgpio_read(sc, bank, REG_IPOL, &ipol)) != 0 ||
250 	    (error = mcpgpio_read(sc, bank, REG_GPPU, &gppu)) != 0) {
251 		return;
252 	}
253 
254 	if (flags & (GPIO_PIN_OUTPUT|GPIO_PIN_INPUT)) {
255 		if ((flags & GPIO_PIN_INPUT) || !(flags & GPIO_PIN_OUTPUT)) {
256 			/* for safety INPUT will override output */
257 			iodir |= bit;
258 		} else {
259 			iodir &= ~bit;
260 		}
261 	}
262 
263 	if (flags & GPIO_PIN_INVIN) {
264 		ipol |= bit;
265 	} else {
266 		ipol &= ~bit;
267 	}
268 
269 	if (flags & GPIO_PIN_PULLUP) {
270 		gppu |= bit;
271 	} else {
272 		gppu &= ~bit;
273 	}
274 
275 	(void) mcpgpio_write(sc, bank, REG_IODIR, iodir);
276 	(void) mcpgpio_write(sc, bank, REG_IPOL, ipol);
277 	(void) mcpgpio_write(sc, bank, REG_GPPU, gppu);
278 
279 	mcpgpio_unlock(sc);
280 }
281 #endif /* NGPIO > 0 */
282 
283 void
mcpgpio_attach(struct mcpgpio_softc * sc)284 mcpgpio_attach(struct mcpgpio_softc *sc)
285 {
286 	int error;
287 
288 	KASSERT(sc->sc_variant != NULL);
289 
290 	/*
291 	 * The SPI front-end provides the logical pin count to
292 	 * deal with muliple chips on one chip select.
293 	 */
294 	if (sc->sc_npins == 0) {
295 		sc->sc_npins = sc->sc_variant->type == MCPGPIO_TYPE_23x08
296 		    ? MCP23x08_GPIO_NPINS : MCP23x17_GPIO_NPINS;
297 	}
298 	sc->sc_gpio_pins =
299 	    kmem_zalloc(sc->sc_npins * sizeof(*sc->sc_gpio_pins), KM_SLEEP);
300 
301 	/*
302 	 * Perform the basic setup of the device.  We program the IOCON
303 	 * register once for each bank, even though the data sheet is
304 	 * not clear that this is strictly necessary.
305 	 */
306 	if (mcpgpio_lock(sc) != 0) {
307 		return;
308 	}
309 	error = mcpgpio_write(sc, 0, REG_IOCON, sc->sc_iocon);
310 	if (error == 0 && sc->sc_variant->type != MCPGPIO_TYPE_23x08) {
311 		error = mcpgpio_write(sc, 1, REG_IOCON, sc->sc_iocon);
312 	}
313 	mcpgpio_unlock(sc);
314 	if (error) {
315 		return;
316 	}
317 
318 	/* XXX FDT glue. */
319 
320 #if NGPIO > 0
321 	struct gpiobus_attach_args gba;
322 	int pin_output_caps;
323 	int i;
324 
325 	pin_output_caps = sc->sc_variant->type == MCPGPIO_TYPE_23x18
326 	    ? GPIO_PIN_OPENDRAIN : GPIO_PIN_PUSHPULL;
327 
328 	for (i = 0; i < sc->sc_npins; i++) {
329 		sc->sc_gpio_pins[i].pin_num = i;
330 		sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT |
331 			GPIO_PIN_OUTPUT |
332 			pin_output_caps |
333 			GPIO_PIN_PULLUP |
334 			GPIO_PIN_INVIN;
335 
336 		/* read initial state */
337 		sc->sc_gpio_pins[i].pin_state =
338 			mcpgpio_gpio_pin_read(sc, i);
339 	}
340 
341 	/* create controller tag */
342 	sc->sc_gpio_gc.gp_cookie = sc;
343 	sc->sc_gpio_gc.gp_pin_read = mcpgpio_gpio_pin_read;
344 	sc->sc_gpio_gc.gp_pin_write = mcpgpio_gpio_pin_write;
345 	sc->sc_gpio_gc.gp_pin_ctl = mcpgpio_gpio_pin_ctl;
346 
347 	gba.gba_gc = &sc->sc_gpio_gc;
348 	gba.gba_pins = sc->sc_gpio_pins;
349 	gba.gba_npins = sc->sc_npins;
350 
351 	config_found(sc->sc_dev, &gba, gpiobus_print,
352 	    CFARGS(.devhandle = device_handle(sc->sc_dev)));
353 #else
354 	aprint_normal_dev(sc->sc_dev, "no GPIO configured in kernel");
355 #endif
356 }
357