Sat Oct 31 14:39:31 2020 UTC ()
Detach led's and sysmon in our detach routine.


(jdc)
diff -r1.1 -r1.2 src/sys/dev/i2c/pcf8574.c

cvs diff -r1.1 -r1.2 src/sys/dev/i2c/pcf8574.c (switch to unified diff)

--- src/sys/dev/i2c/pcf8574.c 2020/10/29 06:55:51 1.1
+++ src/sys/dev/i2c/pcf8574.c 2020/10/31 14:39:31 1.2
@@ -1,328 +1,335 @@ @@ -1,328 +1,335 @@
1/*- 1/*-
2 * Copyright (c) 2020 The NetBSD Foundation, Inc. 2 * Copyright (c) 2020 The NetBSD Foundation, Inc.
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
5 * This code is derived from software contributed to The NetBSD Foundation 5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Julian Coleman. 6 * by Julian Coleman.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions 9 * modification, are permitted provided that the following conditions
10 * are met: 10 * are met:
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution. 15 * documentation and/or other materials provided with the distribution.
16 * 16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE. 27 * POSSIBILITY OF SUCH DAMAGE.
28 */ 28 */
29 29
30/* 30/*
31 * A driver for Philips Semiconductor (NXP) PCF8574/PCF857A GPIO's. 31 * A driver for Philips Semiconductor (NXP) PCF8574/PCF857A GPIO's.
32 * Uses device properties to connect pins to the appropriate subsystem. 32 * Uses device properties to connect pins to the appropriate subsystem.
33 */ 33 */
34 34
35#include <sys/cdefs.h> 35#include <sys/cdefs.h>
36__KERNEL_RCSID(0, "$NetBSD: pcf8574.c,v 1.1 2020/10/29 06:55:51 jdc Exp $"); 36__KERNEL_RCSID(0, "$NetBSD: pcf8574.c,v 1.2 2020/10/31 14:39:31 jdc Exp $");
37 37
38#include <sys/param.h> 38#include <sys/param.h>
39#include <sys/systm.h> 39#include <sys/systm.h>
40#include <sys/device.h> 40#include <sys/device.h>
41#include <sys/kernel.h> 41#include <sys/kernel.h>
42 42
43#include <dev/sysmon/sysmonvar.h> 43#include <dev/sysmon/sysmonvar.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 PCF8574_DEBUG 48#ifdef PCF8574_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
54struct pcf8574_led { 54struct pcf8574_led {
55 void *cookie; 55 void *cookie;
 56 struct led_device *led;
56 uint8_t mask, v_on, v_off; 57 uint8_t mask, v_on, v_off;
57}; 58};
58 59
59#define PCF8574_NPINS 8 60#define PCF8574_NPINS 8
60struct pcf8574_softc { 61struct pcf8574_softc {
61 device_t sc_dev; 62 device_t sc_dev;
62 i2c_tag_t sc_tag; 63 i2c_tag_t sc_tag;
63 i2c_addr_t sc_addr; 64 i2c_addr_t sc_addr;
64 uint8_t sc_state; 65 uint8_t sc_state;
65 uint8_t sc_mask; 66 uint8_t sc_mask;
66 67
67 int sc_nleds; 68 int sc_nleds;
68 struct pcf8574_led sc_leds[PCF8574_NPINS]; 69 struct pcf8574_led sc_leds[PCF8574_NPINS];
69 70
70 struct sysmon_envsys *sc_sme; 71 struct sysmon_envsys *sc_sme;
71 envsys_data_t sc_sensor[PCF8574_NPINS]; 72 envsys_data_t sc_sensor[PCF8574_NPINS];
72 int sc_pin_sensor[PCF8574_NPINS]; 73 int sc_pin_sensor[PCF8574_NPINS];
73 int sc_pin_active[PCF8574_NPINS]; 74 int sc_pin_active[PCF8574_NPINS];
74 75
75#ifdef PCF8574_DEBUG 76#ifdef PCF8574_DEBUG
76 callout_t sc_timer; 77 callout_t sc_timer;
77#endif 78#endif
78}; 79};
79 80
80static int pcf8574_match(device_t, cfdata_t, void *); 81static int pcf8574_match(device_t, cfdata_t, void *);
81static void pcf8574_attach(device_t, device_t, void *); 82static void pcf8574_attach(device_t, device_t, void *);
82static int pcf8574_detach(device_t, int); 83static int pcf8574_detach(device_t, int);
83 84
84static int pcf8574_read(struct pcf8574_softc *sc, uint8_t *val); 85static int pcf8574_read(struct pcf8574_softc *sc, uint8_t *val);
85static int pcf8574_write(struct pcf8574_softc *sc, uint8_t val); 86static int pcf8574_write(struct pcf8574_softc *sc, uint8_t val);
86static void pcf8574_attach_led( 87static void pcf8574_attach_led(
87 struct pcf8574_softc *, char *, int, int, int); 88 struct pcf8574_softc *, char *, int, int, int);
88void pcf8574_refresh(struct sysmon_envsys *, envsys_data_t *); 89void pcf8574_refresh(struct sysmon_envsys *, envsys_data_t *);
89int pcf8574_get_led(void *); 90int pcf8574_get_led(void *);
90void pcf8574_set_led(void *, int); 91void pcf8574_set_led(void *, int);
91 92
92#ifdef PCF8574_DEBUG 93#ifdef PCF8574_DEBUG
93static void pcf8574_timeout(void *); 94static void pcf8574_timeout(void *);
94#endif 95#endif
95 96
96CFATTACH_DECL_NEW(pcf8574io, sizeof(struct pcf8574_softc), 97CFATTACH_DECL_NEW(pcf8574io, sizeof(struct pcf8574_softc),
97 pcf8574_match, pcf8574_attach, pcf8574_detach, NULL); 98 pcf8574_match, pcf8574_attach, pcf8574_detach, NULL);
98 99
99static const struct device_compatible_entry compat_data[] = { 100static const struct device_compatible_entry compat_data[] = {
100 { "i2c-pcf8574", 0 }, 101 { "i2c-pcf8574", 0 },
101 { NULL, 0 } 102 { NULL, 0 }
102}; 103};
103 104
104static int 105static int
105pcf8574_match(device_t parent, cfdata_t cf, void *aux) 106pcf8574_match(device_t parent, cfdata_t cf, void *aux)
106{ 107{
107 struct i2c_attach_args *ia = aux; 108 struct i2c_attach_args *ia = aux;
108 int match_result; 109 int match_result;
109 110
110 if (iic_use_direct_match(ia, cf, compat_data, &match_result)) 111 if (iic_use_direct_match(ia, cf, compat_data, &match_result))
111 return match_result; 112 return match_result;
112 113
113 /* We don't support indirect matches */ 114 /* We don't support indirect matches */
114 return 0; 115 return 0;
115} 116}
116 117
117static void 118static void
118pcf8574_attach(device_t parent, device_t self, void *aux) 119pcf8574_attach(device_t parent, device_t self, void *aux)
119{ 120{
120 struct pcf8574_softc *sc = device_private(self); 121 struct pcf8574_softc *sc = device_private(self);
121 struct i2c_attach_args *ia = aux; 122 struct i2c_attach_args *ia = aux;
122 prop_dictionary_t dict = device_properties(self); 123 prop_dictionary_t dict = device_properties(self);
123 prop_array_t pins; 124 prop_array_t pins;
124 prop_dictionary_t pin; 125 prop_dictionary_t pin;
125 int i, num, def, envc = 0; 126 int i, num, def, envc = 0;
126 char name[32]; 127 char name[32];
127 const char *nptr = NULL, *spptr; 128 const char *nptr = NULL, *spptr;
128 bool ok = TRUE, act, sysmon = FALSE; 129 bool ok = TRUE, act, sysmon = FALSE;
129 130
130 sc->sc_tag = ia->ia_tag; 131 sc->sc_tag = ia->ia_tag;
131 sc->sc_addr = ia->ia_addr; 132 sc->sc_addr = ia->ia_addr;
132 sc->sc_dev = self; 133 sc->sc_dev = self;
133 134
134 /* 135 /*
135 * The PCF8574 requires input pins to be written with the value 1, 136 * The PCF8574 requires input pins to be written with the value 1,
136 * and then read. Assume that all pins are input initially. 137 * and then read. Assume that all pins are input initially.
137 * We'll use the mask when we write, because we have to write a 138 * We'll use the mask when we write, because we have to write a
138 * value for every pin, and we don't want to change input pins. 139 * value for every pin, and we don't want to change input pins.
139 */ 140 */
140 sc->sc_mask = 0xff; 141 sc->sc_mask = 0xff;
141 142
142 pcf8574_read(sc, &sc->sc_state); 143 pcf8574_read(sc, &sc->sc_state);
143 144
144#ifdef PCF8574_DEBUG 145#ifdef PCF8574_DEBUG
145 aprint_normal(": GPIO: state = 0x%02x\n", sc->sc_state); 146 aprint_normal(": GPIO: state = 0x%02x\n", sc->sc_state);
146 147
147 callout_init(&sc->sc_timer, CALLOUT_MPSAFE); 148 callout_init(&sc->sc_timer, CALLOUT_MPSAFE);
148 callout_reset(&sc->sc_timer, hz*30, pcf8574_timeout, sc); 149 callout_reset(&sc->sc_timer, hz*30, pcf8574_timeout, sc);
149#else 150#else
150 aprint_normal(": GPIO\n"); 151 aprint_normal(": GPIO\n");
151#endif 152#endif
152 153
153 pins = prop_dictionary_get(dict, "pins"); 154 pins = prop_dictionary_get(dict, "pins");
154 if (pins == NULL) 155 if (pins == NULL)
155 return; 156 return;
156 157
157 for (i = 0; i < prop_array_count(pins); i++) { 158 for (i = 0; i < prop_array_count(pins); i++) {
158 pin = prop_array_get(pins, i); 159 pin = prop_array_get(pins, i);
159 ok &= prop_dictionary_get_cstring_nocopy(pin, "name", &nptr); 160 ok &= prop_dictionary_get_cstring_nocopy(pin, "name", &nptr);
160 ok &= prop_dictionary_get_uint32(pin, "pin", &num); 161 ok &= prop_dictionary_get_uint32(pin, "pin", &num);
161 ok &= prop_dictionary_get_bool(pin, "active_high", &act); 162 ok &= prop_dictionary_get_bool(pin, "active_high", &act);
162 /* optional default state */ 163 /* optional default state */
163 def = -1; 164 def = -1;
164 prop_dictionary_get_int32(pin, "default_state", &def); 165 prop_dictionary_get_int32(pin, "default_state", &def);
165 if (!ok) 166 if (!ok)
166 continue; 167 continue;
167 /* Extract pin type from the name */ 168 /* Extract pin type from the name */
168 spptr = strstr(nptr, " "); 169 spptr = strstr(nptr, " ");
169 if (spptr == NULL) 170 if (spptr == NULL)
170 continue; 171 continue;
171 spptr += 1; 172 spptr += 1;
172 strncpy(name, spptr, 31); 173 strncpy(name, spptr, 31);
173 sc->sc_pin_active[i] = act; 174 sc->sc_pin_active[i] = act;
174 if (!strncmp(nptr, "LED ", 4)) { 175 if (!strncmp(nptr, "LED ", 4)) {
175 sc->sc_mask &= ~(1 << num); 176 sc->sc_mask &= ~(1 << num);
176 pcf8574_attach_led(sc, name, num, act, def); 177 pcf8574_attach_led(sc, name, num, act, def);
177 } 178 }
178 if (!strncmp(nptr, "INDICATOR ", 4)) { 179 if (!strncmp(nptr, "INDICATOR ", 4)) {
179 if (!sysmon) { 180 if (!sysmon) {
180 sc->sc_sme = sysmon_envsys_create(); 181 sc->sc_sme = sysmon_envsys_create();
181 sysmon = TRUE; 182 sysmon = TRUE;
182 } 183 }
183 /* envsys sensor # to pin # mapping */ 184 /* envsys sensor # to pin # mapping */
184 sc->sc_pin_sensor[envc] = num; 185 sc->sc_pin_sensor[envc] = num;
185 sc->sc_sensor[i].state = ENVSYS_SINVALID; 186 sc->sc_sensor[i].state = ENVSYS_SINVALID;
186 sc->sc_sensor[i].units = ENVSYS_INDICATOR; 187 sc->sc_sensor[i].units = ENVSYS_INDICATOR;
187 strlcpy(sc->sc_sensor[i].desc, name, 188 strlcpy(sc->sc_sensor[i].desc, name,
188 sizeof(sc->sc_sensor[i].desc)); 189 sizeof(sc->sc_sensor[i].desc));
189 if (sysmon_envsys_sensor_attach(sc->sc_sme, 190 if (sysmon_envsys_sensor_attach(sc->sc_sme,
190 &sc->sc_sensor[i])) { 191 &sc->sc_sensor[i])) {
191 sysmon_envsys_destroy(sc->sc_sme); 192 sysmon_envsys_destroy(sc->sc_sme);
192 aprint_error_dev(self, 193 aprint_error_dev(self,
193 "unable to attach pin %d at sysmon\n", i); 194 "unable to attach pin %d at sysmon\n", i);
194 return; 195 return;
195 } 196 }
196 DPRINTF("%s: added indicator: pin %d sensor %d (%s)\n", 197 DPRINTF("%s: added indicator: pin %d sensor %d (%s)\n",
197 device_xname(sc->sc_dev), num, envc, name); 198 device_xname(sc->sc_dev), num, envc, name);
198 envc++; 199 envc++;
199 } 200 }
200 } 201 }
201 202
202 if (sysmon) { 203 if (sysmon) {
203 sc->sc_sme->sme_name = device_xname(self); 204 sc->sc_sme->sme_name = device_xname(self);
204 sc->sc_sme->sme_cookie = sc; 205 sc->sc_sme->sme_cookie = sc;
205 sc->sc_sme->sme_refresh = pcf8574_refresh; 206 sc->sc_sme->sme_refresh = pcf8574_refresh;
206 if (sysmon_envsys_register(sc->sc_sme)) { 207 if (sysmon_envsys_register(sc->sc_sme)) {
207 aprint_error_dev(self, 208 aprint_error_dev(self,
208 "unable to register with sysmon\n"); 209 "unable to register with sysmon\n");
209 sysmon_envsys_destroy(sc->sc_sme); 210 sysmon_envsys_destroy(sc->sc_sme);
210 return; 211 return;
211 } 212 }
212 } 213 }
213} 214}
214 215
215static int 216static int
216pcf8574_detach(device_t self, int flags) 217pcf8574_detach(device_t self, int flags)
217{ 218{
218#ifdef PCF8574_DEBUG 
219 struct pcf8574_softc *sc = device_private(self); 219 struct pcf8574_softc *sc = device_private(self);
 220 int i;
 221
 222 if (sc->sc_sme != NULL)
 223 sysmon_envsys_unregister(sc->sc_sme);
 224
 225 for (i = 0; i < sc->sc_nleds; i++)
 226 led_detach(sc->sc_leds[i].led);
220 227
 228#ifdef PCF8574_DEBUG
221 callout_halt(&sc->sc_timer, NULL); 229 callout_halt(&sc->sc_timer, NULL);
222 callout_destroy(&sc->sc_timer); 230 callout_destroy(&sc->sc_timer);
223#endif 231#endif
224 
225 return 0; 232 return 0;
226} 233}
227 234
228static int 235static int
229pcf8574_read(struct pcf8574_softc *sc, uint8_t *val) 236pcf8574_read(struct pcf8574_softc *sc, uint8_t *val)
230{ 237{
231 int err = 0; 238 int err = 0;
232 239
233 if ((err = iic_acquire_bus(sc->sc_tag, 0)) != 0) 240 if ((err = iic_acquire_bus(sc->sc_tag, 0)) != 0)
234 return err; 241 return err;
235 err = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 242 err = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
236 sc->sc_addr, NULL, 0, val, 1, 0); 243 sc->sc_addr, NULL, 0, val, 1, 0);
237 iic_release_bus(sc->sc_tag, 0); 244 iic_release_bus(sc->sc_tag, 0);
238 return err; 245 return err;
239} 246}
240 247
241static int 248static int
242pcf8574_write(struct pcf8574_softc *sc, uint8_t val) 249pcf8574_write(struct pcf8574_softc *sc, uint8_t val)
243{ 250{
244 int err = 0; 251 int err = 0;
245 252
246 if ((err = iic_acquire_bus(sc->sc_tag, 0)) != 0) 253 if ((err = iic_acquire_bus(sc->sc_tag, 0)) != 0)
247 return err; 254 return err;
248 err = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 255 err = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
249 &val, 1, NULL, 0, 0); 256 &val, 1, NULL, 0, 0);
250 iic_release_bus(sc->sc_tag, 0); 257 iic_release_bus(sc->sc_tag, 0);
251 return err; 258 return err;
252} 259}
253 260
254static void 261static void
255pcf8574_attach_led(struct pcf8574_softc *sc, char *n, int pin, int act, int def) 262pcf8574_attach_led(struct pcf8574_softc *sc, char *n, int pin, int act, int def)
256{ 263{
257 struct pcf8574_led *l; 264 struct pcf8574_led *l;
258 265
259 l = &sc->sc_leds[sc->sc_nleds]; 266 l = &sc->sc_leds[sc->sc_nleds];
260 l->cookie = sc; 267 l->cookie = sc;
261 l->mask = 1 << pin; 268 l->mask = 1 << pin;
262 l->v_on = act ? l->mask : 0; 269 l->v_on = act ? l->mask : 0;
263 l->v_off = act ? 0 : l->mask; 270 l->v_off = act ? 0 : l->mask;
264 led_attach(n, l, pcf8574_get_led, pcf8574_set_led); 271 led_attach(n, l, pcf8574_get_led, pcf8574_set_led);
265 if (def != -1) 272 if (def != -1)
266 pcf8574_set_led(l, def); 273 pcf8574_set_led(l, def);
267 DPRINTF("%s: attached LED: %02x %02x %02x def %d\n", 274 DPRINTF("%s: attached LED: %02x %02x %02x def %d\n",
268 device_xname(sc->sc_dev), l->mask, l->v_on, l->v_off, def); 275 device_xname(sc->sc_dev), l->mask, l->v_on, l->v_off, def);
269 sc->sc_nleds++; 276 sc->sc_nleds++;
270} 277}
271 278
272void 279void
273pcf8574_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 280pcf8574_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
274{ 281{
275 struct pcf8574_softc *sc = sme->sme_cookie; 282 struct pcf8574_softc *sc = sme->sme_cookie;
276 int pin = sc->sc_pin_sensor[edata->sensor]; 283 int pin = sc->sc_pin_sensor[edata->sensor];
277 int act = sc->sc_pin_active[pin]; 284 int act = sc->sc_pin_active[pin];
278 285
279 pcf8574_read(sc, &sc->sc_state); 286 pcf8574_read(sc, &sc->sc_state);
280 if (act) 287 if (act)
281 edata->value_cur = sc->sc_state & 1 << pin ? TRUE : FALSE; 288 edata->value_cur = sc->sc_state & 1 << pin ? TRUE : FALSE;
282 else 289 else
283 edata->value_cur = sc->sc_state & 1 << pin ? FALSE : TRUE; 290 edata->value_cur = sc->sc_state & 1 << pin ? FALSE : TRUE;
284 edata->state = ENVSYS_SVALID; 291 edata->state = ENVSYS_SVALID;
285} 292}
286 293
287int 294int
288pcf8574_get_led(void *cookie) 295pcf8574_get_led(void *cookie)
289{ 296{
290 struct pcf8574_led *l = cookie; 297 struct pcf8574_led *l = cookie;
291 struct pcf8574_softc *sc = l->cookie; 298 struct pcf8574_softc *sc = l->cookie;
292 299
293 return ((sc->sc_state & l->mask) == l->v_on); 300 return ((sc->sc_state & l->mask) == l->v_on);
294} 301}
295 302
296void 303void
297pcf8574_set_led(void *cookie, int val) 304pcf8574_set_led(void *cookie, int val)
298{ 305{
299 struct pcf8574_led *l = cookie; 306 struct pcf8574_led *l = cookie;
300 struct pcf8574_softc *sc = l->cookie; 307 struct pcf8574_softc *sc = l->cookie;
301 uint32_t newstate;  308 uint32_t newstate;
302 309
303 newstate = sc->sc_state & ~l->mask; 310 newstate = sc->sc_state & ~l->mask;
304 newstate |= val ? l->v_on : l->v_off; 311 newstate |= val ? l->v_on : l->v_off;
305 DPRINTF("%s: set LED: %02x -> %02x, %02x %02x %02x\n", 312 DPRINTF("%s: set LED: %02x -> %02x, %02x %02x %02x\n",
306 device_xname(sc->sc_dev), sc->sc_state, newstate, l->mask, l->v_on, l->v_off); 313 device_xname(sc->sc_dev), sc->sc_state, newstate, l->mask, l->v_on, l->v_off);
307 if (newstate != sc->sc_state) { 314 if (newstate != sc->sc_state) {
308 pcf8574_write(sc, newstate | sc->sc_mask); 315 pcf8574_write(sc, newstate | sc->sc_mask);
309 pcf8574_read(sc, &sc->sc_state); 316 pcf8574_read(sc, &sc->sc_state);
310 } 317 }
311} 318}
312 319
313#ifdef PCF8574_DEBUG 320#ifdef PCF8574_DEBUG
314static void 321static void
315pcf8574_timeout(void *v) 322pcf8574_timeout(void *v)
316{ 323{
317 struct pcf8574_softc *sc = v; 324 struct pcf8574_softc *sc = v;
318 uint8_t val; 325 uint8_t val;
319 326
320 pcf8574_read(sc, &val); 327 pcf8574_read(sc, &val);
321 if (val != sc->sc_state) 328 if (val != sc->sc_state)
322 aprint_normal_dev(sc->sc_dev, 329 aprint_normal_dev(sc->sc_dev,
323 "status change: 0x%02x > 0x%02x\n", sc->sc_state, val); 330 "status change: 0x%02x > 0x%02x\n", sc->sc_state, val);
324 sc->sc_state = val; 331 sc->sc_state = val;
325 332
326 callout_reset(&sc->sc_timer, hz*60, pcf8574_timeout, sc); 333 callout_reset(&sc->sc_timer, hz*60, pcf8574_timeout, sc);
327} 334}
328#endif 335#endif