Thu Oct 29 06:50:53 2020 UTC ()
Handle the change in the sparc64 OFW patching, where we now encode the
GPIO pin type in the pin name (only LED types are currently handled).


(jdc)
diff -r1.4 -r1.5 src/sys/dev/i2c/pcagpio.c

cvs diff -r1.4 -r1.5 src/sys/dev/i2c/pcagpio.c (switch to unified diff)

--- src/sys/dev/i2c/pcagpio.c 2020/10/27 20:13:21 1.4
+++ src/sys/dev/i2c/pcagpio.c 2020/10/29 06:50:53 1.5
@@ -1,337 +1,343 @@ @@ -1,337 +1,343 @@
1/* $NetBSD: pcagpio.c,v 1.4 2020/10/27 20:13:21 jdc Exp $ */ 1/* $NetBSD: pcagpio.c,v 1.5 2020/10/29 06:50:53 jdc Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2020 Michael Lorenz 4 * Copyright (c) 2020 Michael Lorenz
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29/* 29/*
30 * a driver for Philips Semiconductor PCA9555 GPIO controllers 30 * a driver for Philips Semiconductor PCA9555 GPIO controllers
31 */ 31 */
32 32
33#include <sys/cdefs.h> 33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: pcagpio.c,v 1.4 2020/10/27 20:13:21 jdc Exp $"); 34__KERNEL_RCSID(0, "$NetBSD: pcagpio.c,v 1.5 2020/10/29 06:50:53 jdc Exp $");
35 35
36#include <sys/param.h> 36#include <sys/param.h>
37#include <sys/systm.h> 37#include <sys/systm.h>
38#include <sys/device.h> 38#include <sys/device.h>
39#ifdef PCAGPIO_DEBUG 39#ifdef PCAGPIO_DEBUG
40#include <sys/kernel.h> 40#include <sys/kernel.h>
41#endif 41#endif
42#include <sys/conf.h> 42#include <sys/conf.h>
43#include <sys/bus.h> 43#include <sys/bus.h>
44 44
45#include <dev/i2c/i2cvar.h> 45#include <dev/i2c/i2cvar.h>
46#include <dev/led.h> 46#include <dev/led.h>
47 47
48#ifdef PCAGPIO_DEBUG 48#ifdef PCAGPIO_DEBUG
49#define DPRINTF printf 49#define DPRINTF printf
50#else 50#else
51#define DPRINTF if (0) printf 51#define DPRINTF if (0) printf
52#endif 52#endif
53 53
54/* commands */ 54/* commands */
55#define PCAGPIO_INPUT 0x00 /* line status */ 55#define PCAGPIO_INPUT 0x00 /* line status */
56#define PCAGPIO_OUTPUT 0x01 /* output status */ 56#define PCAGPIO_OUTPUT 0x01 /* output status */
57#define PCAGPIO_REVERT 0x02 /* revert input if set */ 57#define PCAGPIO_REVERT 0x02 /* revert input if set */
58#define PCAGPIO_CONFIG 0x03 /* input if set, output if not */ 58#define PCAGPIO_CONFIG 0x03 /* input if set, output if not */
59 59
60static int pcagpio_match(device_t, cfdata_t, void *); 60static int pcagpio_match(device_t, cfdata_t, void *);
61static void pcagpio_attach(device_t, device_t, void *); 61static void pcagpio_attach(device_t, device_t, void *);
62static int pcagpio_detach(device_t, int); 62static int pcagpio_detach(device_t, int);
63#ifdef PCAGPIO_DEBUG 63#ifdef PCAGPIO_DEBUG
64static void pcagpio_timeout(void *); 64static void pcagpio_timeout(void *);
65#endif 65#endif
66 66
67/* we can only pass one cookie to led_attach() but we need several values... */ 67/* we can only pass one cookie to led_attach() but we need several values... */
68struct pcagpio_led { 68struct pcagpio_led {
69 void *cookie; 69 void *cookie;
70 uint32_t mask, v_on, v_off; 70 uint32_t mask, v_on, v_off;
71}; 71};
72 72
73struct pcagpio_softc { 73struct pcagpio_softc {
74 device_t sc_dev; 74 device_t sc_dev;
75 i2c_tag_t sc_i2c; 75 i2c_tag_t sc_i2c;
76 i2c_addr_t sc_addr; 76 i2c_addr_t sc_addr;
77 77
78 int sc_is_16bit; 78 int sc_is_16bit;
79 uint32_t sc_state; 79 uint32_t sc_state;
80 struct pcagpio_led sc_leds[16]; 80 struct pcagpio_led sc_leds[16];
81 int sc_nleds; 81 int sc_nleds;
82 82
83#ifdef PCAGPIO_DEBUG 83#ifdef PCAGPIO_DEBUG
84 uint32_t sc_dir, sc_in; 84 uint32_t sc_dir, sc_in;
85 callout_t sc_timer; 85 callout_t sc_timer;
86#endif 86#endif
87}; 87};
88 88
89 89
90static void pcagpio_writereg(struct pcagpio_softc *, int, uint32_t); 90static void pcagpio_writereg(struct pcagpio_softc *, int, uint32_t);
91static uint32_t pcagpio_readreg(struct pcagpio_softc *, int); 91static uint32_t pcagpio_readreg(struct pcagpio_softc *, int);
92static void pcagpio_attach_led( 92static void pcagpio_attach_led(
93 struct pcagpio_softc *, char *, int, int, int); 93 struct pcagpio_softc *, char *, int, int, int);
94static int pcagpio_get(void *); 94static int pcagpio_get(void *);
95static void pcagpio_set(void *, int); 95static void pcagpio_set(void *, int);
96 96
97CFATTACH_DECL_NEW(pcagpio, sizeof(struct pcagpio_softc), 97CFATTACH_DECL_NEW(pcagpio, sizeof(struct pcagpio_softc),
98 pcagpio_match, pcagpio_attach, pcagpio_detach, NULL); 98 pcagpio_match, pcagpio_attach, pcagpio_detach, NULL);
99 99
100static const struct device_compatible_entry compat_data[] = { 100static const struct device_compatible_entry compat_data[] = {
101 { "i2c-pca9555", 1 }, 101 { "i2c-pca9555", 1 },
102 { "pca9555", 1 }, 102 { "pca9555", 1 },
103 { "i2c-pca9556", 0 }, 103 { "i2c-pca9556", 0 },
104 { "pca9556", 0 }, 104 { "pca9556", 0 },
105 { NULL, 0 } 105 { NULL, 0 }
106}; 106};
107 107
108static int 108static int
109pcagpio_match(device_t parent, cfdata_t match, void *aux) 109pcagpio_match(device_t parent, cfdata_t match, void *aux)
110{ 110{
111 struct i2c_attach_args *ia = aux; 111 struct i2c_attach_args *ia = aux;
112 int match_result; 112 int match_result;
113 113
114 if (iic_use_direct_match(ia, match, compat_data, &match_result)) 114 if (iic_use_direct_match(ia, match, compat_data, &match_result))
115 return match_result; 115 return match_result;
116 116
117 return 0; 117 return 0;
118} 118}
119 119
120#ifdef PCAGPIO_DEBUG 120#ifdef PCAGPIO_DEBUG
121static void 121static void
122printdir(char* name, uint32_t val, uint32_t mask, char letter) 122printdir(char* name, uint32_t val, uint32_t mask, char letter)
123{ 123{
124 char flags[17], bits[17]; 124 char flags[17], bits[17];
125 uint32_t bit = 0x8000; 125 uint32_t bit = 0x8000;
126 int i; 126 int i;
127 127
128 val &= mask; 128 val &= mask;
129 for (i = 0; i < 16; i++) { 129 for (i = 0; i < 16; i++) {
130 flags[i] = (mask & bit) ? letter : '-'; 130 flags[i] = (mask & bit) ? letter : '-';
131 bits[i] = (val & bit) ? 'X' : ' '; 131 bits[i] = (val & bit) ? 'X' : ' ';
132 bit = bit >> 1; 132 bit = bit >> 1;
133 } 133 }
134 flags[16] = 0; 134 flags[16] = 0;
135 bits[16] = 0; 135 bits[16] = 0;
136 printf("%s: dir: %s\n", name, flags); 136 printf("%s: dir: %s\n", name, flags);
137 printf("%s: lvl: %s\n", name, bits); 137 printf("%s: lvl: %s\n", name, bits);
138}  138}
139#endif 139#endif
140 140
141static void 141static void
142pcagpio_attach(device_t parent, device_t self, void *aux) 142pcagpio_attach(device_t parent, device_t self, void *aux)
143{ 143{
144 struct pcagpio_softc *sc = device_private(self); 144 struct pcagpio_softc *sc = device_private(self);
145 struct i2c_attach_args *ia = aux; 145 struct i2c_attach_args *ia = aux;
146 const struct device_compatible_entry *dce; 146 const struct device_compatible_entry *dce;
147 prop_dictionary_t dict = device_properties(self); 147 prop_dictionary_t dict = device_properties(self);
148 prop_array_t pins; 148 prop_array_t pins;
149 prop_dictionary_t pin; 149 prop_dictionary_t pin;
150 150
151 sc->sc_dev = self; 151 sc->sc_dev = self;
152 sc->sc_i2c = ia->ia_tag; 152 sc->sc_i2c = ia->ia_tag;
153 sc->sc_addr = ia->ia_addr; 153 sc->sc_addr = ia->ia_addr;
154 sc->sc_nleds = 0; 154 sc->sc_nleds = 0;
155 155
156 aprint_naive("\n"); 156 aprint_naive("\n");
157 sc->sc_is_16bit = 0; 157 sc->sc_is_16bit = 0;
158 if (iic_compatible_match(ia, compat_data, &dce)) 158 if (iic_compatible_match(ia, compat_data, &dce))
159 sc->sc_is_16bit = dce->data; 159 sc->sc_is_16bit = dce->data;
160 160
161 aprint_normal(": %s\n", sc->sc_is_16bit ? "PCA9555" : "PCA9556"); 161 aprint_normal(": %s\n", sc->sc_is_16bit ? "PCA9555" : "PCA9556");
162 162
163 sc->sc_state = pcagpio_readreg(sc, PCAGPIO_OUTPUT); 163 sc->sc_state = pcagpio_readreg(sc, PCAGPIO_OUTPUT);
164 164
165#ifdef PCAGPIO_DEBUG 165#ifdef PCAGPIO_DEBUG
166 uint32_t in, out; 166 uint32_t in, out;
167 sc->sc_dir = pcagpio_readreg(sc, PCAGPIO_CONFIG); 167 sc->sc_dir = pcagpio_readreg(sc, PCAGPIO_CONFIG);
168 sc->sc_in = pcagpio_readreg(sc, PCAGPIO_INPUT); 168 sc->sc_in = pcagpio_readreg(sc, PCAGPIO_INPUT);
169 in = sc-> sc_in; 169 in = sc-> sc_in;
170 out = sc->sc_state; 170 out = sc->sc_state;
171 171
172 out &= ~sc->sc_dir; 172 out &= ~sc->sc_dir;
173 in &= sc->sc_dir; 173 in &= sc->sc_dir;
174  174
175 printdir(sc->sc_dev->dv_xname, in, sc->sc_dir, 'I'); 175 printdir(sc->sc_dev->dv_xname, in, sc->sc_dir, 'I');
176 printdir(sc->sc_dev->dv_xname, out, ~sc->sc_dir, 'O'); 176 printdir(sc->sc_dev->dv_xname, out, ~sc->sc_dir, 'O');
177 177
178 callout_init(&sc->sc_timer, CALLOUT_MPSAFE); 178 callout_init(&sc->sc_timer, CALLOUT_MPSAFE);
179 callout_reset(&sc->sc_timer, hz*20, pcagpio_timeout, sc); 179 callout_reset(&sc->sc_timer, hz*20, pcagpio_timeout, sc);
180 180
181#endif 181#endif
182 182
183 pins = prop_dictionary_get(dict, "pins"); 183 pins = prop_dictionary_get(dict, "pins");
184 if (pins != NULL) { 184 if (pins != NULL) {
185 int i, num, def; 185 int i, num, def;
186 char name[32]; 186 char name[32];
187 const char *nptr; 187 const char *spptr, *nptr;
188 bool ok = TRUE, act; 188 bool ok = TRUE, act;
189 189
190 for (i = 0; i < prop_array_count(pins); i++) { 190 for (i = 0; i < prop_array_count(pins); i++) {
191 nptr = NULL; 191 nptr = NULL;
192 pin = prop_array_get(pins, i); 192 pin = prop_array_get(pins, i);
193 ok &= prop_dictionary_get_cstring_nocopy(pin, "name", 193 ok &= prop_dictionary_get_cstring_nocopy(pin, "name",
194 &nptr); 194 &nptr);
195 strncpy(name, nptr, 31); 
196 ok &= prop_dictionary_get_uint32(pin, "pin", &num); 195 ok &= prop_dictionary_get_uint32(pin, "pin", &num);
197 ok &= prop_dictionary_get_bool( 196 ok &= prop_dictionary_get_bool( pin, "active_high",
198 pin, "active_high", &act); 197 &act);
199 /* optional default state */ 198 /* optional default state */
200 def = -1; 199 def = -1;
201 prop_dictionary_get_int32(pin, "default_state", &def); 200 prop_dictionary_get_int32(pin, "default_state", &def);
202 if (ok) {  201 if (!ok)
 202 continue;
 203 /* Extract pin type from the name */
 204 spptr = strstr(nptr, " ");
 205 if (spptr == NULL)
 206 continue;
 207 spptr += 1;
 208 strncpy(name, spptr, 31);
 209 if (!strncmp(nptr, "LED ", 4))
203 pcagpio_attach_led(sc, name, num, act, def); 210 pcagpio_attach_led(sc, name, num, act, def);
204 } 
205 } 211 }
206 } 212 }
207} 213}
208 214
209static int 215static int
210pcagpio_detach(device_t self, int flags) 216pcagpio_detach(device_t self, int flags)
211{ 217{
212#ifdef PCAGPIO_DEBUG 218#ifdef PCAGPIO_DEBUG
213 struct pcagpio_softc *sc = device_private(self); 219 struct pcagpio_softc *sc = device_private(self);
214 220
215 callout_halt(&sc->sc_timer, NULL); 221 callout_halt(&sc->sc_timer, NULL);
216 callout_destroy(&sc->sc_timer); 222 callout_destroy(&sc->sc_timer);
217#endif 223#endif
218 224
219 return 0; 225 return 0;
220} 226}
221 227
222#ifdef PCAGPIO_DEBUG 228#ifdef PCAGPIO_DEBUG
223static void 229static void
224pcagpio_timeout(void *v) 230pcagpio_timeout(void *v)
225{ 231{
226 struct pcagpio_softc *sc = v; 232 struct pcagpio_softc *sc = v;
227 uint32_t out, dir, in, o_out, o_in; 233 uint32_t out, dir, in, o_out, o_in;
228 234
229 out = pcagpio_readreg(sc, PCAGPIO_OUTPUT); 235 out = pcagpio_readreg(sc, PCAGPIO_OUTPUT);
230 dir = pcagpio_readreg(sc, PCAGPIO_CONFIG); 236 dir = pcagpio_readreg(sc, PCAGPIO_CONFIG);
231 in = pcagpio_readreg(sc, PCAGPIO_INPUT); 237 in = pcagpio_readreg(sc, PCAGPIO_INPUT);
232 if (out != sc->sc_state || dir != sc->sc_dir || in != sc->sc_in) { 238 if (out != sc->sc_state || dir != sc->sc_dir || in != sc->sc_in) {
233 aprint_normal_dev(sc->sc_dev, "status change\n"); 239 aprint_normal_dev(sc->sc_dev, "status change\n");
234 o_out = sc->sc_state; 240 o_out = sc->sc_state;
235 o_in = sc->sc_in; 241 o_in = sc->sc_in;
236 o_out &= ~sc->sc_dir; 242 o_out &= ~sc->sc_dir;
237 o_in &= sc->sc_dir; 243 o_in &= sc->sc_dir;
238 printdir(sc->sc_dev->dv_xname, o_in, sc->sc_dir, 'I'); 244 printdir(sc->sc_dev->dv_xname, o_in, sc->sc_dir, 'I');
239 printdir(sc->sc_dev->dv_xname, o_out, ~sc->sc_dir, 'O'); 245 printdir(sc->sc_dev->dv_xname, o_out, ~sc->sc_dir, 'O');
240 sc->sc_state = out; 246 sc->sc_state = out;
241 sc->sc_dir = dir; 247 sc->sc_dir = dir;
242 sc->sc_in = in; 248 sc->sc_in = in;
243 out &= ~sc->sc_dir; 249 out &= ~sc->sc_dir;
244 in &= sc->sc_dir; 250 in &= sc->sc_dir;
245 printdir(sc->sc_dev->dv_xname, in, sc->sc_dir, 'I'); 251 printdir(sc->sc_dev->dv_xname, in, sc->sc_dir, 'I');
246 printdir(sc->sc_dev->dv_xname, out, ~sc->sc_dir, 'O'); 252 printdir(sc->sc_dev->dv_xname, out, ~sc->sc_dir, 'O');
247 } 253 }
248 callout_reset(&sc->sc_timer, hz*60, pcagpio_timeout, sc); 254 callout_reset(&sc->sc_timer, hz*60, pcagpio_timeout, sc);
249} 255}
250#endif 256#endif
251 257
252static void 258static void
253pcagpio_writereg(struct pcagpio_softc *sc, int reg, uint32_t val) 259pcagpio_writereg(struct pcagpio_softc *sc, int reg, uint32_t val)
254{ 260{
255 uint8_t cmd; 261 uint8_t cmd;
256 262
257 iic_acquire_bus(sc->sc_i2c, 0); 263 iic_acquire_bus(sc->sc_i2c, 0);
258 if (sc->sc_is_16bit) { 264 if (sc->sc_is_16bit) {
259 uint16_t creg; 265 uint16_t creg;
260 cmd = reg << 1; 266 cmd = reg << 1;
261 creg = htole16(val); 267 creg = htole16(val);
262 iic_exec(sc->sc_i2c, I2C_OP_WRITE_WITH_STOP, 268 iic_exec(sc->sc_i2c, I2C_OP_WRITE_WITH_STOP,
263 sc->sc_addr, &cmd, 1, &creg, 2, 0); 269 sc->sc_addr, &cmd, 1, &creg, 2, 0);
264 } else { 270 } else {
265 uint8_t creg; 271 uint8_t creg;
266 cmd = reg; 272 cmd = reg;
267 creg = (uint8_t)val; 273 creg = (uint8_t)val;
268 iic_exec(sc->sc_i2c, I2C_OP_WRITE_WITH_STOP, 274 iic_exec(sc->sc_i2c, I2C_OP_WRITE_WITH_STOP,
269 sc->sc_addr, &cmd, 1, &creg, 1, 0); 275 sc->sc_addr, &cmd, 1, &creg, 1, 0);
270 } 276 }
271 if (reg == PCAGPIO_OUTPUT) sc->sc_state = val; 277 if (reg == PCAGPIO_OUTPUT) sc->sc_state = val;
272 iic_release_bus(sc->sc_i2c, 0); 278 iic_release_bus(sc->sc_i2c, 0);
273}  279}
274 280
275static uint32_t pcagpio_readreg(struct pcagpio_softc *sc, int reg) 281static uint32_t pcagpio_readreg(struct pcagpio_softc *sc, int reg)
276{ 282{
277 uint8_t cmd; 283 uint8_t cmd;
278 uint32_t ret; 284 uint32_t ret;
279 285
280 iic_acquire_bus(sc->sc_i2c, 0); 286 iic_acquire_bus(sc->sc_i2c, 0);
281 if (sc->sc_is_16bit) { 287 if (sc->sc_is_16bit) {
282 uint16_t creg; 288 uint16_t creg;
283 cmd = reg << 1; 289 cmd = reg << 1;
284 iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP, 290 iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP,
285 sc->sc_addr, &cmd, 1, &creg, 2, 0); 291 sc->sc_addr, &cmd, 1, &creg, 2, 0);
286 ret = le16toh(creg); 292 ret = le16toh(creg);
287 } else { 293 } else {
288 uint8_t creg; 294 uint8_t creg;
289 cmd = reg; 295 cmd = reg;
290 iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP, 296 iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP,
291 sc->sc_addr, &cmd, 1, &creg, 1, 0); 297 sc->sc_addr, &cmd, 1, &creg, 1, 0);
292 ret = creg; 298 ret = creg;
293 } 299 }
294 iic_release_bus(sc->sc_i2c, 0); 300 iic_release_bus(sc->sc_i2c, 0);
295 return ret; 301 return ret;
296} 302}
297 303
298static void 304static void
299pcagpio_attach_led(struct pcagpio_softc *sc, char *n, int pin, int act, int def) 305pcagpio_attach_led(struct pcagpio_softc *sc, char *n, int pin, int act, int def)
300{ 306{
301 struct pcagpio_led *l; 307 struct pcagpio_led *l;
302 308
303 l = &sc->sc_leds[sc->sc_nleds]; 309 l = &sc->sc_leds[sc->sc_nleds];
304 l->cookie = sc; 310 l->cookie = sc;
305 l->mask = 1 << pin; 311 l->mask = 1 << pin;
306 l->v_on = act ? l->mask : 0; 312 l->v_on = act ? l->mask : 0;
307 l->v_off = act ? 0 : l->mask; 313 l->v_off = act ? 0 : l->mask;
308 led_attach(n, l, pcagpio_get, pcagpio_set); 314 led_attach(n, l, pcagpio_get, pcagpio_set);
309 if (def != -1) pcagpio_set(l, def); 315 if (def != -1) pcagpio_set(l, def);
310 DPRINTF("%s: %04x %04x %04x def %d\n", 316 DPRINTF("%s: %04x %04x %04x def %d\n",
311 __func__, l->mask, l->v_on, l->v_off, def); 317 __func__, l->mask, l->v_on, l->v_off, def);
312 sc->sc_nleds++; 318 sc->sc_nleds++;
313} 319}
314 320
315static int 321static int
316pcagpio_get(void *cookie) 322pcagpio_get(void *cookie)
317{ 323{
318 struct pcagpio_led *l = cookie; 324 struct pcagpio_led *l = cookie;
319 struct pcagpio_softc *sc = l->cookie; 325 struct pcagpio_softc *sc = l->cookie;
320 326
321 return ((sc->sc_state & l->mask) == l->v_on); 327 return ((sc->sc_state & l->mask) == l->v_on);
322} 328}
323 329
324static void 330static void
325pcagpio_set(void *cookie, int val) 331pcagpio_set(void *cookie, int val)
326{ 332{
327 struct pcagpio_led *l = cookie; 333 struct pcagpio_led *l = cookie;
328 struct pcagpio_softc *sc = l->cookie; 334 struct pcagpio_softc *sc = l->cookie;
329 uint32_t newstate;  335 uint32_t newstate;
330 336
331 newstate = sc->sc_state & ~l->mask; 337 newstate = sc->sc_state & ~l->mask;
332 newstate |= val ? l->v_on : l->v_off; 338 newstate |= val ? l->v_on : l->v_off;
333 DPRINTF("%s: %04x -> %04x, %04x %04x %04x\n", __func__, 339 DPRINTF("%s: %04x -> %04x, %04x %04x %04x\n", __func__,
334 sc->sc_state, newstate, l->mask, l->v_on, l->v_off); 340 sc->sc_state, newstate, l->mask, l->v_on, l->v_off);
335 if (newstate != sc->sc_state) 341 if (newstate != sc->sc_state)
336 pcagpio_writereg(sc, PCAGPIO_OUTPUT, newstate); 342 pcagpio_writereg(sc, PCAGPIO_OUTPUT, newstate);
337} 343}