Annotation of sys/dev/i2c/pca9554.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: pca9554.c,v 1.14 2007/07/31 21:34:39 cnst Exp $ */
2:
3: /*
4: * Copyright (c) 2005 Theo de Raadt
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: #include <sys/param.h>
20: #include <sys/systm.h>
21: #include <sys/device.h>
22: #include <sys/gpio.h>
23: #include <sys/sensors.h>
24:
25: #include <dev/i2c/i2cvar.h>
26:
27: #include <dev/gpio/gpiovar.h>
28:
29: /* Phillips 9554 registers */
30: #define PCA9554_IN 0x00
31: #define PCA9554_OUT 0x01
32: #define PCA9554_POLARITY 0x02
33: #define PCA9554_CONFIG 0x03
34:
35: /* Sensors */
36: #define PCAGPIO_NPINS 8
37:
38: struct pcagpio_softc {
39: struct device sc_dev;
40: i2c_tag_t sc_tag;
41: i2c_addr_t sc_addr;
42: u_int8_t sc_control;
43: u_int8_t sc_polarity;
44:
45: struct gpio_chipset_tag sc_gpio_gc;
46: gpio_pin_t sc_gpio_pins[PCAGPIO_NPINS];
47:
48: struct ksensor sc_sensor[PCAGPIO_NPINS];
49: struct ksensordev sc_sensordev;
50: };
51:
52: int pcagpio_match(struct device *, void *, void *);
53: void pcagpio_attach(struct device *, struct device *, void *);
54: int pcagpio_check(struct i2c_attach_args *, u_int8_t *, u_int8_t *);
55: void pcagpio_refresh(void *);
56:
57: int pcagpio_gpio_pin_read(void *, int);
58: void pcagpio_gpio_pin_write(void *, int, int);
59: void pcagpio_gpio_pin_ctl(void *, int, int);
60:
61: struct cfattach pcagpio_ca = {
62: sizeof(struct pcagpio_softc), pcagpio_match, pcagpio_attach
63: };
64:
65: struct cfdriver pcagpio_cd = {
66: NULL, "pcagpio", DV_DULL
67: };
68:
69: int
70: pcagpio_match(struct device *parent, void *match, void *aux)
71: {
72: struct i2c_attach_args *ia = aux;
73:
74: if (strcmp(ia->ia_name, "PCA9554") == 0 ||
75: strcmp(ia->ia_name, "PCA9554M") == 0 ||
76: strcmp(ia->ia_name, "pca9555") == 0 ||
77: strcmp(ia->ia_name, "pca9556") == 0 ||
78: strcmp(ia->ia_name, "pca9557") == 0)
79: return (1);
80: return (0);
81: }
82:
83: void
84: pcagpio_attach(struct device *parent, struct device *self, void *aux)
85: {
86: struct pcagpio_softc *sc = (struct pcagpio_softc *)self;
87: struct i2c_attach_args *ia = aux;
88: struct gpiobus_attach_args gba;
89: u_int8_t cmd, data;
90: int outputs = 0, i;
91:
92: sc->sc_tag = ia->ia_tag;
93: sc->sc_addr = ia->ia_addr;
94:
95: cmd = PCA9554_CONFIG;
96: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
97: sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
98: printf(": failed to initialize\n");
99: return;
100: }
101: sc->sc_control = data;
102: cmd = PCA9554_POLARITY;
103: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
104: sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
105: printf(": failed to initialize\n");
106: return;
107: }
108: sc->sc_polarity = data;
109: cmd = PCA9554_OUT;
110: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
111: sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
112: printf(": failed to initialize\n");
113: return;
114: }
115:
116: /* Initialize sensor data. */
117: strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
118: sizeof(sc->sc_sensordev.xname));
119:
120: for (i = 0; i < PCAGPIO_NPINS; i++) {
121: sc->sc_sensor[i].type = SENSOR_INDICATOR;
122: if ((sc->sc_control & (1 << i)) == 0) {
123: strlcpy(sc->sc_sensor[i].desc, "out",
124: sizeof(sc->sc_sensor[i].desc));
125: outputs++;
126: } else
127: strlcpy(sc->sc_sensor[i].desc, "in",
128: sizeof(sc->sc_sensor[i].desc));
129:
130: }
131:
132: if (sensor_task_register(sc, pcagpio_refresh, 5) == NULL) {
133: printf(", unable to register update task\n");
134: return;
135: }
136:
137: #if 0
138: for (i = 0; i < PCAGPIO_NPINS; i++)
139: sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
140: sensordev_install(&sc->sc_sensordev);
141: #endif
142:
143: printf(":");
144: if (PCAGPIO_NPINS - outputs)
145: printf(" %d inputs", PCAGPIO_NPINS - outputs);
146: if (outputs)
147: printf(" %d outputs", outputs);
148: printf("\n");
149:
150: for (i = 0; i < PCAGPIO_NPINS; i++) {
151: sc->sc_gpio_pins[i].pin_num = i;
152: sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
153:
154: if ((sc->sc_control & (1 << i)) == 0) {
155: sc->sc_gpio_pins[i].pin_flags = GPIO_PIN_OUTPUT;
156: sc->sc_gpio_pins[i].pin_state =
157: data & (1 << i) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
158: }
159: }
160:
161: /* Create controller tag */
162: sc->sc_gpio_gc.gp_cookie = sc;
163: sc->sc_gpio_gc.gp_pin_read = pcagpio_gpio_pin_read;
164: sc->sc_gpio_gc.gp_pin_write = pcagpio_gpio_pin_write;
165: sc->sc_gpio_gc.gp_pin_ctl = pcagpio_gpio_pin_ctl;
166:
167: gba.gba_name = "gpio";
168: gba.gba_gc = &sc->sc_gpio_gc;
169: gba.gba_pins = sc->sc_gpio_pins;
170: gba.gba_npins = PCAGPIO_NPINS;
171:
172: config_found(&sc->sc_dev, &gba, gpiobus_print);
173:
174: }
175:
176: void
177: pcagpio_refresh(void *arg)
178: {
179: struct pcagpio_softc *sc = arg;
180: u_int8_t cmd, in, out, bit;
181: int i;
182:
183: iic_acquire_bus(sc->sc_tag, 0);
184:
185: cmd = PCA9554_IN;
186: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
187: sc->sc_addr, &cmd, sizeof cmd, &in, sizeof in, 0))
188: goto invalid;
189:
190: cmd = PCA9554_OUT;
191: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
192: sc->sc_addr, &cmd, sizeof cmd, &out, sizeof out, 0))
193: goto invalid;
194:
195: for (i = 0; i < PCAGPIO_NPINS; i++) {
196: bit = 1 << i;
197: if ((sc->sc_control & bit))
198: sc->sc_sensor[i].value = (in & bit) ? 1 : 0;
199: else
200: sc->sc_sensor[i].value = (out & bit) ? 1 : 0;
201: }
202:
203: invalid:
204: iic_release_bus(sc->sc_tag, 0);
205: }
206:
207:
208: int
209: pcagpio_gpio_pin_read(void *arg, int pin)
210: {
211: struct pcagpio_softc *sc = arg;
212: u_int8_t cmd, in;
213:
214: cmd = PCA9554_IN;
215: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
216: sc->sc_addr, &cmd, sizeof cmd, &in, sizeof in, 0))
217: return 0;
218: return ((in ^ sc->sc_polarity) & (1 << pin)) ? 1 : 0;
219: }
220:
221: void
222: pcagpio_gpio_pin_write(void *arg, int pin, int value)
223: {
224: struct pcagpio_softc *sc = arg;
225: u_int8_t cmd, out, mask;
226:
227: mask = 0xff ^ (1 << pin);
228: cmd = PCA9554_OUT;
229: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
230: sc->sc_addr, &cmd, sizeof cmd, &out, sizeof out, 0))
231: return;
232: out = (out & mask) | (value << pin);
233:
234: cmd = PCA9554_OUT;
235: if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
236: sc->sc_addr, &cmd, sizeof cmd, &out, sizeof out, 0))
237: return;
238: }
239:
240: void
241: pcagpio_gpio_pin_ctl(void *arg, int pin, int flags)
242: {
243: #if 0
244: struct pcagpio_softc *sc = arg;
245: u_int32_t conf;
246:
247: pcagpio_gpio_pin_select(sc, pin);
248: conf = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh,
249: GSCGPIO_CONF);
250:
251: conf &= ~(GSCGPIO_CONF_OUTPUTEN | GSCGPIO_CONF_PUSHPULL |
252: GSCGPIO_CONF_PULLUP);
253: if ((flags & GPIO_PIN_TRISTATE) == 0)
254: conf |= GSCGPIO_CONF_OUTPUTEN;
255: if (flags & GPIO_PIN_PUSHPULL)
256: conf |= GSCGPIO_CONF_PUSHPULL;
257: if (flags & GPIO_PIN_PULLUP)
258: conf |= GSCGPIO_CONF_PULLUP;
259: bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh,
260: GSCGPIO_CONF, conf);
261: #endif
262: }
CVSweb