1 /*        $NetBSD: w83795g.c,v 1.6 2024/02/11 09:20:08 andvar Exp $   */
2 
3 /*
4  * Copyright (c) 2013 Soren S. Jorvang.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions, and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: w83795g.c,v 1.6 2024/02/11 09:20:08 andvar Exp $");
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/device.h>
34 #include <sys/conf.h>
35 #include <sys/gpio.h>
36 #include <sys/wdog.h>
37 
38 #include <dev/i2c/i2cvar.h>
39 #include <dev/gpio/gpiovar.h>
40 #include <dev/sysmon/sysmonvar.h>
41 
42 #include <dev/i2c/w83795greg.h>
43 
44 #define NUM_SENSORS 53
45 static const struct w83795g_sensor {
46           const char *desc;
47           enum envsys_units type;
48           uint8_t en_reg;
49           uint8_t en_mask;
50           uint8_t en_bits;
51           uint8_t msb;
52 } sensors[NUM_SENSORS] = {
53 #define _VOLT ENVSYS_SVOLTS_DC
54           { "VSEN1",   _VOLT, W83795G_V_CTRL1, 0x01, 0x01, W83795G_VSEN1 },
55           { "VSEN2",   _VOLT, W83795G_V_CTRL1, 0x02, 0x02, W83795G_VSEN2 },
56           { "VSEN3",   _VOLT, W83795G_V_CTRL1, 0x04, 0x04, W83795G_VSEN3 },
57           { "VSEN4",   _VOLT, W83795G_V_CTRL1, 0x08, 0x08, W83795G_VSEN4 },
58           { "VSEN5",   _VOLT, W83795G_V_CTRL1, 0x10, 0x10, W83795G_VSEN5 },
59           { "VSEN6",   _VOLT, W83795G_V_CTRL1, 0x20, 0x20, W83795G_VSEN6 },
60           { "VSEN7",   _VOLT, W83795G_V_CTRL1, 0x40, 0x40, W83795G_VSEN7 },
61           { "VSEN8",   _VOLT, W83795G_V_CTRL1, 0x80, 0x80, W83795G_VSEN8 },
62           { "VSEN9",   _VOLT, W83795G_V_CTRL2, 0x01, 0x01, W83795G_VSEN9 },
63           { "VSEN10",  _VOLT, W83795G_V_CTRL2, 0x02, 0x02, W83795G_VSEN10 },
64           { "VSEN11",  _VOLT, W83795G_V_CTRL2, 0x04, 0x04, W83795G_VSEN11 },
65           { "VTT",     _VOLT, W83795G_V_CTRL2, 0x08, 0x08, W83795G_VTT },
66           { "3VDD",    _VOLT, W83795G_V_CTRL2, 0x10, 0x10, W83795G_3VDD },
67           { "3VSB",    _VOLT, W83795G_V_CTRL2, 0x20, 0x20, W83795G_3VSB },
68           { "VBAT",    _VOLT, W83795G_V_CTRL2, 0x40, 0x40, W83795G_VBAT },
69           { "VSEN12",  _VOLT, W83795G_T_CTRL1, 0x03, 0x02, W83795G_VSEN12 },
70           { "VSEN13",  _VOLT, W83795G_T_CTRL1, 0x0c, 0x08, W83795G_VSEN13 },
71           { "VDSEN14", _VOLT, W83795G_T_CTRL2, 0x03, 0x02, W83795G_VDSEN14 },
72           { "VDSEN15", _VOLT, W83795G_T_CTRL2, 0x0c, 0x08, W83795G_VDSEN15 },
73           { "VDSEN16", _VOLT, W83795G_T_CTRL2, 0x30, 0x20, W83795G_VDSEN16 },
74           { "VDSEN17", _VOLT, W83795G_T_CTRL2, 0xc0, 0x80, W83795G_VDSEN17 },
75 #define _TEMP ENVSYS_STEMP
76           { "TR5",     _TEMP, W83795G_T_CTRL1, 0x03, 0x03, W83795G_TR5 },
77           { "TR6",     _TEMP, W83795G_T_CTRL1, 0x0c, 0x0c, W83795G_TR6 },
78           { "TD1",     _TEMP, W83795G_T_CTRL2, 0x03, 0x01, W83795G_TD1 },
79           { "TD2",     _TEMP, W83795G_T_CTRL2, 0x0c, 0x04, W83795G_TD2 },
80           { "TD3",     _TEMP, W83795G_T_CTRL2, 0x30, 0x10, W83795G_TD3 },
81           { "TD4",     _TEMP, W83795G_T_CTRL2, 0xc0, 0x40, W83795G_TD4 },
82           { "TR1",     _TEMP, W83795G_T_CTRL2, 0x03, 0x03, W83795G_TR1 },
83           { "TR2",     _TEMP, W83795G_T_CTRL2, 0x0c, 0x0c, W83795G_TR2 },
84           { "TR3",     _TEMP, W83795G_T_CTRL2, 0x30, 0x30, W83795G_TR3 },
85           { "TR4",     _TEMP, W83795G_T_CTRL2, 0xc0, 0xc0, W83795G_TR4 },
86           { "DTS1",    _TEMP, W83795G_T_CTRL1, 0x20, 0x20, W83795G_DTS1 },
87           { "DTS2",    _TEMP, W83795G_T_CTRL1, 0x20, 0x20, W83795G_DTS2 },
88           { "DTS3",    _TEMP, W83795G_T_CTRL1, 0x20, 0x20, W83795G_DTS3 },
89           { "DTS4",    _TEMP, W83795G_T_CTRL1, 0x20, 0x20, W83795G_DTS4 },
90           { "DTS5",    _TEMP, W83795G_T_CTRL1, 0x20, 0x20, W83795G_DTS5 },
91           { "DTS6",    _TEMP, W83795G_T_CTRL1, 0x20, 0x20, W83795G_DTS6 },
92           { "DTS7",    _TEMP, W83795G_T_CTRL1, 0x20, 0x20, W83795G_DTS7 },
93           { "DTS8",    _TEMP, W83795G_T_CTRL1, 0x20, 0x20, W83795G_DTS8 },
94 #define _FAN ENVSYS_SFANRPM
95           { "FANIN1",  _FAN,  W83795G_F_CTRL1, 0x01, 0x01, W83795G_FANIN1 },
96           { "FANIN2",  _FAN,  W83795G_F_CTRL1, 0x02, 0x02, W83795G_FANIN2 },
97           { "FANIN3",  _FAN,  W83795G_F_CTRL1, 0x04, 0x04, W83795G_FANIN3 },
98           { "FANIN4",  _FAN,  W83795G_F_CTRL1, 0x08, 0x08, W83795G_FANIN4 },
99           { "FANIN5",  _FAN,  W83795G_F_CTRL1, 0x10, 0x10, W83795G_FANIN5 },
100           { "FANIN6",  _FAN,  W83795G_F_CTRL1, 0x20, 0x20, W83795G_FANIN6 },
101           { "FANIN7",  _FAN,  W83795G_F_CTRL1, 0x40, 0x40, W83795G_FANIN7 },
102           { "FANIN8",  _FAN,  W83795G_F_CTRL1, 0x80, 0x80, W83795G_FANIN8 },
103           { "FANIN9",  _FAN,  W83795G_F_CTRL2, 0x01, 0x01, W83795G_FANIN9 },
104           { "FANIN10", _FAN,  W83795G_F_CTRL2, 0x02, 0x02, W83795G_FANIN10 },
105           { "FANIN11", _FAN,  W83795G_F_CTRL2, 0x04, 0x04, W83795G_FANIN11 },
106           { "FANIN12", _FAN,  W83795G_F_CTRL2, 0x08, 0x08, W83795G_FANIN12 },
107           { "FANIN13", _FAN,  W83795G_F_CTRL2, 0x10, 0x10, W83795G_FANIN13 },
108           { "FANIN14", _FAN,  W83795G_F_CTRL2, 0x20, 0x20, W83795G_FANIN14 },
109 };
110 
111 struct w83795g_softc {
112           device_t            sc_dev;
113           i2c_tag_t           sc_tag;
114           i2c_addr_t                    sc_addr;
115           struct gpio_chipset_tag       sc_gpio_gc;
116           gpio_pin_t                    sc_gpio_pins[8];
117           struct sysmon_envsys          *sc_sme;
118           envsys_data_t                 sc_sensors[NUM_SENSORS];
119           struct sysmon_wdog  sc_smw;
120 };
121 
122 static int          w83795g_match(device_t, cfdata_t, void *);
123 static void         w83795g_attach(device_t, device_t, void *);
124 
125 CFATTACH_DECL_NEW(w83795g, sizeof(struct w83795g_softc),
126     w83795g_match, w83795g_attach, NULL, NULL);
127 
128 static void         w83795g_refresh(struct sysmon_envsys *, envsys_data_t *);
129 static void         w83795g_get_limits(struct sysmon_envsys *, envsys_data_t *,
130    sysmon_envsys_lim_t *limits, uint32_t *props);
131 
132 static int          w83795g_gpio_read(void *, int);
133 static void         w83795g_gpio_write(void *, int, int);
134 static void         w83795g_gpio_ctl(void *, int, int);
135 
136 static int          w83795g_wdog_setmode(struct sysmon_wdog *);
137 static int          w83795g_wdog_tickle(struct sysmon_wdog *);
138 
139 static int
w83795g_match(device_t parent,cfdata_t match,void * aux)140 w83795g_match(device_t parent, cfdata_t match, void *aux)
141 {
142           struct i2c_attach_args *ia = aux;
143           uint8_t bank, vend, chip, deva;
144 
145           if (ia->ia_addr < I2CADDR_MINADDR || ia->ia_addr > I2CADDR_MAXADDR)
146                     return 0;
147 
148           iic_acquire_bus(ia->ia_tag, 0);
149           iic_smbus_read_byte(ia->ia_tag, ia->ia_addr, W83795G_BANKSEL, &bank, 0);
150           iic_smbus_read_byte(ia->ia_tag, ia->ia_addr, W83795G_VENDOR, &vend, 0);
151           iic_smbus_read_byte(ia->ia_tag, ia->ia_addr, W83795G_CHIP, &chip, 0);
152           iic_smbus_read_byte(ia->ia_tag, ia->ia_addr, W83795G_DEVICEA, &deva, 0);
153           iic_release_bus(ia->ia_tag, 0);
154 
155           if ((bank & BANKSEL_HBACS && vend == VENDOR_NUVOTON_ID_HI) ||
156              (~bank & BANKSEL_HBACS && vend == VENDOR_NUVOTON_ID_LO))
157                     if (chip == CHIP_W83795G && deva == DEVICEA_A)
158                               return I2C_MATCH_ADDRESS_AND_PROBE;
159 
160           return 0;
161 }
162 
163 static void
w83795g_attach(device_t parent,device_t self,void * aux)164 w83795g_attach(device_t parent, device_t self, void *aux)
165 {
166           struct w83795g_softc *sc = device_private(self);
167           struct i2c_attach_args *ia = aux;
168           struct gpiobus_attach_args gba;
169           uint8_t conf, rev, reg, gpiom, en_reg;
170           int i;
171 
172           sc->sc_dev = self;
173           sc->sc_tag = ia->ia_tag;
174           sc->sc_addr = ia->ia_addr;
175           sc->sc_gpio_gc.gp_cookie = sc;
176           sc->sc_gpio_gc.gp_pin_read = w83795g_gpio_read;
177           sc->sc_gpio_gc.gp_pin_write = w83795g_gpio_write;
178           sc->sc_gpio_gc.gp_pin_ctl = w83795g_gpio_ctl;
179           sc->sc_sme = sysmon_envsys_create();
180           sc->sc_sme->sme_name = device_xname(self);
181           sc->sc_sme->sme_cookie = sc;
182           sc->sc_sme->sme_refresh = w83795g_refresh;
183           sc->sc_sme->sme_get_limits = w83795g_get_limits;
184           sc->sc_smw.smw_name = device_xname(self);
185           sc->sc_smw.smw_cookie = sc;
186           sc->sc_smw.smw_setmode = w83795g_wdog_setmode;
187           sc->sc_smw.smw_tickle = w83795g_wdog_tickle;
188           sc->sc_smw.smw_period = 60;
189 
190           iic_acquire_bus(sc->sc_tag, 0);
191           iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
192           iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, W83795G_CONFIG, &conf, 0);
193           iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, W83795G_DEVICE, &rev, 0);
194 
195           aprint_normal(": Nuvoton W83795");
196           if (conf & CONFIG_CONFIG48)
197                     aprint_normal("ADG");
198           else
199                     aprint_normal("G");
200           aprint_verbose(" (rev %c)", rev - DEVICEA_A + 'A');
201           aprint_normal(" Hardware Monitor\n");
202           aprint_naive(": Hardware Monitor\n");
203 
204           /* Debug dump of all register banks */
205           for (i = 0; i < 1024; i++) {
206                     if (i % 256 == 0) {
207                               iic_smbus_write_byte(sc->sc_tag, sc->sc_addr,
208                                   W83795G_BANKSEL, i / 256, 0);
209                               aprint_debug_dev(self, "register bank %d:\n", i / 256);
210                     }
211                     if (i % 32 == 0)
212                               aprint_debug_dev(self, "%02x ", i % 256);
213                     iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, i % 256, &reg, 0);
214                     aprint_debug("%02x", reg);
215                     if (i % 32 == 31)
216                               aprint_debug("\n");
217                     else if (i % 8 == 7)
218                               aprint_debug(" ");
219           }
220 
221           iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
222 
223           for (i = 0; i < NUM_SENSORS; i++) {
224                     iic_smbus_read_byte(sc->sc_tag, sc->sc_addr,
225                         sensors[i].en_reg, &en_reg, 0);
226 
227                     if ((en_reg & sensors[i].en_mask) != sensors[i].en_bits)
228                               continue;
229 
230                     strcpy(sc->sc_sensors[i].desc, sensors[i].desc);
231                     sc->sc_sensors[i].units = sensors[i].type;
232                     sc->sc_sensors[i].state = ENVSYS_SINVALID;
233                     sc->sc_sensors[i].flags = ENVSYS_FMONLIMITS;
234                     sc->sc_sensors[i].flags |= ENVSYS_FHAS_ENTROPY;
235                     sc->sc_sensors[i].private = i;
236                     sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensors[i]);
237           }
238 
239           iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, W83795G_GPIO_M, &gpiom, 0);
240           iic_release_bus(sc->sc_tag, 0);
241 
242           if (conf & CONFIG_CONFIG48)
243                     gba.gba_npins = 4;
244           else
245                     gba.gba_npins = 8;
246           gba.gba_gc = &sc->sc_gpio_gc;
247           gba.gba_pins = sc->sc_gpio_pins;
248 
249           for (i = 0; i < gba.gba_npins; i++) {
250                     sc->sc_gpio_pins[i].pin_num = i;
251                     sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_OUTPUT | GPIO_PIN_INPUT;
252                     sc->sc_gpio_pins[i].pin_flags = (gpiom & (1 << i)) ?
253                         GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
254                     sc->sc_gpio_pins[i].pin_state = w83795g_gpio_read(sc, i);
255           }
256 
257           if (sysmon_envsys_register(sc->sc_sme))
258                     aprint_error_dev(self, "unable to register with sysmon\n");
259 
260           if (sysmon_wdog_register(&sc->sc_smw) != 0)
261                     aprint_error_dev(self, "couldn't register watchdog\n");
262 
263           if (!pmf_device_register(self, NULL, NULL))
264                     aprint_error_dev(self, "couldn't establish power handler\n");
265 
266           config_found(self, &gba, gpiobus_print, CFARGS_NONE);
267 }
268 
269 static void
w83795g_refresh(struct sysmon_envsys * sme,envsys_data_t * edata)270 w83795g_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
271 {
272           struct w83795g_softc *sc = sme->sme_cookie;
273           const struct w83795g_sensor *sensor = &sensors[edata->private];
274           uint8_t msb, lsb;
275 
276           sensor = &sensors[edata->private];
277 
278           iic_acquire_bus(sc->sc_tag, 0);
279           iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
280           iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, sensor->msb, &msb, 0);
281           iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, W83795G_VR_LSB, &lsb, 0);
282           iic_release_bus(sc->sc_tag, 0);
283 
284           switch (edata->units) {
285           case ENVSYS_SVOLTS_DC:
286                     if (sensor->msb == W83795G_3VDD ||
287                         sensor->msb == W83795G_3VSB ||
288                         sensor->msb == W83795G_VBAT)
289                               edata->value_cur = (msb << 2 | lsb >> 6) * 6000;
290                     else
291                               edata->value_cur = (msb << 2 | lsb >> 6) * 2000;
292                     break;
293           case ENVSYS_STEMP:
294                     edata->value_cur = ((int8_t)msb << 2 | lsb >> 6) * 250000 +
295                         273150000;
296                     break;
297           case ENVSYS_SFANRPM:
298                     edata->value_cur = 1350000 / (msb << 4 | lsb >> 4);
299                     break;
300           }
301 
302           edata->state = ENVSYS_SVALID;
303 }
304 
305 static void
w83795g_get_limits(struct sysmon_envsys * sme,envsys_data_t * edata,sysmon_envsys_lim_t * limits,uint32_t * props)306 w83795g_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
307     sysmon_envsys_lim_t *limits, uint32_t *props)
308 {
309           struct w83795g_softc *sc = sme->sme_cookie;
310           const struct w83795g_sensor *sensor = &sensors[edata->private];
311           uint8_t index, msb, lsb;
312 
313           iic_acquire_bus(sc->sc_tag, 0);
314           iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
315 
316           switch (edata->units) {
317           case ENVSYS_SVOLTS_DC:
318                     break;
319           case ENVSYS_STEMP:
320                     if (sensor->msb == W83795G_TR5)
321                               index = W83795G_TR5CRIT;
322                     else if (sensor->msb == W83795G_TR6)
323                               index = W83795G_TR6CRIT;
324                     else if (sensor->msb >= W83795G_DTS1)
325                               index = W83795G_DTSCRIT;
326                     else
327                               index = W83795G_TD1CRIT +
328                                   (sensor->msb - W83795G_TD1) * 4;
329                     iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, index, &msb, 0);
330                     limits->sel_critmax = (int8_t)msb * 1000000 + 273150000;
331                     index += 2;
332                     iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, index++, &msb, 0);
333                     limits->sel_warnmax = (int8_t)msb * 1000000 + 273150000;
334                     *props |= PROP_CRITMAX | PROP_WARNMAX;
335                     break;
336           case ENVSYS_SFANRPM:
337                     index = W83795G_FAN1HL + (sensor->msb - W83795G_FANIN1) * 2;
338                     iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, index, &msb, 0);
339                     index = W83795G_FHL1LSB + (sensor->msb - W83795G_FANIN1) / 2;
340                     iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, index, &lsb, 0);
341                     if (index % 2)
342                               lsb >>= 4;
343                     else
344                               lsb &= 0xf;
345                     limits->sel_warnmin = 1350000 / (msb << 4 | lsb);
346                     *props |= PROP_WARNMIN;
347                     break;
348           }
349 
350           iic_release_bus(sc->sc_tag, 0);
351 }
352 
353 static int
w83795g_gpio_read(void * arg,int pin)354 w83795g_gpio_read(void *arg, int pin)
355 {
356           struct w83795g_softc *sc = arg;
357           uint8_t in, out;
358 
359           iic_acquire_bus(sc->sc_tag, 0);
360           iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
361           iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, W83795G_GPIO_I, &in, 0);
362           iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, W83795G_GPIO_O, &out, 0);
363           iic_release_bus(sc->sc_tag, 0);
364 
365           if (sc->sc_gpio_pins[pin].pin_flags == GPIO_PIN_OUTPUT)
366                     in = out;
367 
368           return (in & (1 << pin)) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
369 }
370 
371 static void
w83795g_gpio_write(void * arg,int pin,int value)372 w83795g_gpio_write(void *arg, int pin, int value)
373 {
374           struct w83795g_softc *sc = arg;
375           uint8_t out;
376 
377           iic_acquire_bus(sc->sc_tag, 0);
378           iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
379           iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, W83795G_GPIO_O, &out, 0);
380 
381           if (value == GPIO_PIN_LOW)
382                     out &= ~(1 << pin);
383           else if (value == GPIO_PIN_HIGH)
384                     out |= (1 << pin);
385 
386           iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_GPIO_O, out, 0);
387           iic_release_bus(sc->sc_tag, 0);
388 }
389 
390 static void
w83795g_gpio_ctl(void * arg,int pin,int flags)391 w83795g_gpio_ctl(void *arg, int pin, int flags)
392 {
393           struct w83795g_softc *sc = arg;
394           uint8_t mode;
395 
396           iic_acquire_bus(sc->sc_tag, 0);
397           iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
398           iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, W83795G_GPIO_M, &mode, 0);
399 
400           if (flags & GPIO_PIN_INPUT)
401                     mode &= ~(1 << pin);
402           if (flags & GPIO_PIN_OUTPUT)
403                     mode |= (1 << pin);
404 
405           iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_GPIO_M, mode, 0);
406           iic_release_bus(sc->sc_tag, 0);
407 }
408 
409 static int
w83795g_wdog_setmode(struct sysmon_wdog * smw)410 w83795g_wdog_setmode(struct sysmon_wdog *smw)
411 {
412           struct w83795g_softc *sc = smw->smw_cookie;
413 
414           /*
415            * This device also supports a "hard" watchdog mode, which survives
416            * across reboots, but making use of that would require sysmon_wdog
417            * to have a way of querying the watchdog state at startup.
418            */
419 
420           iic_acquire_bus(sc->sc_tag, 0);
421           iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
422           iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_WDT_ENA,
423               WDT_ENA_ENWDT | WDT_ENA_SOFT, 0);
424           if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED)
425                     iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_WDTLOCK,
426                         WDTLOCK_DISABLE_SOFT, 0);
427           else
428                     iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_WDTLOCK,
429                         WDTLOCK_ENABLE_SOFT, 0);
430           iic_release_bus(sc->sc_tag, 0);
431 
432           if (smw->smw_period == WDOG_PERIOD_DEFAULT)
433                     smw->smw_period = 60;
434           smw->smw_period = roundup(smw->smw_period, 60);
435           w83795g_wdog_tickle(smw);
436 
437           return 0;
438 }
439 
440 static int
w83795g_wdog_tickle(struct sysmon_wdog * smw)441 w83795g_wdog_tickle(struct sysmon_wdog *smw)
442 {
443           struct w83795g_softc *sc = smw->smw_cookie;
444 
445           iic_acquire_bus(sc->sc_tag, 0);
446           iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_BANKSEL, 0, 0);
447           iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, W83795G_WDT_CNT,
448               smw->smw_period / 60, 0);
449           iic_release_bus(sc->sc_tag, 0);
450 
451           return 0;
452 }
453