xref: /openbsd-src/sys/dev/gpio/gpioow.c (revision 471aeecfc619bc9b69519928152daf993376c2a1)
1*471aeecfSnaddy /*	$OpenBSD: gpioow.c,v 1.6 2022/04/06 18:59:28 naddy Exp $	*/
2f8c248a6Sgrange 
3f8c248a6Sgrange /*
4f8c248a6Sgrange  * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
5f8c248a6Sgrange  *
6f8c248a6Sgrange  * Permission to use, copy, modify, and distribute this software for any
7f8c248a6Sgrange  * purpose with or without fee is hereby granted, provided that the above
8f8c248a6Sgrange  * copyright notice and this permission notice appear in all copies.
9f8c248a6Sgrange  *
10f8c248a6Sgrange  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11f8c248a6Sgrange  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12f8c248a6Sgrange  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13f8c248a6Sgrange  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14f8c248a6Sgrange  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15f8c248a6Sgrange  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16f8c248a6Sgrange  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17f8c248a6Sgrange  */
18f8c248a6Sgrange 
19f8c248a6Sgrange /*
20f8c248a6Sgrange  * 1-Wire bus bit-banging through GPIO pin.
21f8c248a6Sgrange  */
22f8c248a6Sgrange 
23f8c248a6Sgrange #include <sys/param.h>
24f8c248a6Sgrange #include <sys/systm.h>
25f8c248a6Sgrange #include <sys/device.h>
26f8c248a6Sgrange #include <sys/gpio.h>
27f8c248a6Sgrange 
28f8c248a6Sgrange #include <dev/gpio/gpiovar.h>
29f8c248a6Sgrange 
30f8c248a6Sgrange #include <dev/onewire/onewirevar.h>
31f8c248a6Sgrange 
32f8c248a6Sgrange #define GPIOOW_NPINS		1
33f8c248a6Sgrange #define GPIOOW_PIN_DATA		0
34f8c248a6Sgrange 
35f8c248a6Sgrange struct gpioow_softc {
36f8c248a6Sgrange 	struct device		sc_dev;
37f8c248a6Sgrange 
38f8c248a6Sgrange 	void *			sc_gpio;
39f8c248a6Sgrange 	struct gpio_pinmap	sc_map;
40f8c248a6Sgrange 	int			__map[GPIOOW_NPINS];
41f8c248a6Sgrange 
42f8c248a6Sgrange 	struct onewire_bus	sc_ow_bus;
43f8c248a6Sgrange 	struct device *		sc_ow_dev;
44f8c248a6Sgrange 
45f8c248a6Sgrange 	int			sc_data;
46f8c248a6Sgrange 	int			sc_dying;
47f8c248a6Sgrange };
48f8c248a6Sgrange 
49f8c248a6Sgrange int	gpioow_match(struct device *, void *, void *);
50f8c248a6Sgrange void	gpioow_attach(struct device *, struct device *, void *);
51f8c248a6Sgrange int	gpioow_detach(struct device *, int);
52e78728c7Spirofti int	gpioow_activate(struct device *, int);
53f8c248a6Sgrange 
54f8c248a6Sgrange int	gpioow_ow_reset(void *);
55f8c248a6Sgrange int	gpioow_ow_bit(void *, int);
56f8c248a6Sgrange 
57f8c248a6Sgrange void	gpioow_bb_rx(void *);
58f8c248a6Sgrange void	gpioow_bb_tx(void *);
59f8c248a6Sgrange int	gpioow_bb_get(void *);
60f8c248a6Sgrange void	gpioow_bb_set(void *, int);
61f8c248a6Sgrange 
62*471aeecfSnaddy const struct cfattach gpioow_ca = {
63f8c248a6Sgrange 	sizeof(struct gpioow_softc),
64f8c248a6Sgrange 	gpioow_match,
65f8c248a6Sgrange 	gpioow_attach,
66f8c248a6Sgrange 	gpioow_detach,
67f8c248a6Sgrange 	gpioow_activate
68f8c248a6Sgrange };
69f8c248a6Sgrange 
70f8c248a6Sgrange struct cfdriver gpioow_cd = {
71f8c248a6Sgrange 	NULL, "gpioow", DV_DULL
72f8c248a6Sgrange };
73f8c248a6Sgrange 
74f8c248a6Sgrange static const struct onewire_bbops gpioow_bbops = {
75f8c248a6Sgrange 	gpioow_bb_rx,
76f8c248a6Sgrange 	gpioow_bb_tx,
77f8c248a6Sgrange 	gpioow_bb_get,
78f8c248a6Sgrange 	gpioow_bb_set
79f8c248a6Sgrange };
80f8c248a6Sgrange 
81f8c248a6Sgrange int
gpioow_match(struct device * parent,void * match,void * aux)82f8c248a6Sgrange gpioow_match(struct device *parent, void *match, void *aux)
83f8c248a6Sgrange {
84f8c248a6Sgrange 	struct cfdata *cf = match;
85fca40c6aSmbalmer 	struct gpio_attach_args *ga = aux;
86fca40c6aSmbalmer 
87fca40c6aSmbalmer 	if (ga->ga_offset == -1)
88fca40c6aSmbalmer 		return 0;
89f8c248a6Sgrange 
90f8c248a6Sgrange 	return (strcmp(cf->cf_driver->cd_name, "gpioow") == 0);
91f8c248a6Sgrange }
92f8c248a6Sgrange 
93f8c248a6Sgrange void
gpioow_attach(struct device * parent,struct device * self,void * aux)94f8c248a6Sgrange gpioow_attach(struct device *parent, struct device *self, void *aux)
95f8c248a6Sgrange {
96f8c248a6Sgrange 	struct gpioow_softc *sc = (struct gpioow_softc *)self;
97f8c248a6Sgrange 	struct gpio_attach_args *ga = aux;
98f8c248a6Sgrange 	struct onewirebus_attach_args oba;
99f8c248a6Sgrange 	int caps;
100f8c248a6Sgrange 
101f8c248a6Sgrange 	/* Check that we have enough pins */
102f8c248a6Sgrange 	if (gpio_npins(ga->ga_mask) != GPIOOW_NPINS) {
103f8c248a6Sgrange 		printf(": invalid pin mask\n");
104f8c248a6Sgrange 		return;
105f8c248a6Sgrange 	}
106f8c248a6Sgrange 
107f8c248a6Sgrange 	/* Map pins */
108f8c248a6Sgrange 	sc->sc_gpio = ga->ga_gpio;
109f8c248a6Sgrange 	sc->sc_map.pm_map = sc->__map;
110f8c248a6Sgrange 	if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask,
111f8c248a6Sgrange 	    &sc->sc_map)) {
112f8c248a6Sgrange 		printf(": can't map pins\n");
113f8c248a6Sgrange 		return;
114f8c248a6Sgrange 	}
115f8c248a6Sgrange 
116f8c248a6Sgrange 	/* Configure data pin */
117f8c248a6Sgrange 	caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA);
118f8c248a6Sgrange 	if (!(caps & GPIO_PIN_OUTPUT)) {
119f8c248a6Sgrange 		printf(": data pin is unable to drive output\n");
120f8c248a6Sgrange 		goto fail;
121f8c248a6Sgrange 	}
122f8c248a6Sgrange 	if (!(caps & GPIO_PIN_INPUT)) {
123f8c248a6Sgrange 		printf(": data pin is unable to read input\n");
124f8c248a6Sgrange 		goto fail;
125f8c248a6Sgrange 	}
126f8c248a6Sgrange 	printf(": DATA[%d]", sc->sc_map.pm_map[GPIOOW_PIN_DATA]);
127f8c248a6Sgrange 	sc->sc_data = GPIO_PIN_OUTPUT;
128f8c248a6Sgrange 	if (caps & GPIO_PIN_OPENDRAIN) {
129f8c248a6Sgrange 		printf(" open-drain");
130f8c248a6Sgrange 		sc->sc_data |= GPIO_PIN_OPENDRAIN;
131f8c248a6Sgrange 	} else if ((caps & GPIO_PIN_PUSHPULL) && (caps & GPIO_PIN_TRISTATE)) {
132f8c248a6Sgrange 		printf(" push-pull tri-state");
133f8c248a6Sgrange 		sc->sc_data |= GPIO_PIN_PUSHPULL;
134f8c248a6Sgrange 	}
135f8c248a6Sgrange 	if (caps & GPIO_PIN_PULLUP) {
136f8c248a6Sgrange 		printf(" pull-up");
137f8c248a6Sgrange 		sc->sc_data |= GPIO_PIN_PULLUP;
138f8c248a6Sgrange 	}
139f8c248a6Sgrange 	gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, sc->sc_data);
140f8c248a6Sgrange 
141f8c248a6Sgrange 	printf("\n");
142f8c248a6Sgrange 
143f8c248a6Sgrange 	/* Attach 1-Wire bus */
144f8c248a6Sgrange 	sc->sc_ow_bus.bus_cookie = sc;
145f8c248a6Sgrange 	sc->sc_ow_bus.bus_reset = gpioow_ow_reset;
146f8c248a6Sgrange 	sc->sc_ow_bus.bus_bit = gpioow_ow_bit;
147f8c248a6Sgrange 
148f8c248a6Sgrange 	bzero(&oba, sizeof(oba));
149f8c248a6Sgrange 	oba.oba_bus = &sc->sc_ow_bus;
150f8c248a6Sgrange 	sc->sc_ow_dev = config_found(self, &oba, onewirebus_print);
151f8c248a6Sgrange 
152f8c248a6Sgrange 	return;
153f8c248a6Sgrange 
154f8c248a6Sgrange fail:
155f8c248a6Sgrange 	gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
156f8c248a6Sgrange }
157f8c248a6Sgrange 
158f8c248a6Sgrange int
gpioow_detach(struct device * self,int flags)159f8c248a6Sgrange gpioow_detach(struct device *self, int flags)
160f8c248a6Sgrange {
161f8c248a6Sgrange 	struct gpioow_softc *sc = (struct gpioow_softc *)self;
162f8c248a6Sgrange 	int rv = 0;
163f8c248a6Sgrange 
164fca40c6aSmbalmer 	gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
165fca40c6aSmbalmer 
166f8c248a6Sgrange 	if (sc->sc_ow_dev != NULL)
167f8c248a6Sgrange 		rv = config_detach(sc->sc_ow_dev, flags);
168f8c248a6Sgrange 
169f8c248a6Sgrange 	return (rv);
170f8c248a6Sgrange }
171f8c248a6Sgrange 
172f8c248a6Sgrange int
gpioow_activate(struct device * self,int act)173e78728c7Spirofti gpioow_activate(struct device *self, int act)
174f8c248a6Sgrange {
175f8c248a6Sgrange 	struct gpioow_softc *sc = (struct gpioow_softc *)self;
176f8c248a6Sgrange 	int rv = 0;
177f8c248a6Sgrange 
178f8c248a6Sgrange 	switch (act) {
179f8c248a6Sgrange 	case DVACT_DEACTIVATE:
180f8c248a6Sgrange 		sc->sc_dying = 1;
181f8c248a6Sgrange 		if (sc->sc_ow_dev != NULL)
182f8c248a6Sgrange 			rv = config_deactivate(sc->sc_ow_dev);
183f8c248a6Sgrange 		break;
184f8c248a6Sgrange 	}
185f8c248a6Sgrange 
186f8c248a6Sgrange 	return (rv);
187f8c248a6Sgrange }
188f8c248a6Sgrange 
189f8c248a6Sgrange int
gpioow_ow_reset(void * arg)190f8c248a6Sgrange gpioow_ow_reset(void *arg)
191f8c248a6Sgrange {
192f8c248a6Sgrange 	return (onewire_bb_reset(&gpioow_bbops, arg));
193f8c248a6Sgrange }
194f8c248a6Sgrange 
195f8c248a6Sgrange int
gpioow_ow_bit(void * arg,int value)196f8c248a6Sgrange gpioow_ow_bit(void *arg, int value)
197f8c248a6Sgrange {
198f8c248a6Sgrange 	return (onewire_bb_bit(&gpioow_bbops, arg, value));
199f8c248a6Sgrange }
200f8c248a6Sgrange 
201f8c248a6Sgrange void
gpioow_bb_rx(void * arg)202f8c248a6Sgrange gpioow_bb_rx(void *arg)
203f8c248a6Sgrange {
204f8c248a6Sgrange 	struct gpioow_softc *sc = arg;
205f8c248a6Sgrange 	int data = sc->sc_data;
206f8c248a6Sgrange 
207f8c248a6Sgrange 	data &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE);
208f8c248a6Sgrange 	data |= GPIO_PIN_INPUT;
209f8c248a6Sgrange 	if (data & GPIO_PIN_PUSHPULL)
210f8c248a6Sgrange 		data |= GPIO_PIN_TRISTATE;
211f8c248a6Sgrange 	if (sc->sc_data != data) {
212f8c248a6Sgrange 		sc->sc_data = data;
213f8c248a6Sgrange 		gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA,
214f8c248a6Sgrange 		    sc->sc_data);
215f8c248a6Sgrange 	}
216f8c248a6Sgrange }
217f8c248a6Sgrange 
218f8c248a6Sgrange void
gpioow_bb_tx(void * arg)219f8c248a6Sgrange gpioow_bb_tx(void *arg)
220f8c248a6Sgrange {
221f8c248a6Sgrange 	struct gpioow_softc *sc = arg;
222f8c248a6Sgrange 	int data = sc->sc_data;
223f8c248a6Sgrange 
224f8c248a6Sgrange 	data &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE);
225f8c248a6Sgrange 	data |= GPIO_PIN_OUTPUT;
226f8c248a6Sgrange 	if (sc->sc_data != data) {
227f8c248a6Sgrange 		sc->sc_data = data;
228f8c248a6Sgrange 		gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA,
229f8c248a6Sgrange 		    sc->sc_data);
230f8c248a6Sgrange 	}
231f8c248a6Sgrange }
232f8c248a6Sgrange 
233f8c248a6Sgrange int
gpioow_bb_get(void * arg)234f8c248a6Sgrange gpioow_bb_get(void *arg)
235f8c248a6Sgrange {
236f8c248a6Sgrange 	struct gpioow_softc *sc = arg;
237f8c248a6Sgrange 
238f8c248a6Sgrange 	return (gpio_pin_read(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA) ==
239f8c248a6Sgrange 	    GPIO_PIN_HIGH ? 1 : 0);
240f8c248a6Sgrange }
241f8c248a6Sgrange 
242f8c248a6Sgrange void
gpioow_bb_set(void * arg,int value)243f8c248a6Sgrange gpioow_bb_set(void *arg, int value)
244f8c248a6Sgrange {
245f8c248a6Sgrange 	struct gpioow_softc *sc = arg;
246f8c248a6Sgrange 
247f8c248a6Sgrange 	gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA,
248f8c248a6Sgrange 	    value ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
249f8c248a6Sgrange }
250