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