xref: /openbsd-src/sys/dev/gpio/gpiosim.c (revision 471aeecfc619bc9b69519928152daf993376c2a1)
1*471aeecfSnaddy /*      $OpenBSD: gpiosim.c,v 1.2 2022/04/06 18:59:28 naddy Exp $	*/
2717eb34cSmbalmer 
3717eb34cSmbalmer /*
4717eb34cSmbalmer  * Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org>
5717eb34cSmbalmer  * All rights reserved.
6717eb34cSmbalmer  *
7717eb34cSmbalmer  * Permission to use, copy, modify, and distribute this software for any
8717eb34cSmbalmer  * purpose with or without fee is hereby granted, provided that the above
9717eb34cSmbalmer  * copyright notice and this permission notice appear in all copies.
10717eb34cSmbalmer  *
11717eb34cSmbalmer  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12717eb34cSmbalmer  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13717eb34cSmbalmer  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14717eb34cSmbalmer  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15717eb34cSmbalmer  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
16717eb34cSmbalmer  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17717eb34cSmbalmer  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18717eb34cSmbalmer  */
19717eb34cSmbalmer 
20717eb34cSmbalmer /* 32 bit wide GPIO simulator  */
21717eb34cSmbalmer #include <sys/param.h>
22717eb34cSmbalmer #include <sys/systm.h>
23717eb34cSmbalmer #include <sys/device.h>
24717eb34cSmbalmer #include <sys/gpio.h>
25717eb34cSmbalmer #include <sys/malloc.h>
26717eb34cSmbalmer #include <sys/sysctl.h>
27717eb34cSmbalmer #include <sys/ioccom.h>
28717eb34cSmbalmer 
29717eb34cSmbalmer #include <dev/gpio/gpiovar.h>
30717eb34cSmbalmer #include <dev/biovar.h>
31717eb34cSmbalmer 
32717eb34cSmbalmer #define	GPIOSIM_NPINS	32
33717eb34cSmbalmer 
34717eb34cSmbalmer struct gpiosim_softc {
35717eb34cSmbalmer 	struct device		sc_dev;
36717eb34cSmbalmer 	u_int32_t		sc_state;
37717eb34cSmbalmer 	struct gpio_chipset_tag	sc_gpio_gc;
38717eb34cSmbalmer 	gpio_pin_t		sc_gpio_pins[GPIOSIM_NPINS];
39717eb34cSmbalmer };
40717eb34cSmbalmer 
41717eb34cSmbalmer struct gpiosim_op {
42717eb34cSmbalmer 	void *cookie;
43717eb34cSmbalmer 	u_int32_t mask;
44717eb34cSmbalmer 	u_int32_t state;
45717eb34cSmbalmer };
46717eb34cSmbalmer #define GPIOSIMREAD	_IOWR('G', 0, struct gpiosim_op)
47717eb34cSmbalmer #define GPIOSIMWRITE	_IOW('G', 1, struct gpiosim_op)
48717eb34cSmbalmer 
49717eb34cSmbalmer int	gpiosim_match(struct device *, void *, void *);
50717eb34cSmbalmer void	gpiosim_attach(struct device *, struct device *, void *);
51717eb34cSmbalmer int	gpiosim_ioctl(struct device *, u_long cmd, caddr_t data);
52717eb34cSmbalmer 
53717eb34cSmbalmer int	gpiosim_pin_read(void *, int);
54717eb34cSmbalmer void	gpiosim_pin_write(void *, int, int);
55717eb34cSmbalmer void	gpiosim_pin_ctl(void *, int, int);
56717eb34cSmbalmer 
57*471aeecfSnaddy const struct cfattach gpiosim_ca = {
58717eb34cSmbalmer 	sizeof(struct gpiosim_softc), gpiosim_match, gpiosim_attach
59717eb34cSmbalmer };
60717eb34cSmbalmer 
61717eb34cSmbalmer struct cfdriver gpiosim_cd = {
62717eb34cSmbalmer 	NULL, "gpiosim", DV_DULL
63717eb34cSmbalmer };
64717eb34cSmbalmer 
65717eb34cSmbalmer int
gpiosim_match(struct device * parent,void * match,void * aux)66717eb34cSmbalmer gpiosim_match(struct device *parent, void *match, void *aux)
67717eb34cSmbalmer {
68717eb34cSmbalmer 	return 1;
69717eb34cSmbalmer }
70717eb34cSmbalmer 
71717eb34cSmbalmer void
gpiosim_attach(struct device * parent,struct device * self,void * aux)72717eb34cSmbalmer gpiosim_attach(struct device *parent, struct device *self, void *aux)
73717eb34cSmbalmer {
74717eb34cSmbalmer 	struct gpiosim_softc *sc = (void *)self;
75717eb34cSmbalmer 	struct gpiobus_attach_args gba;
76717eb34cSmbalmer 	int i;
77717eb34cSmbalmer 
78717eb34cSmbalmer 	/* initialize pin array */
79717eb34cSmbalmer 	for (i = 0; i < GPIOSIM_NPINS; i++) {
80717eb34cSmbalmer 		sc->sc_gpio_pins[i].pin_num = i;
81717eb34cSmbalmer 		sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT |
82717eb34cSmbalmer 		    GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN |
83717eb34cSmbalmer 		    GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN |
84717eb34cSmbalmer 		    GPIO_PIN_INVIN | GPIO_PIN_INVOUT;
85717eb34cSmbalmer 
86717eb34cSmbalmer 		/* read initial state */
87717eb34cSmbalmer 		sc->sc_gpio_pins[i].pin_flags = GPIO_PIN_INPUT;
88717eb34cSmbalmer 		sc->sc_state = 0;
89717eb34cSmbalmer 
90717eb34cSmbalmer 		/* create controller tag */
91717eb34cSmbalmer 		sc->sc_gpio_gc.gp_cookie = sc;
92717eb34cSmbalmer 		sc->sc_gpio_gc.gp_pin_read = gpiosim_pin_read;
93717eb34cSmbalmer 		sc->sc_gpio_gc.gp_pin_write = gpiosim_pin_write;
94717eb34cSmbalmer 		sc->sc_gpio_gc.gp_pin_ctl = gpiosim_pin_ctl;
95717eb34cSmbalmer 
96717eb34cSmbalmer 		gba.gba_name = "gpio";
97717eb34cSmbalmer 		gba.gba_gc = &sc->sc_gpio_gc;
98717eb34cSmbalmer 		gba.gba_pins = sc->sc_gpio_pins;
99717eb34cSmbalmer 		gba.gba_npins = GPIOSIM_NPINS;
100717eb34cSmbalmer 	}
101717eb34cSmbalmer 	printf("\n");
102717eb34cSmbalmer 	config_found(&sc->sc_dev, &gba, gpiobus_print);
103717eb34cSmbalmer 	bio_register(&sc->sc_dev, gpiosim_ioctl);
104717eb34cSmbalmer }
105717eb34cSmbalmer 
106717eb34cSmbalmer int
gpiosim_ioctl(struct device * self,u_long cmd,caddr_t data)107717eb34cSmbalmer gpiosim_ioctl(struct device *self, u_long cmd, caddr_t data)
108717eb34cSmbalmer {
109717eb34cSmbalmer 	struct gpiosim_softc *sc = (void *)self;
110717eb34cSmbalmer 	struct gpiosim_op *op = (void *)data;
111717eb34cSmbalmer 
112717eb34cSmbalmer 	switch (cmd) {
113717eb34cSmbalmer 		case GPIOSIMREAD:
114717eb34cSmbalmer 			op->state = sc->sc_state;
115717eb34cSmbalmer 			break;
116717eb34cSmbalmer 		case GPIOSIMWRITE:
117717eb34cSmbalmer 			sc->sc_state = (sc->sc_state & ~op->mask) |
118717eb34cSmbalmer 			    (op->state & op->mask);
119717eb34cSmbalmer 			break;
120717eb34cSmbalmer 	}
121717eb34cSmbalmer 	return 0;
122717eb34cSmbalmer }
123717eb34cSmbalmer 
124717eb34cSmbalmer int
gpiosim_pin_read(void * arg,int pin)125717eb34cSmbalmer gpiosim_pin_read(void *arg, int pin)
126717eb34cSmbalmer {
127717eb34cSmbalmer 	struct gpiosim_softc *sc = (struct gpiosim_softc *)arg;
128717eb34cSmbalmer 
129717eb34cSmbalmer 	if (sc->sc_state & (1 << pin))
130717eb34cSmbalmer 		return GPIO_PIN_HIGH;
131717eb34cSmbalmer 	else
132717eb34cSmbalmer 		return GPIO_PIN_LOW;
133717eb34cSmbalmer }
134717eb34cSmbalmer 
135717eb34cSmbalmer void
gpiosim_pin_write(void * arg,int pin,int value)136717eb34cSmbalmer gpiosim_pin_write(void *arg, int pin, int value)
137717eb34cSmbalmer {
138717eb34cSmbalmer 	struct gpiosim_softc *sc = (struct gpiosim_softc *)arg;
139717eb34cSmbalmer 
140717eb34cSmbalmer 	if (value == 0)
141717eb34cSmbalmer 		sc->sc_state &= ~(1 << pin);
142717eb34cSmbalmer 	else
143717eb34cSmbalmer 		sc->sc_state |= (1 << pin);
144717eb34cSmbalmer }
145717eb34cSmbalmer 
146717eb34cSmbalmer void
gpiosim_pin_ctl(void * arg,int pin,int flags)147717eb34cSmbalmer gpiosim_pin_ctl(void *arg, int pin, int flags)
148717eb34cSmbalmer {
149717eb34cSmbalmer 	struct gpiosim_softc *sc = (struct gpiosim_softc *)arg;
150717eb34cSmbalmer 
151717eb34cSmbalmer 	sc->sc_gpio_pins[pin].pin_flags = flags;
152717eb34cSmbalmer }
153