| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: wbsio.c,v 1.17 2017/12/13 00:27:01 knakahara Exp $ */ | | 1 | /* $NetBSD: wbsio.c,v 1.18 2017/12/13 00:27:53 knakahara Exp $ */ |
2 | /* $OpenBSD: wbsio.c,v 1.10 2015/03/14 03:38:47 jsg Exp $ */ | | 2 | /* $OpenBSD: wbsio.c,v 1.10 2015/03/14 03:38:47 jsg Exp $ */ |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2008 Mark Kettenis <kettenis@openbsd.org> | | 4 | * Copyright (c) 2008 Mark Kettenis <kettenis@openbsd.org> |
5 | * | | 5 | * |
6 | * Permission to use, copy, modify, and distribute this software for any | | 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 | | 7 | * purpose with or without fee is hereby granted, provided that the above |
8 | * copyright notice and this permission notice appear in all copies. | | 8 | * copyright notice and this permission notice appear in all copies. |
9 | * | | 9 | * |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | | 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| @@ -24,55 +24,60 @@ | | | @@ -24,55 +24,60 @@ |
24 | #include <sys/param.h> | | 24 | #include <sys/param.h> |
25 | #include <sys/device.h> | | 25 | #include <sys/device.h> |
26 | #include <sys/kernel.h> | | 26 | #include <sys/kernel.h> |
27 | #include <sys/module.h> | | 27 | #include <sys/module.h> |
28 | #include <sys/systm.h> | | 28 | #include <sys/systm.h> |
29 | #include <sys/mutex.h> | | 29 | #include <sys/mutex.h> |
30 | #include <sys/gpio.h> | | 30 | #include <sys/gpio.h> |
31 | | | 31 | |
32 | #include <sys/bus.h> | | 32 | #include <sys/bus.h> |
33 | | | 33 | |
34 | #include <dev/isa/isareg.h> | | 34 | #include <dev/isa/isareg.h> |
35 | #include <dev/isa/isavar.h> | | 35 | #include <dev/isa/isavar.h> |
36 | #include <dev/isa/wbsioreg.h> | | 36 | #include <dev/isa/wbsioreg.h> |
| | | 37 | #include <dev/sysmon/sysmonvar.h> |
37 | | | 38 | |
38 | /* Don't use gpio for now in the module */ | | 39 | /* Don't use gpio for now in the module */ |
39 | #ifndef _MODULE | | 40 | #ifndef _MODULE |
40 | #include "gpio.h" | | 41 | #include "gpio.h" |
41 | #endif | | 42 | #endif |
42 | #if NGPIO > 0 | | 43 | #if NGPIO > 0 |
43 | #include <dev/gpio/gpiovar.h> | | 44 | #include <dev/gpio/gpiovar.h> |
44 | #endif | | 45 | #endif |
45 | | | 46 | |
46 | struct wbsio_softc { | | 47 | struct wbsio_softc { |
47 | device_t sc_dev; | | 48 | device_t sc_dev; |
48 | device_t sc_lm_dev; | | 49 | device_t sc_lm_dev; |
49 | #if NGPIO > 0 | | 50 | #if NGPIO > 0 |
50 | device_t sc_gpio_dev; | | 51 | device_t sc_gpio_dev; |
51 | #endif | | 52 | #endif |
52 | | | 53 | |
53 | bus_space_tag_t sc_iot; | | 54 | bus_space_tag_t sc_iot; |
54 | bus_space_handle_t sc_ioh; | | 55 | bus_space_handle_t sc_ioh; |
| | | 56 | kmutex_t sc_conf_lock; |
55 | | | 57 | |
56 | struct isa_attach_args sc_ia; | | 58 | struct isa_attach_args sc_ia; |
57 | struct isa_io sc_io; | | 59 | struct isa_io sc_io; |
58 | | | 60 | |
59 | #if NGPIO > 0 | | 61 | #if NGPIO > 0 |
60 | bus_space_handle_t sc_gpio_ioh; | | 62 | bus_space_handle_t sc_gpio_ioh; |
61 | kmutex_t sc_gpio_lock; | | 63 | kmutex_t sc_gpio_lock; |
62 | struct gpio_chipset_tag sc_gpio_gc; | | 64 | struct gpio_chipset_tag sc_gpio_gc; |
63 | struct gpio_pin sc_gpio_pins[WBSIO_GPIO_NPINS]; | | 65 | struct gpio_pin sc_gpio_pins[WBSIO_GPIO_NPINS]; |
64 | bool sc_gpio_rt; | | 66 | bool sc_gpio_rt; |
65 | #endif | | 67 | #endif |
| | | 68 | |
| | | 69 | struct sysmon_wdog sc_smw; |
| | | 70 | bool sc_smw_valid; |
66 | }; | | 71 | }; |
67 | | | 72 | |
68 | static const struct wbsio_product { | | 73 | static const struct wbsio_product { |
69 | uint16_t id; | | 74 | uint16_t id; |
70 | bool idis12bits; | | 75 | bool idis12bits; |
71 | const char *str; | | 76 | const char *str; |
72 | } wbsio_products[] = { | | 77 | } wbsio_products[] = { |
73 | { WBSIO_ID_W83627HF, false, "W83627HF" }, | | 78 | { WBSIO_ID_W83627HF, false, "W83627HF" }, |
74 | { WBSIO_ID_W83697HF, false, "W83697HF" }, | | 79 | { WBSIO_ID_W83697HF, false, "W83697HF" }, |
75 | { WBSIO_ID_W83637HF, false, "W83637HF" }, | | 80 | { WBSIO_ID_W83637HF, false, "W83637HF" }, |
76 | { WBSIO_ID_W83627THF, false, "W83627THF" }, | | 81 | { WBSIO_ID_W83627THF, false, "W83627THF" }, |
77 | { WBSIO_ID_W83687THF, false, "W83687THF" }, | | 82 | { WBSIO_ID_W83687THF, false, "W83687THF" }, |
78 | { WBSIO_ID_W83627DHG, true, "W83627DHG" }, | | 83 | { WBSIO_ID_W83627DHG, true, "W83627DHG" }, |
| @@ -91,53 +96,67 @@ static const struct wbsio_product { | | | @@ -91,53 +96,67 @@ static const struct wbsio_product { |
91 | { WBSIO_ID_NCT6792D, true, "NCT6792D" }, | | 96 | { WBSIO_ID_NCT6792D, true, "NCT6792D" }, |
92 | { WBSIO_ID_NCT6793D, true, "NCT6793D" }, | | 97 | { WBSIO_ID_NCT6793D, true, "NCT6793D" }, |
93 | { WBSIO_ID_NCT6795D, true, "NCT6795D" }, | | 98 | { WBSIO_ID_NCT6795D, true, "NCT6795D" }, |
94 | }; | | 99 | }; |
95 | | | 100 | |
96 | static const struct wbsio_product *wbsio_lookup(uint8_t id, uint8_t rev); | | 101 | static const struct wbsio_product *wbsio_lookup(uint8_t id, uint8_t rev); |
97 | static int wbsio_match(device_t, cfdata_t, void *); | | 102 | static int wbsio_match(device_t, cfdata_t, void *); |
98 | static void wbsio_attach(device_t, device_t, void *); | | 103 | static void wbsio_attach(device_t, device_t, void *); |
99 | static int wbsio_detach(device_t, int); | | 104 | static int wbsio_detach(device_t, int); |
100 | static int wbsio_rescan(device_t, const char *, const int *); | | 105 | static int wbsio_rescan(device_t, const char *, const int *); |
101 | static void wbsio_childdet(device_t, device_t); | | 106 | static void wbsio_childdet(device_t, device_t); |
102 | static int wbsio_print(void *, const char *); | | 107 | static int wbsio_print(void *, const char *); |
103 | static int wbsio_search(device_t, cfdata_t, const int *, void *); | | 108 | static int wbsio_search(device_t, cfdata_t, const int *, void *); |
| | | 109 | static bool wbsio_suspend(device_t, const pmf_qual_t *); |
104 | #if NGPIO > 0 | | 110 | #if NGPIO > 0 |
105 | static int wbsio_gpio_search(device_t, cfdata_t, const int *, void *); | | 111 | static int wbsio_gpio_search(device_t, cfdata_t, const int *, void *); |
106 | static int wbsio_gpio_rt_init(struct wbsio_softc *); | | 112 | static int wbsio_gpio_rt_init(struct wbsio_softc *); |
107 | static int wbsio_gpio_rt_read(struct wbsio_softc *, int, int); | | 113 | static int wbsio_gpio_rt_read(struct wbsio_softc *, int, int); |
108 | static void wbsio_gpio_rt_write(struct wbsio_softc *, int, int, int); | | 114 | static void wbsio_gpio_rt_write(struct wbsio_softc *, int, int, int); |
109 | static int wbsio_gpio_rt_pin_read(void *, int); | | 115 | static int wbsio_gpio_rt_pin_read(void *, int); |
110 | static void wbsio_gpio_rt_pin_write(void *, int, int); | | 116 | static void wbsio_gpio_rt_pin_write(void *, int, int); |
111 | static void wbsio_gpio_rt_pin_ctl(void *, int, int); | | 117 | static void wbsio_gpio_rt_pin_ctl(void *, int, int); |
112 | static void wbsio_gpio_enable_nct6779d(device_t); | | 118 | static void wbsio_gpio_enable_nct6779d(device_t); |
113 | static void wbsio_gpio_pinconfig_nct6779d(device_t); | | 119 | static void wbsio_gpio_pinconfig_nct6779d(device_t); |
114 | #endif | | 120 | #endif |
| | | 121 | static void wbsio_wdog_attach(device_t); |
| | | 122 | static int wbsio_wdog_detach(device_t); |
| | | 123 | static int wbsio_wdog_setmode(struct sysmon_wdog *); |
| | | 124 | static int wbsio_wdog_tickle(struct sysmon_wdog *); |
| | | 125 | static void wbsio_wdog_setcounter(struct wbsio_softc *, uint8_t); |
| | | 126 | static void wbsio_wdog_clear_timeout(struct wbsio_softc *); |
115 | | | 127 | |
116 | CFATTACH_DECL2_NEW(wbsio, sizeof(struct wbsio_softc), | | 128 | CFATTACH_DECL2_NEW(wbsio, sizeof(struct wbsio_softc), |
117 | wbsio_match, wbsio_attach, wbsio_detach, NULL, | | 129 | wbsio_match, wbsio_attach, wbsio_detach, NULL, |
118 | wbsio_rescan, wbsio_childdet); | | 130 | wbsio_rescan, wbsio_childdet); |
119 | | | 131 | |
120 | static __inline void | | 132 | static __inline void |
121 | wbsio_conf_enable(bus_space_tag_t iot, bus_space_handle_t ioh) | | 133 | wbsio_conf_enable(kmutex_t *lock, bus_space_tag_t iot, bus_space_handle_t ioh) |
122 | { | | 134 | { |
| | | 135 | if (lock) |
| | | 136 | mutex_enter(lock); |
| | | 137 | |
123 | bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_EN_MAGIC); | | 138 | bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_EN_MAGIC); |
124 | bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_EN_MAGIC); | | 139 | bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_EN_MAGIC); |
125 | } | | 140 | } |
126 | | | 141 | |
127 | static __inline void | | 142 | static __inline void |
128 | wbsio_conf_disable(bus_space_tag_t iot, bus_space_handle_t ioh) | | 143 | wbsio_conf_disable(kmutex_t *lock, bus_space_tag_t iot, bus_space_handle_t ioh) |
129 | { | | 144 | { |
| | | 145 | |
130 | bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_DS_MAGIC); | | 146 | bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_DS_MAGIC); |
| | | 147 | |
| | | 148 | if (lock) |
| | | 149 | mutex_exit(lock); |
131 | } | | 150 | } |
132 | | | 151 | |
133 | static __inline uint8_t | | 152 | static __inline uint8_t |
134 | wbsio_conf_read(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t index) | | 153 | wbsio_conf_read(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t index) |
135 | { | | 154 | { |
136 | bus_space_write_1(iot, ioh, WBSIO_INDEX, index); | | 155 | bus_space_write_1(iot, ioh, WBSIO_INDEX, index); |
137 | return (bus_space_read_1(iot, ioh, WBSIO_DATA)); | | 156 | return (bus_space_read_1(iot, ioh, WBSIO_DATA)); |
138 | } | | 157 | } |
139 | | | 158 | |
140 | static __inline void | | 159 | static __inline void |
141 | wbsio_conf_write(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t index, | | 160 | wbsio_conf_write(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t index, |
142 | uint8_t data) | | 161 | uint8_t data) |
143 | { | | 162 | { |
| @@ -178,31 +197,31 @@ wbsio_match(device_t parent, cfdata_t ma | | | @@ -178,31 +197,31 @@ wbsio_match(device_t parent, cfdata_t ma |
178 | if (ia->ia_nio < 1) | | 197 | if (ia->ia_nio < 1) |
179 | return 0; | | 198 | return 0; |
180 | | | 199 | |
181 | if (ISA_DIRECT_CONFIG(ia)) | | 200 | if (ISA_DIRECT_CONFIG(ia)) |
182 | return 0; | | 201 | return 0; |
183 | | | 202 | |
184 | if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) | | 203 | if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) |
185 | return 0; | | 204 | return 0; |
186 | | | 205 | |
187 | /* Match by device ID */ | | 206 | /* Match by device ID */ |
188 | iot = ia->ia_iot; | | 207 | iot = ia->ia_iot; |
189 | if (bus_space_map(iot, ia->ia_io[0].ir_addr, WBSIO_IOSIZE, 0, &ioh)) | | 208 | if (bus_space_map(iot, ia->ia_io[0].ir_addr, WBSIO_IOSIZE, 0, &ioh)) |
190 | return 0; | | 209 | return 0; |
191 | wbsio_conf_enable(iot, ioh); | | 210 | wbsio_conf_enable(NULL, iot, ioh); |
192 | id = wbsio_conf_read(iot, ioh, WBSIO_ID); | | 211 | id = wbsio_conf_read(iot, ioh, WBSIO_ID); |
193 | rev = wbsio_conf_read(iot, ioh, WBSIO_REV); | | 212 | rev = wbsio_conf_read(iot, ioh, WBSIO_REV); |
194 | aprint_debug("wbsio_probe: id 0x%02x, rev 0x%02x\n", id, rev); | | 213 | aprint_debug("wbsio_probe: id 0x%02x, rev 0x%02x\n", id, rev); |
195 | wbsio_conf_disable(iot, ioh); | | 214 | wbsio_conf_disable(NULL, iot, ioh); |
196 | bus_space_unmap(iot, ioh, WBSIO_IOSIZE); | | 215 | bus_space_unmap(iot, ioh, WBSIO_IOSIZE); |
197 | | | 216 | |
198 | if ((product = wbsio_lookup(id, rev)) == NULL) | | 217 | if ((product = wbsio_lookup(id, rev)) == NULL) |
199 | return 0; | | 218 | return 0; |
200 | | | 219 | |
201 | ia->ia_nio = 1; | | 220 | ia->ia_nio = 1; |
202 | ia->ia_io[0].ir_size = WBSIO_IOSIZE; | | 221 | ia->ia_io[0].ir_size = WBSIO_IOSIZE; |
203 | ia->ia_niomem = 0; | | 222 | ia->ia_niomem = 0; |
204 | ia->ia_nirq = 0; | | 223 | ia->ia_nirq = 0; |
205 | ia->ia_ndrq = 0; | | 224 | ia->ia_ndrq = 0; |
206 | return 1; | | 225 | return 1; |
207 | } | | 226 | } |
208 | | | 227 | |
| @@ -218,88 +237,98 @@ wbsio_attach(device_t parent, device_t s | | | @@ -218,88 +237,98 @@ wbsio_attach(device_t parent, device_t s |
218 | | | 237 | |
219 | sc->sc_dev = self; | | 238 | sc->sc_dev = self; |
220 | | | 239 | |
221 | sc->sc_ia = *ia; | | 240 | sc->sc_ia = *ia; |
222 | | | 241 | |
223 | /* Map ISA I/O space */ | | 242 | /* Map ISA I/O space */ |
224 | sc->sc_iot = ia->ia_iot; | | 243 | sc->sc_iot = ia->ia_iot; |
225 | if (bus_space_map(sc->sc_iot, ia->ia_io[0].ir_addr, | | 244 | if (bus_space_map(sc->sc_iot, ia->ia_io[0].ir_addr, |
226 | WBSIO_IOSIZE, 0, &sc->sc_ioh)) { | | 245 | WBSIO_IOSIZE, 0, &sc->sc_ioh)) { |
227 | aprint_error(": can't map i/o space\n"); | | 246 | aprint_error(": can't map i/o space\n"); |
228 | return; | | 247 | return; |
229 | } | | 248 | } |
230 | | | 249 | |
| | | 250 | mutex_init(&sc->sc_conf_lock, MUTEX_DEFAULT, IPL_NONE); |
| | | 251 | |
231 | /* Enter configuration mode */ | | 252 | /* Enter configuration mode */ |
232 | wbsio_conf_enable(sc->sc_iot, sc->sc_ioh); | | 253 | wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
233 | | | 254 | |
234 | /* Read device ID */ | | 255 | /* Read device ID */ |
235 | id = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID); | | 256 | id = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID); |
236 | /* Read device revision */ | | 257 | /* Read device revision */ |
237 | rev = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_REV); | | 258 | rev = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_REV); |
238 | | | 259 | |
239 | /* Escape from configuration mode */ | | 260 | /* Escape from configuration mode */ |
240 | wbsio_conf_disable(sc->sc_iot, sc->sc_ioh); | | 261 | wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
241 | | | 262 | |
242 | if ((product = wbsio_lookup(id, rev)) == NULL) { | | 263 | if ((product = wbsio_lookup(id, rev)) == NULL) { |
243 | aprint_error_dev(self, "Unknown device. Failed to attach\n"); | | 264 | aprint_error_dev(self, "Unknown device. Failed to attach\n"); |
244 | return; | | 265 | return; |
245 | } | | 266 | } |
246 | if (product->idis12bits) | | 267 | if (product->idis12bits) |
247 | rev &= 0x0f; /* Revision is low 4bits */ | | 268 | rev &= 0x0f; /* Revision is low 4bits */ |
248 | | | 269 | |
249 | desc = product->str; | | 270 | desc = product->str; |
250 | if (desc[0] == 'W') | | 271 | if (desc[0] == 'W') |
251 | vendor = "Winbond"; | | 272 | vendor = "Winbond"; |
252 | else | | 273 | else |
253 | vendor = "Nuvoton"; | | 274 | vendor = "Nuvoton"; |
254 | aprint_naive("\n"); | | 275 | aprint_naive("\n"); |
255 | aprint_normal(": %s LPC Super I/O %s rev ", vendor, desc); | | 276 | aprint_normal(": %s LPC Super I/O %s rev ", vendor, desc); |
256 | if (product->idis12bits) { | | 277 | if (product->idis12bits) { |
257 | /* Revision filed is 4bit only */ | | 278 | /* Revision filed is 4bit only */ |
258 | aprint_normal("%c\n", 'A' + rev); | | 279 | aprint_normal("%c\n", 'A' + rev); |
259 | } else | | 280 | } else |
260 | aprint_normal("0x%02x\n", rev); | | 281 | aprint_normal("0x%02x\n", rev); |
261 | | | 282 | |
262 | if (!pmf_device_register(self, NULL, NULL)) | | 283 | if (!pmf_device_register(self, wbsio_suspend, NULL)) |
263 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 284 | aprint_error_dev(self, "couldn't establish power handler\n"); |
| | | 285 | |
| | | 286 | wbsio_wdog_attach(self); |
| | | 287 | |
264 | wbsio_rescan(self, "wbsio", NULL); | | 288 | wbsio_rescan(self, "wbsio", NULL); |
265 | | | 289 | |
266 | #if NGPIO > 0 | | 290 | #if NGPIO > 0 |
267 | | | 291 | |
268 | wbsio_rescan(self, "gpiobus", NULL); | | 292 | wbsio_rescan(self, "gpiobus", NULL); |
269 | #endif | | 293 | #endif |
270 | } | | 294 | } |
271 | | | 295 | |
272 | int | | 296 | int |
273 | wbsio_detach(device_t self, int flags) | | 297 | wbsio_detach(device_t self, int flags) |
274 | { | | 298 | { |
275 | struct wbsio_softc *sc = device_private(self); | | 299 | struct wbsio_softc *sc = device_private(self); |
276 | int rc; | | 300 | int rc; |
277 | | | 301 | |
| | | 302 | if ((rc = wbsio_wdog_detach(self)) != 0) |
| | | 303 | return rc; |
| | | 304 | |
278 | if ((rc = config_detach_children(self, flags)) != 0) | | 305 | if ((rc = config_detach_children(self, flags)) != 0) |
279 | return rc; | | 306 | return rc; |
280 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, WBSIO_IOSIZE); | | 307 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, WBSIO_IOSIZE); |
281 | pmf_device_deregister(self); | | 308 | pmf_device_deregister(self); |
282 | | | 309 | |
283 | #if NGPIO > 0 | | 310 | #if NGPIO > 0 |
284 | if (sc->sc_gpio_dev) { | | 311 | if (sc->sc_gpio_dev) { |
285 | bus_space_unmap(sc->sc_iot, sc->sc_gpio_ioh, | | 312 | bus_space_unmap(sc->sc_iot, sc->sc_gpio_ioh, |
286 | WBSIO_GPIO_IOSIZE); | | 313 | WBSIO_GPIO_IOSIZE); |
287 | } | | 314 | } |
288 | | | 315 | |
289 | if (sc->sc_gpio_rt) { | | 316 | if (sc->sc_gpio_rt) { |
290 | mutex_destroy(&sc->sc_gpio_lock); | | 317 | mutex_destroy(&sc->sc_gpio_lock); |
291 | } | | 318 | } |
292 | #endif | | 319 | #endif |
| | | 320 | |
| | | 321 | mutex_destroy(&sc->sc_conf_lock); |
293 | return 0; | | 322 | return 0; |
294 | } | | 323 | } |
295 | | | 324 | |
296 | int | | 325 | int |
297 | wbsio_rescan(device_t self, const char *ifattr, const int *locators) | | 326 | wbsio_rescan(device_t self, const char *ifattr, const int *locators) |
298 | { | | 327 | { |
299 | | | 328 | |
300 | #if NGPIO > 0 | | 329 | #if NGPIO > 0 |
301 | if (ifattr_match(ifattr, "gpiobus")) { | | 330 | if (ifattr_match(ifattr, "gpiobus")) { |
302 | config_search_loc(wbsio_gpio_search, self, | | 331 | config_search_loc(wbsio_gpio_search, self, |
303 | ifattr, locators, NULL); | | 332 | ifattr, locators, NULL); |
304 | return 0; | | 333 | return 0; |
305 | } | | 334 | } |
| @@ -318,55 +347,55 @@ wbsio_childdet(device_t self, device_t c | | | @@ -318,55 +347,55 @@ wbsio_childdet(device_t self, device_t c |
318 | sc->sc_lm_dev = NULL; | | 347 | sc->sc_lm_dev = NULL; |
319 | } | | 348 | } |
320 | | | 349 | |
321 | static int | | 350 | static int |
322 | wbsio_search(device_t parent, cfdata_t cf, const int *slocs, void *aux) | | 351 | wbsio_search(device_t parent, cfdata_t cf, const int *slocs, void *aux) |
323 | { | | 352 | { |
324 | struct wbsio_softc *sc = device_private(parent); | | 353 | struct wbsio_softc *sc = device_private(parent); |
325 | const struct wbsio_product *product; | | 354 | const struct wbsio_product *product; |
326 | uint16_t iobase; | | 355 | uint16_t iobase; |
327 | uint16_t devid; | | 356 | uint16_t devid; |
328 | uint8_t reg0, reg1, rev; | | 357 | uint8_t reg0, reg1, rev; |
329 | | | 358 | |
330 | /* Enter configuration mode */ | | 359 | /* Enter configuration mode */ |
331 | wbsio_conf_enable(sc->sc_iot, sc->sc_ioh); | | 360 | wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
332 | | | 361 | |
333 | /* Select HM logical device */ | | 362 | /* Select HM logical device */ |
334 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_HM); | | 363 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_HM); |
335 | | | 364 | |
336 | /* | | 365 | /* |
337 | * The address should be 8-byte aligned, but it seems some | | 366 | * The address should be 8-byte aligned, but it seems some |
338 | * BIOSes ignore this. They get away with it, because | | 367 | * BIOSes ignore this. They get away with it, because |
339 | * Apparently the hardware simply ignores the lower three | | 368 | * Apparently the hardware simply ignores the lower three |
340 | * bits. We do the same here. | | 369 | * bits. We do the same here. |
341 | */ | | 370 | */ |
342 | reg0 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_HM_ADDR_LSB); | | 371 | reg0 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_HM_ADDR_LSB); |
343 | reg1 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_HM_ADDR_MSB); | | 372 | reg1 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_HM_ADDR_MSB); |
344 | | | 373 | |
345 | /* Escape from configuration mode */ | | 374 | /* Escape from configuration mode */ |
346 | wbsio_conf_disable(sc->sc_iot, sc->sc_ioh); | | 375 | wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
347 | | | 376 | |
348 | iobase = (reg1 << 8) | (reg0 & ~0x7); | | 377 | iobase = (reg1 << 8) | (reg0 & ~0x7); |
349 | | | 378 | |
350 | if (iobase == 0) | | 379 | if (iobase == 0) |
351 | return -1; | | 380 | return -1; |
352 | | | 381 | |
353 | /* Enter configuration mode */ | | 382 | /* Enter configuration mode */ |
354 | wbsio_conf_enable(sc->sc_iot, sc->sc_ioh); | | 383 | wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
355 | /* Read device ID and revision */ | | 384 | /* Read device ID and revision */ |
356 | devid = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID); | | 385 | devid = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID); |
357 | rev = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_REV); | | 386 | rev = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_REV); |
358 | /* Escape from configuration mode */ | | 387 | /* Escape from configuration mode */ |
359 | wbsio_conf_disable(sc->sc_iot, sc->sc_ioh); | | 388 | wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
360 | | | 389 | |
361 | if ((product = wbsio_lookup(devid, rev)) == NULL) { | | 390 | if ((product = wbsio_lookup(devid, rev)) == NULL) { |
362 | aprint_error_dev(parent, "%s: Unknown device.\n", __func__); | | 391 | aprint_error_dev(parent, "%s: Unknown device.\n", __func__); |
363 | return -1; | | 392 | return -1; |
364 | } | | 393 | } |
365 | if (product->idis12bits) | | 394 | if (product->idis12bits) |
366 | devid = (devid << 4) | (rev >> 4); | | 395 | devid = (devid << 4) | (rev >> 4); |
367 | | | 396 | |
368 | sc->sc_ia.ia_nio = 1; | | 397 | sc->sc_ia.ia_nio = 1; |
369 | sc->sc_ia.ia_io = &sc->sc_io; | | 398 | sc->sc_ia.ia_io = &sc->sc_io; |
370 | sc->sc_ia.ia_io[0].ir_addr = iobase; | | 399 | sc->sc_ia.ia_io[0].ir_addr = iobase; |
371 | sc->sc_ia.ia_io[0].ir_size = 8; | | 400 | sc->sc_ia.ia_io[0].ir_size = 8; |
372 | sc->sc_ia.ia_niomem = 0; | | 401 | sc->sc_ia.ia_niomem = 0; |
| @@ -384,44 +413,58 @@ wbsio_print(void *aux, const char *pnp) | | | @@ -384,44 +413,58 @@ wbsio_print(void *aux, const char *pnp) |
384 | { | | 413 | { |
385 | struct isa_attach_args *ia = aux; | | 414 | struct isa_attach_args *ia = aux; |
386 | | | 415 | |
387 | if (pnp) | | 416 | if (pnp) |
388 | aprint_normal("%s", pnp); | | 417 | aprint_normal("%s", pnp); |
389 | if (ia->ia_io[0].ir_size) | | 418 | if (ia->ia_io[0].ir_size) |
390 | aprint_normal(" port 0x%x", ia->ia_io[0].ir_addr); | | 419 | aprint_normal(" port 0x%x", ia->ia_io[0].ir_addr); |
391 | if (ia->ia_io[0].ir_size > 1) | | 420 | if (ia->ia_io[0].ir_size > 1) |
392 | aprint_normal("-0x%x", ia->ia_io[0].ir_addr + | | 421 | aprint_normal("-0x%x", ia->ia_io[0].ir_addr + |
393 | ia->ia_io[0].ir_size - 1); | | 422 | ia->ia_io[0].ir_size - 1); |
394 | return (UNCONF); | | 423 | return (UNCONF); |
395 | } | | 424 | } |
396 | | | 425 | |
| | | 426 | static bool |
| | | 427 | wbsio_suspend(device_t self, const pmf_qual_t *qual) |
| | | 428 | { |
| | | 429 | struct wbsio_softc *sc = device_private(self); |
| | | 430 | |
| | | 431 | if (sc->sc_smw_valid) { |
| | | 432 | if ((sc->sc_smw.smw_mode & WDOG_MODE_MASK) |
| | | 433 | != WDOG_MODE_DISARMED) |
| | | 434 | return false; |
| | | 435 | } |
| | | 436 | |
| | | 437 | return true; |
| | | 438 | } |
| | | 439 | |
397 | #if NGPIO > 0 | | 440 | #if NGPIO > 0 |
398 | static int | | 441 | static int |
399 | wbsio_gpio_search(device_t parent, cfdata_t cf, const int *slocs, void *aux) | | 442 | wbsio_gpio_search(device_t parent, cfdata_t cf, const int *slocs, void *aux) |
400 | { | | 443 | { |
401 | struct wbsio_softc *sc = device_private(parent); | | 444 | struct wbsio_softc *sc = device_private(parent); |
402 | const struct wbsio_product *product; | | 445 | const struct wbsio_product *product; |
403 | struct gpiobus_attach_args gba; | | 446 | struct gpiobus_attach_args gba; |
404 | uint16_t devid; | | 447 | uint16_t devid; |
405 | uint8_t rev; | | 448 | uint8_t rev; |
406 | int i; | | 449 | int i; |
407 | | | 450 | |
408 | /* Enter configuration mode */ | | 451 | /* Enter configuration mode */ |
409 | wbsio_conf_enable(sc->sc_iot, sc->sc_ioh); | | 452 | wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
410 | /* Read device ID and revision */ | | 453 | /* Read device ID and revision */ |
411 | devid = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID); | | 454 | devid = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID); |
412 | rev = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_REV); | | 455 | rev = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_REV); |
413 | /* Escape from configuration mode */ | | 456 | /* Escape from configuration mode */ |
414 | wbsio_conf_disable(sc->sc_iot, sc->sc_ioh); | | 457 | wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
415 | | | 458 | |
416 | if ((product = wbsio_lookup(devid, rev)) == NULL) { | | 459 | if ((product = wbsio_lookup(devid, rev)) == NULL) { |
417 | aprint_error_dev(parent, "%s: Unknown device.\n", __func__); | | 460 | aprint_error_dev(parent, "%s: Unknown device.\n", __func__); |
418 | return -1; | | 461 | return -1; |
419 | } | | 462 | } |
420 | | | 463 | |
421 | sc->sc_gpio_rt = false; | | 464 | sc->sc_gpio_rt = false; |
422 | | | 465 | |
423 | switch (product->id) { | | 466 | switch (product->id) { |
424 | case WBSIO_ID_NCT6779D: | | 467 | case WBSIO_ID_NCT6779D: |
425 | wbsio_gpio_enable_nct6779d(parent); | | 468 | wbsio_gpio_enable_nct6779d(parent); |
426 | sc->sc_gpio_rt = true; | | 469 | sc->sc_gpio_rt = true; |
427 | break; | | 470 | break; |
| @@ -469,36 +512,36 @@ wbsio_gpio_search(device_t parent, cfdat | | | @@ -469,36 +512,36 @@ wbsio_gpio_search(device_t parent, cfdat |
469 | | | 512 | |
470 | sc->sc_gpio_dev = config_attach(parent, cf, &gba, gpiobus_print); | | 513 | sc->sc_gpio_dev = config_attach(parent, cf, &gba, gpiobus_print); |
471 | | | 514 | |
472 | return 0; | | 515 | return 0; |
473 | } | | 516 | } |
474 | | | 517 | |
475 | static int | | 518 | static int |
476 | wbsio_gpio_rt_init(struct wbsio_softc *sc) | | 519 | wbsio_gpio_rt_init(struct wbsio_softc *sc) |
477 | { | | 520 | { |
478 | uint16_t iobase; | | 521 | uint16_t iobase; |
479 | uint8_t reg0, reg1; | | 522 | uint8_t reg0, reg1; |
480 | | | 523 | |
481 | /* Enter configuration mode */ | | 524 | /* Enter configuration mode */ |
482 | wbsio_conf_enable(sc->sc_iot, sc->sc_ioh); | | 525 | wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
483 | | | 526 | |
484 | /* Get GPIO Register Table address */ | | 527 | /* Get GPIO Register Table address */ |
485 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); | | 528 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); |
486 | reg0 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_ADDR_LSB); | | 529 | reg0 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_ADDR_LSB); |
487 | reg1 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_ADDR_MSB); | | 530 | reg1 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_ADDR_MSB); |
488 | iobase = (reg1 << 8) | (reg0 & ~0x7); | | 531 | iobase = (reg1 << 8) | (reg0 & ~0x7); |
489 | | | 532 | |
490 | /* Escape from configuration mode */ | | 533 | /* Escape from configuration mode */ |
491 | wbsio_conf_disable(sc->sc_iot, sc->sc_ioh); | | 534 | wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
492 | | | 535 | |
493 | if (bus_space_map(sc->sc_iot, iobase, WBSIO_GPIO_IOSIZE, | | 536 | if (bus_space_map(sc->sc_iot, iobase, WBSIO_GPIO_IOSIZE, |
494 | 0, &sc->sc_gpio_ioh)) { | | 537 | 0, &sc->sc_gpio_ioh)) { |
495 | aprint_error_dev(sc->sc_dev, | | 538 | aprint_error_dev(sc->sc_dev, |
496 | "can't map gpio to i/o space\n"); | | 539 | "can't map gpio to i/o space\n"); |
497 | return -1; | | 540 | return -1; |
498 | } | | 541 | } |
499 | | | 542 | |
500 | aprint_normal_dev(sc->sc_dev, "GPIO: port 0x%x-0x%x\n", | | 543 | aprint_normal_dev(sc->sc_dev, "GPIO: port 0x%x-0x%x\n", |
501 | iobase, iobase + WBSIO_GPIO_IOSIZE); | | 544 | iobase, iobase + WBSIO_GPIO_IOSIZE); |
502 | | | 545 | |
503 | mutex_init(&sc->sc_gpio_lock, MUTEX_DEFAULT, IPL_NONE); | | 546 | mutex_init(&sc->sc_gpio_lock, MUTEX_DEFAULT, IPL_NONE); |
504 | | | 547 | |
| @@ -596,62 +639,62 @@ wbsio_gpio_rt_pin_ctl(void *aux, int pin | | | @@ -596,62 +639,62 @@ wbsio_gpio_rt_pin_ctl(void *aux, int pin |
596 | } | | 639 | } |
597 | | | 640 | |
598 | wbsio_gpio_rt_write(sc, port, WBSIO_GPIO_IOR, ior); | | 641 | wbsio_gpio_rt_write(sc, port, WBSIO_GPIO_IOR, ior); |
599 | wbsio_gpio_rt_write(sc, port, WBSIO_GPIO_INV, inv); | | 642 | wbsio_gpio_rt_write(sc, port, WBSIO_GPIO_INV, inv); |
600 | } | | 643 | } |
601 | | | 644 | |
602 | static void | | 645 | static void |
603 | wbsio_gpio_enable_nct6779d(device_t parent) | | 646 | wbsio_gpio_enable_nct6779d(device_t parent) |
604 | { | | 647 | { |
605 | struct wbsio_softc *sc = device_private(parent); | | 648 | struct wbsio_softc *sc = device_private(parent); |
606 | uint8_t reg, conf; | | 649 | uint8_t reg, conf; |
607 | | | 650 | |
608 | /* Enter configuration mode */ | | 651 | /* Enter configuration mode */ |
609 | wbsio_conf_enable(sc->sc_iot, sc->sc_ioh); | | 652 | wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
610 | | | 653 | |
611 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); | | 654 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); |
612 | reg = WBSIO_GPIO_CONF; | | 655 | reg = WBSIO_GPIO_CONF; |
613 | conf = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, reg); | | 656 | conf = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, reg); |
614 | /* Activate Register Table access */ | | 657 | /* Activate Register Table access */ |
615 | conf |= WBSIO_GPIO_BASEADDR; | | 658 | conf |= WBSIO_GPIO_BASEADDR; |
616 | | | 659 | |
617 | conf |= WBSIO_GPIO0_ENABLE; | | 660 | conf |= WBSIO_GPIO0_ENABLE; |
618 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, reg, conf); | | 661 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, reg, conf); |
619 | | | 662 | |
620 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO1); | | 663 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO1); |
621 | reg = WBSIO_GPIO_CONF; | | 664 | reg = WBSIO_GPIO_CONF; |
622 | conf = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, reg); | | 665 | conf = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, reg); |
623 | conf |= WBSIO_GPIO1_ENABLE; | | 666 | conf |= WBSIO_GPIO1_ENABLE; |
624 | conf |= WBSIO_GPIO2_ENABLE; | | 667 | conf |= WBSIO_GPIO2_ENABLE; |
625 | conf |= WBSIO_GPIO3_ENABLE; | | 668 | conf |= WBSIO_GPIO3_ENABLE; |
626 | conf |= WBSIO_GPIO4_ENABLE; | | 669 | conf |= WBSIO_GPIO4_ENABLE; |
627 | conf |= WBSIO_GPIO5_ENABLE; | | 670 | conf |= WBSIO_GPIO5_ENABLE; |
628 | conf |= WBSIO_GPIO6_ENABLE; | | 671 | conf |= WBSIO_GPIO6_ENABLE; |
629 | conf |= WBSIO_GPIO7_ENABLE; | | 672 | conf |= WBSIO_GPIO7_ENABLE; |
630 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, reg, conf); | | 673 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, reg, conf); |
631 | | | 674 | |
632 | /* Escape from configuration mode */ | | 675 | /* Escape from configuration mode */ |
633 | wbsio_conf_disable(sc->sc_iot, sc->sc_ioh); | | 676 | wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
634 | } | | 677 | } |
635 | | | 678 | |
636 | static void | | 679 | static void |
637 | wbsio_gpio_pinconfig_nct6779d(device_t parent) | | 680 | wbsio_gpio_pinconfig_nct6779d(device_t parent) |
638 | { | | 681 | { |
639 | struct wbsio_softc *sc = device_private(parent); | | 682 | struct wbsio_softc *sc = device_private(parent); |
640 | uint8_t sfr, mfs0, mfs1, mfs2, mfs3; | | 683 | uint8_t sfr, mfs0, mfs1, mfs2, mfs3; |
641 | uint8_t mfs4, mfs5, mfs6, gopt2, hm_conf; | | 684 | uint8_t mfs4, mfs5, mfs6, gopt2, hm_conf; |
642 | | | 685 | |
643 | /* Enter configuration mode */ | | 686 | /* Enter configuration mode */ |
644 | wbsio_conf_enable(sc->sc_iot, sc->sc_ioh); | | 687 | wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
645 | | | 688 | |
646 | /* Strapping Function Result */ | | 689 | /* Strapping Function Result */ |
647 | sfr = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_SFR); | | 690 | sfr = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_SFR); |
648 | sfr &= ~(WBSIO_SFR_LPT | WBSIO_SFR_DSW | WBSIO_SFR_AMDPWR); | | 691 | sfr &= ~(WBSIO_SFR_LPT | WBSIO_SFR_DSW | WBSIO_SFR_AMDPWR); |
649 | | | 692 | |
650 | /* Read current configuration */ | | 693 | /* Read current configuration */ |
651 | mfs0 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS0); | | 694 | mfs0 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS0); |
652 | mfs1 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS1); | | 695 | mfs1 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS1); |
653 | mfs2 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS2); | | 696 | mfs2 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS2); |
654 | mfs3 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS3); | | 697 | mfs3 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS3); |
655 | mfs4 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS4); | | 698 | mfs4 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS4); |
656 | mfs5 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS5); | | 699 | mfs5 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS5); |
657 | mfs6 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS6); | | 700 | mfs6 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS6); |
| @@ -730,30 +773,177 @@ wbsio_gpio_pinconfig_nct6779d(device_t p | | | @@ -730,30 +773,177 @@ wbsio_gpio_pinconfig_nct6779d(device_t p |
730 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS0, mfs0); | | 773 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS0, mfs0); |
731 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS1, mfs1); | | 774 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS1, mfs1); |
732 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS2, mfs2); | | 775 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS2, mfs2); |
733 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS3, mfs3); | | 776 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS3, mfs3); |
734 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS4, mfs4); | | 777 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS4, mfs4); |
735 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS5, mfs5); | | 778 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS5, mfs5); |
736 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS6, mfs6); | | 779 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS6, mfs6); |
737 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_GOPT2, gopt2); | | 780 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_GOPT2, gopt2); |
738 | | | 781 | |
739 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_HM); | | 782 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_HM); |
740 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_HM_CONF, hm_conf); | | 783 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_HM_CONF, hm_conf); |
741 | | | 784 | |
742 | /* Escape from configuration mode */ | | 785 | /* Escape from configuration mode */ |
743 | wbsio_conf_disable(sc->sc_iot, sc->sc_ioh); | | 786 | wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
| | | 787 | } |
| | | 788 | |
| | | 789 | #endif /* NGPIO > 0 */ |
| | | 790 | |
| | | 791 | static void |
| | | 792 | wbsio_wdog_attach(device_t self) |
| | | 793 | { |
| | | 794 | struct wbsio_softc *sc = device_private(self); |
| | | 795 | const struct wbsio_product *product; |
| | | 796 | uint8_t gpio, mode; |
| | | 797 | uint16_t devid; |
| | | 798 | uint8_t rev; |
| | | 799 | |
| | | 800 | sc->sc_smw_valid = false; |
| | | 801 | |
| | | 802 | wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
| | | 803 | devid = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID); |
| | | 804 | rev = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_REV); |
| | | 805 | wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
| | | 806 | |
| | | 807 | if ((product = wbsio_lookup(devid, rev)) == NULL) { |
| | | 808 | return; |
| | | 809 | } |
| | | 810 | |
| | | 811 | switch (product->id) { |
| | | 812 | case WBSIO_ID_NCT6779D: |
| | | 813 | break; |
| | | 814 | default: |
| | | 815 | /* WDT is not supoorted */ |
| | | 816 | return; |
| | | 817 | } |
| | | 818 | |
| | | 819 | wbsio_wdog_setcounter(sc, WBSIO_WDT_CNTR_STOP); |
| | | 820 | |
| | | 821 | wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
| | | 822 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); |
| | | 823 | |
| | | 824 | gpio = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_CONF); |
| | | 825 | mode = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_WDT_MODE); |
| | | 826 | |
| | | 827 | gpio |= WBSIO_GPIO0_WDT1; |
| | | 828 | |
| | | 829 | mode &= ~WBSIO_WDT_MODE_FASTER; |
| | | 830 | mode &= ~WBSIO_WDT_MODE_MINUTES; |
| | | 831 | mode &= ~WBSIO_WDT_MODE_KBCRST; |
| | | 832 | mode &= ~WBSIO_WDT_MODE_LEVEL; |
| | | 833 | |
| | | 834 | /* initialize WDT mode */ |
| | | 835 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_WDT_MODE, mode); |
| | | 836 | /* Activate WDT1 function */ |
| | | 837 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_CONF, gpio); |
| | | 838 | |
| | | 839 | wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
| | | 840 | |
| | | 841 | sc->sc_smw.smw_name = device_xname(self); |
| | | 842 | sc->sc_smw.smw_cookie = sc; |
| | | 843 | sc->sc_smw.smw_setmode = wbsio_wdog_setmode; |
| | | 844 | sc->sc_smw.smw_tickle = wbsio_wdog_tickle; |
| | | 845 | sc->sc_smw.smw_period = WBSIO_WDT_CNTR_MAX; |
| | | 846 | |
| | | 847 | if (sysmon_wdog_register(&sc->sc_smw)) |
| | | 848 | aprint_error_dev(self, "couldn't register with sysmon\n"); |
| | | 849 | else |
| | | 850 | sc->sc_smw_valid = true; |
| | | 851 | } |
| | | 852 | |
| | | 853 | static int |
| | | 854 | wbsio_wdog_detach(device_t self) |
| | | 855 | { |
| | | 856 | struct wbsio_softc *sc = device_private(self); |
| | | 857 | int error; |
| | | 858 | |
| | | 859 | error = 0; |
| | | 860 | |
| | | 861 | if (sc->sc_smw_valid) { |
| | | 862 | if ((sc->sc_smw.smw_mode & WDOG_MODE_MASK) |
| | | 863 | != WDOG_MODE_DISARMED) |
| | | 864 | return EBUSY; |
| | | 865 | |
| | | 866 | error = sysmon_wdog_unregister(&sc->sc_smw); |
| | | 867 | } |
| | | 868 | |
| | | 869 | if (!error) |
| | | 870 | sc->sc_smw_valid = false; |
| | | 871 | |
| | | 872 | return error; |
| | | 873 | } |
| | | 874 | |
| | | 875 | static int |
| | | 876 | wbsio_wdog_setmode(struct sysmon_wdog *smw) |
| | | 877 | { |
| | | 878 | |
| | | 879 | switch(smw->smw_mode & WDOG_MODE_MASK) { |
| | | 880 | case WDOG_MODE_DISARMED: |
| | | 881 | wbsio_wdog_setcounter(smw->smw_cookie, WBSIO_WDT_CNTR_STOP); |
| | | 882 | wbsio_wdog_clear_timeout(smw->smw_cookie); |
| | | 883 | break; |
| | | 884 | default: |
| | | 885 | if (smw->smw_period > WBSIO_WDT_CNTR_MAX |
| | | 886 | || smw->smw_period == 0) |
| | | 887 | return EINVAL; |
| | | 888 | |
| | | 889 | wbsio_wdog_setcounter(smw->smw_cookie, smw->smw_period); |
| | | 890 | } |
| | | 891 | |
| | | 892 | return 0; |
| | | 893 | } |
| | | 894 | |
| | | 895 | static void |
| | | 896 | wbsio_wdog_setcounter(struct wbsio_softc *sc, uint8_t period) |
| | | 897 | { |
| | | 898 | |
| | | 899 | KASSERT(!mutex_owned(&sc->sc_conf_lock)); |
| | | 900 | |
| | | 901 | wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
| | | 902 | |
| | | 903 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); |
| | | 904 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_WDT_CNTR, period); |
| | | 905 | |
| | | 906 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); |
| | | 907 | |
| | | 908 | |
| | | 909 | wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
| | | 910 | } |
| | | 911 | |
| | | 912 | static void |
| | | 913 | wbsio_wdog_clear_timeout(struct wbsio_softc *sc) |
| | | 914 | { |
| | | 915 | uint8_t st; |
| | | 916 | |
| | | 917 | KASSERT(!mutex_owned(&sc->sc_conf_lock)); |
| | | 918 | |
| | | 919 | wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
| | | 920 | |
| | | 921 | st = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_WDT_STAT); |
| | | 922 | st &= ~WBSIO_WDT_STAT_TIMEOUT; |
| | | 923 | wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_WDT_STAT, st); |
| | | 924 | |
| | | 925 | wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); |
| | | 926 | } |
| | | 927 | |
| | | 928 | static int |
| | | 929 | wbsio_wdog_tickle(struct sysmon_wdog *smw) |
| | | 930 | { |
| | | 931 | |
| | | 932 | wbsio_wdog_setcounter(smw->smw_cookie, smw->smw_period); |
| | | 933 | |
| | | 934 | return 0; |
744 | } | | 935 | } |
745 | | | 936 | |
746 | #endif | | | |
747 | | | 937 | |
748 | MODULE(MODULE_CLASS_DRIVER, wbsio, NULL); | | 938 | MODULE(MODULE_CLASS_DRIVER, wbsio, NULL); |
749 | | | 939 | |
750 | #ifdef _MODULE | | 940 | #ifdef _MODULE |
751 | #include "ioconf.c" | | 941 | #include "ioconf.c" |
752 | #endif | | 942 | #endif |
753 | | | 943 | |
754 | static int | | 944 | static int |
755 | wbsio_modcmd(modcmd_t cmd, void *opaque) | | 945 | wbsio_modcmd(modcmd_t cmd, void *opaque) |
756 | { | | 946 | { |
757 | switch (cmd) { | | 947 | switch (cmd) { |
758 | case MODULE_CMD_INIT: | | 948 | case MODULE_CMD_INIT: |
759 | #ifdef _MODULE | | 949 | #ifdef _MODULE |