1 /* $OpenBSD: gdiumiic.c,v 1.9 2022/08/10 15:00:58 miod Exp $ */
2
3 /*
4 * Copyright (c) 2010 Miodrag Vallat.
5 * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /*
21 * I2C bus bit-banging through GPIO pins.
22 *
23 * Derived from /sys/dev/gpio/gpioiic.c, with SDA and SCL pin order
24 * exchanged, and knowledge of bus contents added.
25 */
26
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/device.h>
30 #include <sys/gpio.h>
31 #include <sys/rwlock.h>
32
33 #include <machine/autoconf.h>
34
35 #include <dev/gpio/gpiovar.h>
36
37 #include <dev/i2c/i2cvar.h>
38 #include <dev/i2c/i2c_bitbang.h>
39
40 #define GPIOIIC_PIN_SDA 1
41 #define GPIOIIC_PIN_SCL 0
42 #define GPIOIIC_NPINS 2
43
44 #define GPIOIIC_SDA 0x02
45 #define GPIOIIC_SCL 0x01
46
47 struct gdiumiic_softc {
48 struct device sc_dev;
49
50 void * sc_gpio;
51 struct gpio_pinmap sc_map;
52 int __map[GPIOIIC_NPINS];
53
54 struct i2c_controller sc_i2c_tag;
55 struct rwlock sc_i2c_lock;
56
57 int sc_sda;
58 int sc_scl;
59 };
60
61 int gdiumiic_match(struct device *, void *, void *);
62 void gdiumiic_attach(struct device *, struct device *, void *);
63 int gdiumiic_detach(struct device *, int);
64
65 int gdiumiic_i2c_acquire_bus(void *, int);
66 void gdiumiic_i2c_release_bus(void *, int);
67 int gdiumiic_i2c_send_start(void *, int);
68 int gdiumiic_i2c_send_stop(void *, int);
69 int gdiumiic_i2c_initiate_xfer(void *, i2c_addr_t, int);
70 int gdiumiic_i2c_read_byte(void *, u_int8_t *, int);
71 int gdiumiic_i2c_write_byte(void *, u_int8_t, int);
72
73 void gdiumiic_bb_set_bits(void *, u_int32_t);
74 void gdiumiic_bb_set_dir(void *, u_int32_t);
75 u_int32_t gdiumiic_bb_read_bits(void *);
76
77 int gdiumiic_bustype(struct gpio_attach_args *);
78 void gdiumiic_sensors_scan(struct device *,
79 struct i2cbus_attach_args *, void *);
80
81 const struct cfattach gdiumiic_ca = {
82 sizeof(struct gdiumiic_softc),
83 gdiumiic_match,
84 gdiumiic_attach,
85 gdiumiic_detach
86 };
87
88 struct cfdriver gdiumiic_cd = {
89 NULL, "gdiumiic", DV_DULL
90 };
91
92 static const struct i2c_bitbang_ops gdiumiic_bbops = {
93 gdiumiic_bb_set_bits,
94 gdiumiic_bb_set_dir,
95 gdiumiic_bb_read_bits,
96 { GPIOIIC_SDA, GPIOIIC_SCL, GPIOIIC_SDA, 0 }
97 };
98
99 #define GDIUMIIC_BUSTYPE_SENSORS 0
100 #define GDIUMIIC_BUSTYPE_VIDCTRL 1
101
102 int
gdiumiic_bustype(struct gpio_attach_args * ga)103 gdiumiic_bustype(struct gpio_attach_args *ga)
104 {
105 extern int gdium_revision;
106
107 /*
108 * Hardware pin connections depend upon the motherboard revision.
109 * XXX magic numbers (should match kernel configuration)
110 */
111 switch (gdium_revision) {
112 case 0:
113 if (ga->ga_offset == 46 && ga->ga_mask == 0x03)
114 return GDIUMIIC_BUSTYPE_SENSORS;
115 break;
116 default:
117 if (ga->ga_offset == 6 && ga->ga_mask == 0x81)
118 return GDIUMIIC_BUSTYPE_SENSORS;
119 break;
120 }
121
122 if (ga->ga_offset == 41 && ga->ga_mask == 0x03)
123 return GDIUMIIC_BUSTYPE_VIDCTRL;
124
125 return -1;
126
127 }
128
129 int
gdiumiic_match(struct device * parent,void * match,void * aux)130 gdiumiic_match(struct device *parent, void *match, void *aux)
131 {
132 struct cfdata *cf = match;
133 struct gpio_attach_args *ga = aux;
134
135 if (ga->ga_offset == -1 || gdiumiic_bustype(ga) < 0)
136 return 0;
137
138 return (sys_platform->system_type == LOONGSON_GDIUM &&
139 strcmp(cf->cf_driver->cd_name, "gdiumiic") == 0);
140 }
141
142 void
gdiumiic_attach(struct device * parent,struct device * self,void * aux)143 gdiumiic_attach(struct device *parent, struct device *self, void *aux)
144 {
145 struct gdiumiic_softc *sc = (struct gdiumiic_softc *)self;
146 struct gpio_attach_args *ga = aux;
147 struct i2cbus_attach_args iba;
148 int caps;
149
150 /* Check that we have enough pins */
151 if (gpio_npins(ga->ga_mask) != GPIOIIC_NPINS) {
152 printf(": invalid pin mask\n");
153 return;
154 }
155
156 /* Map pins */
157 sc->sc_gpio = ga->ga_gpio;
158 sc->sc_map.pm_map = sc->__map;
159 if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask,
160 &sc->sc_map)) {
161 printf(": can't map pins\n");
162 return;
163 }
164
165 /* Configure SDA pin */
166 caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA);
167 if (!(caps & GPIO_PIN_OUTPUT)) {
168 printf(": SDA pin is unable to drive output\n");
169 goto fail;
170 }
171 if (!(caps & GPIO_PIN_INPUT)) {
172 printf(": SDA pin is unable to read input\n");
173 goto fail;
174 }
175 printf(": SDA[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SDA]);
176 sc->sc_sda = GPIO_PIN_OUTPUT;
177 #if 0
178 if (caps & GPIO_PIN_OPENDRAIN) {
179 printf(" open-drain");
180 sc->sc_sda |= GPIO_PIN_OPENDRAIN;
181 } else if ((caps & GPIO_PIN_PUSHPULL) && (caps & GPIO_PIN_TRISTATE)) {
182 printf(" push-pull tri-state");
183 sc->sc_sda |= GPIO_PIN_PUSHPULL;
184 }
185 if (caps & GPIO_PIN_PULLUP) {
186 printf(" pull-up");
187 sc->sc_sda |= GPIO_PIN_PULLUP;
188 }
189 #endif
190 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA, sc->sc_sda);
191
192 /* Configure SCL pin */
193 caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL);
194 if (!(caps & GPIO_PIN_OUTPUT)) {
195 printf(": SCL pin is unable to drive output\n");
196 goto fail;
197 }
198 printf(", SCL[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SCL]);
199 sc->sc_scl = GPIO_PIN_OUTPUT;
200 #if 0
201 if (caps & GPIO_PIN_OPENDRAIN) {
202 printf(" open-drain");
203 sc->sc_scl |= GPIO_PIN_OPENDRAIN;
204 if (caps & GPIO_PIN_PULLUP) {
205 printf(" pull-up");
206 sc->sc_scl |= GPIO_PIN_PULLUP;
207 }
208 } else if (caps & GPIO_PIN_PUSHPULL) {
209 printf(" push-pull");
210 sc->sc_scl |= GPIO_PIN_PUSHPULL;
211 }
212 #endif
213 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL, sc->sc_scl);
214
215 printf("\n");
216
217 /* Attach I2C bus */
218 rw_init(&sc->sc_i2c_lock, "iiclk");
219 sc->sc_i2c_tag.ic_cookie = sc;
220 sc->sc_i2c_tag.ic_acquire_bus = gdiumiic_i2c_acquire_bus;
221 sc->sc_i2c_tag.ic_release_bus = gdiumiic_i2c_release_bus;
222 sc->sc_i2c_tag.ic_send_start = gdiumiic_i2c_send_start;
223 sc->sc_i2c_tag.ic_send_stop = gdiumiic_i2c_send_stop;
224 sc->sc_i2c_tag.ic_initiate_xfer = gdiumiic_i2c_initiate_xfer;
225 sc->sc_i2c_tag.ic_read_byte = gdiumiic_i2c_read_byte;
226 sc->sc_i2c_tag.ic_write_byte = gdiumiic_i2c_write_byte;
227
228 bzero(&iba, sizeof(iba));
229 iba.iba_name = "iic";
230 iba.iba_tag = &sc->sc_i2c_tag;
231 if (gdiumiic_bustype(ga) == GDIUMIIC_BUSTYPE_SENSORS)
232 iba.iba_bus_scan = gdiumiic_sensors_scan;
233 config_found(self, &iba, iicbus_print);
234
235 return;
236
237 fail:
238 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
239 }
240
241 int
gdiumiic_detach(struct device * self,int flags)242 gdiumiic_detach(struct device *self, int flags)
243 {
244 return (0);
245 }
246
247 int
gdiumiic_i2c_acquire_bus(void * cookie,int flags)248 gdiumiic_i2c_acquire_bus(void *cookie, int flags)
249 {
250 struct gdiumiic_softc *sc = cookie;
251
252 if (cold || (flags & I2C_F_POLL))
253 return (0);
254
255 return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
256 }
257
258 void
gdiumiic_i2c_release_bus(void * cookie,int flags)259 gdiumiic_i2c_release_bus(void *cookie, int flags)
260 {
261 struct gdiumiic_softc *sc = cookie;
262
263 if (cold || (flags & I2C_F_POLL))
264 return;
265
266 rw_exit(&sc->sc_i2c_lock);
267 }
268
269 int
gdiumiic_i2c_send_start(void * cookie,int flags)270 gdiumiic_i2c_send_start(void *cookie, int flags)
271 {
272 return (i2c_bitbang_send_start(cookie, flags, &gdiumiic_bbops));
273 }
274
275 int
gdiumiic_i2c_send_stop(void * cookie,int flags)276 gdiumiic_i2c_send_stop(void *cookie, int flags)
277 {
278 return (i2c_bitbang_send_stop(cookie, flags, &gdiumiic_bbops));
279 }
280
281 int
gdiumiic_i2c_initiate_xfer(void * cookie,i2c_addr_t addr,int flags)282 gdiumiic_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
283 {
284 return (i2c_bitbang_initiate_xfer(cookie, addr, flags, &gdiumiic_bbops));
285 }
286
287 int
gdiumiic_i2c_read_byte(void * cookie,u_int8_t * bytep,int flags)288 gdiumiic_i2c_read_byte(void *cookie, u_int8_t *bytep, int flags)
289 {
290 return (i2c_bitbang_read_byte(cookie, bytep, flags, &gdiumiic_bbops));
291 }
292
293 int
gdiumiic_i2c_write_byte(void * cookie,u_int8_t byte,int flags)294 gdiumiic_i2c_write_byte(void *cookie, u_int8_t byte, int flags)
295 {
296 return (i2c_bitbang_write_byte(cookie, byte, flags, &gdiumiic_bbops));
297 }
298
299 void
gdiumiic_bb_set_bits(void * cookie,u_int32_t bits)300 gdiumiic_bb_set_bits(void *cookie, u_int32_t bits)
301 {
302 struct gdiumiic_softc *sc = cookie;
303
304 gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA,
305 bits & GPIOIIC_SDA ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
306 gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL,
307 bits & GPIOIIC_SCL ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
308 }
309
310 void
gdiumiic_bb_set_dir(void * cookie,u_int32_t bits)311 gdiumiic_bb_set_dir(void *cookie, u_int32_t bits)
312 {
313 struct gdiumiic_softc *sc = cookie;
314 int sda = sc->sc_sda;
315
316 sda &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE);
317 sda |= (bits & GPIOIIC_SDA ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT);
318 #if 0
319 if ((sda & GPIO_PIN_PUSHPULL) && !(bits & GPIOIIC_SDA))
320 sda |= GPIO_PIN_TRISTATE;
321 #endif
322 if (sc->sc_sda != sda) {
323 sc->sc_sda = sda;
324 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA,
325 sc->sc_sda);
326 }
327 }
328
329 u_int32_t
gdiumiic_bb_read_bits(void * cookie)330 gdiumiic_bb_read_bits(void *cookie)
331 {
332 struct gdiumiic_softc *sc = cookie;
333 u_int32_t bits = 0;
334
335 if (gpio_pin_read(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA) ==
336 GPIO_PIN_HIGH)
337 bits |= GPIOIIC_SDA;
338 if (gpio_pin_read(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL) ==
339 GPIO_PIN_HIGH)
340 bits |= GPIOIIC_SCL;
341
342 return bits;
343 }
344
345 /*
346 * Attach devices to the first (sensors + RTC) i2c bus.
347 *
348 * Note that the i2c scan performed by the MI i2c code will fail to
349 * identify our lm75 chip correctly.
350 */
351 void
gdiumiic_sensors_scan(struct device * iicdev,struct i2cbus_attach_args * iba,void * arg)352 gdiumiic_sensors_scan(struct device *iicdev, struct i2cbus_attach_args *iba,
353 void *arg)
354 {
355 struct i2c_attach_args ia;
356 /* not worth #define'ing _I2C_PRIVATE for */
357 extern int iic_print(void *, const char *);
358
359 bzero(&ia, sizeof ia);
360 ia.ia_tag = iba->iba_tag;
361 ia.ia_addr = 0x40;
362 ia.ia_size = 1;
363 ia.ia_name = "stsec";
364 config_found(iicdev, &ia, iic_print);
365
366 bzero(&ia, sizeof ia);
367 ia.ia_tag = iba->iba_tag;
368 ia.ia_addr = 0x48;
369 ia.ia_size = 1;
370 ia.ia_name = "lm75";
371 config_found(iicdev, &ia, iic_print);
372
373 bzero(&ia, sizeof ia);
374 ia.ia_tag = iba->iba_tag;
375 ia.ia_addr = 0x51;
376 ia.ia_size = 1;
377 ia.ia_name = "spd";
378 config_found(iicdev, &ia, iic_print);
379
380 bzero(&ia, sizeof ia);
381 ia.ia_tag = iba->iba_tag;
382 ia.ia_addr = 0x68;
383 ia.ia_size = 1;
384 ia.ia_name = "st,m41t83";
385 config_found(iicdev, &ia, iic_print);
386 }
387