FreeBSD/Linux Kernel Cross Reference
sys/dev/gpio/gpioiic.c
1 /* $OpenBSD: gpioiic.c,v 1.11 2022/04/06 18:59:28 naddy Exp $ */
2
3 /*
4 * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * I2C bus bit-banging through GPIO pins.
21 */
22
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
26 #include <sys/gpio.h>
27 #include <sys/rwlock.h>
28
29 #include <dev/gpio/gpiovar.h>
30
31 #include <dev/i2c/i2cvar.h>
32 #include <dev/i2c/i2c_bitbang.h>
33
34 #define GPIOIIC_PIN_SDA 0
35 #define GPIOIIC_PIN_SCL 1
36 #define GPIOIIC_NPINS 2
37
38 /* flags */
39 #define GPIOIIC_PIN_REVERSE 0x01
40
41 #define GPIOIIC_SDA 0x01
42 #define GPIOIIC_SCL 0x02
43
44 struct gpioiic_softc {
45 struct device sc_dev;
46
47 void * sc_gpio;
48 struct gpio_pinmap sc_map;
49 int __map[GPIOIIC_NPINS];
50
51 struct i2c_controller sc_i2c_tag;
52 struct rwlock sc_i2c_lock;
53
54 int sc_pin_sda;
55 int sc_pin_scl;
56
57 int sc_sda;
58 int sc_scl;
59 };
60
61 int gpioiic_match(struct device *, void *, void *);
62 void gpioiic_attach(struct device *, struct device *, void *);
63 int gpioiic_detach(struct device *, int);
64
65 int gpioiic_i2c_acquire_bus(void *, int);
66 void gpioiic_i2c_release_bus(void *, int);
67 int gpioiic_i2c_send_start(void *, int);
68 int gpioiic_i2c_send_stop(void *, int);
69 int gpioiic_i2c_initiate_xfer(void *, i2c_addr_t, int);
70 int gpioiic_i2c_read_byte(void *, u_int8_t *, int);
71 int gpioiic_i2c_write_byte(void *, u_int8_t, int);
72
73 void gpioiic_bb_set_bits(void *, u_int32_t);
74 void gpioiic_bb_set_dir(void *, u_int32_t);
75 u_int32_t gpioiic_bb_read_bits(void *);
76
77 const struct cfattach gpioiic_ca = {
78 sizeof(struct gpioiic_softc),
79 gpioiic_match,
80 gpioiic_attach,
81 gpioiic_detach
82 };
83
84 struct cfdriver gpioiic_cd = {
85 NULL, "gpioiic", DV_DULL
86 };
87
88 static const struct i2c_bitbang_ops gpioiic_bbops = {
89 gpioiic_bb_set_bits,
90 gpioiic_bb_set_dir,
91 gpioiic_bb_read_bits,
92 { GPIOIIC_SDA, GPIOIIC_SCL, GPIOIIC_SDA, 0 }
93 };
94
95 int
96 gpioiic_match(struct device *parent, void *match, void *aux)
97 {
98 struct cfdata *cf = match;
99 struct gpio_attach_args *ga = aux;
100
101 if (ga->ga_offset == -1)
102 return 0;
103
104 return (strcmp(cf->cf_driver->cd_name, "gpioiic") == 0);
105 }
106
107 void
108 gpioiic_attach(struct device *parent, struct device *self, void *aux)
109 {
110 struct gpioiic_softc *sc = (struct gpioiic_softc *)self;
111 struct gpio_attach_args *ga = aux;
112 struct i2cbus_attach_args iba;
113 int caps;
114
115 /* Check that we have enough pins */
116 if (gpio_npins(ga->ga_mask) != GPIOIIC_NPINS) {
117 printf(": invalid pin mask\n");
118 return;
119 }
120
121 /* Map pins */
122 sc->sc_gpio = ga->ga_gpio;
123 sc->sc_map.pm_map = sc->__map;
124 if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask,
125 &sc->sc_map)) {
126 printf(": can't map pins\n");
127 return;
128 }
129
130 if (ga->ga_flags & GPIOIIC_PIN_REVERSE) {
131 sc->sc_pin_sda = GPIOIIC_PIN_SCL;
132 sc->sc_pin_scl = GPIOIIC_PIN_SDA;
133 } else {
134 sc->sc_pin_sda = GPIOIIC_PIN_SDA;
135 sc->sc_pin_scl = GPIOIIC_PIN_SCL;
136 }
137
138 /* Configure SDA pin */
139 caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, sc->sc_pin_sda);
140 if (!(caps & GPIO_PIN_OUTPUT)) {
141 printf(": SDA pin is unable to drive output\n");
142 goto fail;
143 }
144 if (!(caps & GPIO_PIN_INPUT)) {
145 printf(": SDA pin is unable to read input\n");
146 goto fail;
147 }
148 printf(": SDA[%d]", sc->sc_map.pm_map[sc->sc_pin_sda]);
149 sc->sc_sda = GPIO_PIN_OUTPUT;
150 if (caps & GPIO_PIN_OPENDRAIN) {
151 printf(" open-drain");
152 sc->sc_sda |= GPIO_PIN_OPENDRAIN;
153 } else if ((caps & GPIO_PIN_PUSHPULL) && (caps & GPIO_PIN_TRISTATE)) {
154 printf(" push-pull tri-state");
155 sc->sc_sda |= GPIO_PIN_PUSHPULL;
156 }
157 if (caps & GPIO_PIN_PULLUP) {
158 printf(" pull-up");
159 sc->sc_sda |= GPIO_PIN_PULLUP;
160 }
161 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, sc->sc_pin_sda, sc->sc_sda);
162
163 /* Configure SCL pin */
164 caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, sc->sc_pin_scl);
165 if (!(caps & GPIO_PIN_OUTPUT)) {
166 printf(": SCL pin is unable to drive output\n");
167 goto fail;
168 }
169 printf(", SCL[%d]", sc->sc_map.pm_map[sc->sc_pin_scl]);
170 sc->sc_scl = GPIO_PIN_OUTPUT;
171 if (caps & GPIO_PIN_OPENDRAIN) {
172 printf(" open-drain");
173 sc->sc_scl |= GPIO_PIN_OPENDRAIN;
174 if (caps & GPIO_PIN_PULLUP) {
175 printf(" pull-up");
176 sc->sc_scl |= GPIO_PIN_PULLUP;
177 }
178 } else if (caps & GPIO_PIN_PUSHPULL) {
179 printf(" push-pull");
180 sc->sc_scl |= GPIO_PIN_PUSHPULL;
181 }
182 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, sc->sc_pin_scl, sc->sc_scl);
183
184 printf("\n");
185
186 /* Attach I2C bus */
187 rw_init(&sc->sc_i2c_lock, "iiclk");
188 sc->sc_i2c_tag.ic_cookie = sc;
189 sc->sc_i2c_tag.ic_acquire_bus = gpioiic_i2c_acquire_bus;
190 sc->sc_i2c_tag.ic_release_bus = gpioiic_i2c_release_bus;
191 sc->sc_i2c_tag.ic_send_start = gpioiic_i2c_send_start;
192 sc->sc_i2c_tag.ic_send_stop = gpioiic_i2c_send_stop;
193 sc->sc_i2c_tag.ic_initiate_xfer = gpioiic_i2c_initiate_xfer;
194 sc->sc_i2c_tag.ic_read_byte = gpioiic_i2c_read_byte;
195 sc->sc_i2c_tag.ic_write_byte = gpioiic_i2c_write_byte;
196
197 bzero(&iba, sizeof(iba));
198 iba.iba_name = "iic";
199 iba.iba_tag = &sc->sc_i2c_tag;
200 config_found(self, &iba, iicbus_print);
201
202 return;
203
204 fail:
205 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
206 }
207
208 int
209 gpioiic_detach(struct device *self, int flags)
210 {
211 return (0);
212 }
213
214 int
215 gpioiic_i2c_acquire_bus(void *cookie, int flags)
216 {
217 struct gpioiic_softc *sc = cookie;
218
219 if (cold || (flags & I2C_F_POLL))
220 return (0);
221
222 return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
223 }
224
225 void
226 gpioiic_i2c_release_bus(void *cookie, int flags)
227 {
228 struct gpioiic_softc *sc = cookie;
229
230 if (cold || (flags & I2C_F_POLL))
231 return;
232
233 rw_exit(&sc->sc_i2c_lock);
234 }
235
236 int
237 gpioiic_i2c_send_start(void *cookie, int flags)
238 {
239 return (i2c_bitbang_send_start(cookie, flags, &gpioiic_bbops));
240 }
241
242 int
243 gpioiic_i2c_send_stop(void *cookie, int flags)
244 {
245 return (i2c_bitbang_send_stop(cookie, flags, &gpioiic_bbops));
246 }
247
248 int
249 gpioiic_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
250 {
251 return (i2c_bitbang_initiate_xfer(cookie, addr, flags, &gpioiic_bbops));
252 }
253
254 int
255 gpioiic_i2c_read_byte(void *cookie, u_int8_t *bytep, int flags)
256 {
257 return (i2c_bitbang_read_byte(cookie, bytep, flags, &gpioiic_bbops));
258 }
259
260 int
261 gpioiic_i2c_write_byte(void *cookie, u_int8_t byte, int flags)
262 {
263 return (i2c_bitbang_write_byte(cookie, byte, flags, &gpioiic_bbops));
264 }
265
266 void
267 gpioiic_bb_set_bits(void *cookie, u_int32_t bits)
268 {
269 struct gpioiic_softc *sc = cookie;
270
271 gpio_pin_write(sc->sc_gpio, &sc->sc_map, sc->sc_pin_sda,
272 bits & GPIOIIC_SDA ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
273 gpio_pin_write(sc->sc_gpio, &sc->sc_map, sc->sc_pin_scl,
274 bits & GPIOIIC_SCL ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
275 }
276
277 void
278 gpioiic_bb_set_dir(void *cookie, u_int32_t bits)
279 {
280 struct gpioiic_softc *sc = cookie;
281 int sda = sc->sc_sda;
282
283 sda &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE);
284 sda |= (bits & GPIOIIC_SDA ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT);
285 if ((sda & GPIO_PIN_PUSHPULL) && !(bits & GPIOIIC_SDA))
286 sda |= GPIO_PIN_TRISTATE;
287 if (sc->sc_sda != sda) {
288 sc->sc_sda = sda;
289 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, sc->sc_pin_sda,
290 sc->sc_sda);
291 }
292 }
293
294 u_int32_t
295 gpioiic_bb_read_bits(void *cookie)
296 {
297 struct gpioiic_softc *sc = cookie;
298 u_int32_t bits = 0;
299
300 if (gpio_pin_read(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA) ==
301 GPIO_PIN_HIGH)
302 bits |= GPIOIIC_SDA;
303 if (gpio_pin_read(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL) ==
304 GPIO_PIN_HIGH)
305 bits |= GPIOIIC_SCL;
306
307 return bits;
308 }
Cache object: 1793c9f6242bfc0197d6616529ab1662
|