| @@ -1,343 +1,373 @@ | | | @@ -1,343 +1,373 @@ |
1 | /* $NetBSD: smsc.c,v 1.10 2011/06/20 18:12:54 pgoyette Exp $ */ | | 1 | /* $NetBSD: smsc.c,v 1.11 2011/07/31 16:18:54 jmcneill Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2007 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2007 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Brett Lymn. | | 8 | * by Brett Lymn. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * This is a driver for the Standard Microsystems Corp (SMSC) | | 33 | * This is a driver for the Standard Microsystems Corp (SMSC) |
34 | * LPC47B397 "super i/o" chip. This driver only handles the environment | | 34 | * LPC47B397 "super i/o" chip. This driver only handles the environment |
35 | * monitoring capabilities of the chip, the other functions will be | | 35 | * monitoring capabilities of the chip, the other functions will be |
36 | * probed/matched as "normal" PC hardware devices (serial ports, fdc, so on). | | 36 | * probed/matched as "normal" PC hardware devices (serial ports, fdc, so on). |
37 | * SMSC has not deigned to release a datasheet for this particular chip | | 37 | * SMSC has not deigned to release a datasheet for this particular chip |
38 | * (though they do for others they make) so this driver was written from | | 38 | * (though they do for others they make) so this driver was written from |
39 | * information contained in the comment block for the Linux driver. | | 39 | * information contained in the comment block for the Linux driver. |
40 | */ | | 40 | */ |
41 | | | 41 | |
42 | #include <sys/cdefs.h> | | 42 | #include <sys/cdefs.h> |
43 | __KERNEL_RCSID(0, "$NetBSD: smsc.c,v 1.10 2011/06/20 18:12:54 pgoyette Exp $"); | | 43 | __KERNEL_RCSID(0, "$NetBSD: smsc.c,v 1.11 2011/07/31 16:18:54 jmcneill Exp $"); |
44 | | | 44 | |
45 | #include <sys/param.h> | | 45 | #include <sys/param.h> |
46 | #include <sys/systm.h> | | 46 | #include <sys/systm.h> |
47 | #include <sys/device.h> | | 47 | #include <sys/device.h> |
| | | 48 | #include <sys/module.h> |
48 | #include <sys/bus.h> | | 49 | #include <sys/bus.h> |
49 | | | 50 | |
50 | #include <dev/isa/isareg.h> | | 51 | #include <dev/isa/isareg.h> |
51 | #include <dev/isa/isavar.h> | | 52 | #include <dev/isa/isavar.h> |
52 | | | 53 | |
53 | #include <dev/sysmon/sysmonvar.h> | | 54 | #include <dev/sysmon/sysmonvar.h> |
54 | #include <dev/isa/smscvar.h> | | 55 | #include <dev/isa/smscvar.h> |
55 | | | 56 | |
56 | #if defined(LMDEBUG) | | 57 | #if defined(LMDEBUG) |
57 | #define DPRINTF(x) do { printf x; } while (0) | | 58 | #define DPRINTF(x) do { printf x; } while (0) |
58 | #else | | 59 | #else |
59 | #define DPRINTF(x) | | 60 | #define DPRINTF(x) |
60 | #endif | | 61 | #endif |
61 | | | 62 | |
62 | static int smsc_match(device_t, cfdata_t, void *); | | 63 | static int smsc_match(device_t, cfdata_t, void *); |
63 | static void smsc_attach(device_t, device_t, void *); | | 64 | static void smsc_attach(device_t, device_t, void *); |
64 | static int smsc_detach(device_t, int); | | 65 | static int smsc_detach(device_t, int); |
65 | | | 66 | |
66 | static uint8_t smsc_readreg(bus_space_tag_t, bus_space_handle_t, int); | | 67 | static uint8_t smsc_readreg(bus_space_tag_t, bus_space_handle_t, int); |
67 | static void smsc_writereg(bus_space_tag_t, bus_space_handle_t, int, int); | | 68 | static void smsc_writereg(bus_space_tag_t, bus_space_handle_t, int, int); |
68 | | | 69 | |
69 | static void smsc_refresh(struct sysmon_envsys *, envsys_data_t *); | | 70 | static void smsc_refresh(struct sysmon_envsys *, envsys_data_t *); |
70 | | | 71 | |
71 | CFATTACH_DECL_NEW(smsc, sizeof(struct smsc_softc), | | 72 | CFATTACH_DECL_NEW(smsc, sizeof(struct smsc_softc), |
72 | smsc_match, smsc_attach, smsc_detach, NULL); | | 73 | smsc_match, smsc_attach, smsc_detach, NULL); |
73 | | | 74 | |
74 | /* | | 75 | /* |
75 | * Probe for the SMSC Super I/O chip | | 76 | * Probe for the SMSC Super I/O chip |
76 | */ | | 77 | */ |
77 | static int | | 78 | static int |
78 | smsc_match(device_t parent, cfdata_t match, void *aux) | | 79 | smsc_match(device_t parent, cfdata_t match, void *aux) |
79 | { | | 80 | { |
80 | bus_space_handle_t ioh; | | 81 | bus_space_handle_t ioh; |
81 | struct isa_attach_args *ia = aux; | | 82 | struct isa_attach_args *ia = aux; |
82 | int rv; | | 83 | int rv; |
83 | uint8_t cr; | | 84 | uint8_t cr; |
84 | | | 85 | |
85 | /* Must supply an address */ | | 86 | /* Must supply an address */ |
86 | if (ia->ia_nio < 1) | | 87 | if (ia->ia_nio < 1) |
87 | return 0; | | 88 | return 0; |
88 | | | 89 | |
89 | if (ISA_DIRECT_CONFIG(ia)) | | 90 | if (ISA_DIRECT_CONFIG(ia)) |
90 | return 0; | | 91 | return 0; |
91 | | | 92 | |
92 | if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) | | 93 | if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) |
93 | return 0; | | 94 | return 0; |
94 | | | 95 | |
95 | if (bus_space_map(ia->ia_iot, ia->ia_io[0].ir_addr, 2, 0, &ioh)) | | 96 | if (bus_space_map(ia->ia_iot, ia->ia_io[0].ir_addr, 2, 0, &ioh)) |
96 | return 0; | | 97 | return 0; |
97 | | | 98 | |
98 | /* To get the device ID we must enter config mode... */ | | 99 | /* To get the device ID we must enter config mode... */ |
99 | bus_space_write_1(ia->ia_iot, ioh, SMSC_ADDR, SMSC_CONFIG_START); | | 100 | bus_space_write_1(ia->ia_iot, ioh, SMSC_ADDR, SMSC_CONFIG_START); |
100 | | | 101 | |
101 | /* Then select the device id register */ | | 102 | /* Then select the device id register */ |
102 | cr = smsc_readreg(ia->ia_iot, ioh, SMSC_DEVICE_ID); | | 103 | cr = smsc_readreg(ia->ia_iot, ioh, SMSC_DEVICE_ID); |
103 | | | 104 | |
104 | /* Exit config mode, apparently this is important to do */ | | 105 | /* Exit config mode, apparently this is important to do */ |
105 | bus_space_write_1(ia->ia_iot, ioh, SMSC_ADDR, SMSC_CONFIG_END); | | 106 | bus_space_write_1(ia->ia_iot, ioh, SMSC_ADDR, SMSC_CONFIG_END); |
106 | | | 107 | |
107 | switch (cr) { | | 108 | switch (cr) { |
108 | case SMSC_ID_47B397: | | 109 | case SMSC_ID_47B397: |
109 | case SMSC_ID_SCH5307NS: | | 110 | case SMSC_ID_SCH5307NS: |
110 | case SMSC_ID_SCH5317: | | 111 | case SMSC_ID_SCH5317: |
111 | rv = 1; | | 112 | rv = 1; |
112 | break; | | 113 | break; |
113 | default: | | 114 | default: |
114 | rv = 0; | | 115 | rv = 0; |
115 | break; | | 116 | break; |
116 | } | | 117 | } |
117 | | | 118 | |
118 | DPRINTF(("smsc: rv = %d, cr = %x\n", rv, cr)); | | 119 | DPRINTF(("smsc: rv = %d, cr = %x\n", rv, cr)); |
119 | | | 120 | |
120 | bus_space_unmap(ia->ia_iot, ioh, 2); | | 121 | bus_space_unmap(ia->ia_iot, ioh, 2); |
121 | | | 122 | |
122 | if (rv) { | | 123 | if (rv) { |
123 | ia->ia_nio = 1; | | 124 | ia->ia_nio = 1; |
124 | ia->ia_io[0].ir_size = 2; | | 125 | ia->ia_io[0].ir_size = 2; |
125 | | | 126 | |
126 | ia->ia_niomem = 0; | | 127 | ia->ia_niomem = 0; |
127 | ia->ia_nirq = 0; | | 128 | ia->ia_nirq = 0; |
128 | ia->ia_ndrq = 0; | | 129 | ia->ia_ndrq = 0; |
129 | } | | 130 | } |
130 | | | 131 | |
131 | return rv; | | 132 | return rv; |
132 | } | | 133 | } |
133 | | | 134 | |
134 | /* | | 135 | /* |
135 | * Get the base address for the monitoring registers and set up the | | 136 | * Get the base address for the monitoring registers and set up the |
136 | * sysmon_envsys(9) framework. | | 137 | * sysmon_envsys(9) framework. |
137 | */ | | 138 | */ |
138 | static void | | 139 | static void |
139 | smsc_attach(device_t parent, device_t self, void *aux) | | 140 | smsc_attach(device_t parent, device_t self, void *aux) |
140 | { | | 141 | { |
141 | struct smsc_softc *sc = device_private(self); | | 142 | struct smsc_softc *sc = device_private(self); |
142 | struct isa_attach_args *ia = aux; | | 143 | struct isa_attach_args *ia = aux; |
143 | bus_space_handle_t ioh; | | 144 | bus_space_handle_t ioh; |
144 | uint8_t rev, msb, lsb, chipid; | | 145 | uint8_t rev, msb, lsb, chipid; |
145 | unsigned address; | | 146 | unsigned address; |
146 | int i; | | 147 | int i; |
147 | | | 148 | |
148 | sc->sc_iot = ia->ia_iot; | | 149 | sc->sc_iot = ia->ia_iot; |
149 | | | 150 | |
150 | aprint_naive("\n"); | | 151 | aprint_naive("\n"); |
151 | | | 152 | |
152 | /* | | 153 | /* |
153 | * To attach we need to find the actual Hardware Monitor | | 154 | * To attach we need to find the actual Hardware Monitor |
154 | * I/O address space. | | 155 | * I/O address space. |
155 | */ | | 156 | */ |
156 | if (bus_space_map(ia->ia_iot, ia->ia_io[0].ir_addr, 2, 0, | | 157 | if (bus_space_map(ia->ia_iot, ia->ia_io[0].ir_addr, 2, 0, |
157 | &ioh)) { | | 158 | &ioh)) { |
158 | aprint_error(": can't map base i/o space\n"); | | 159 | aprint_error(": can't map base i/o space\n"); |
159 | return; | | 160 | return; |
160 | } | | 161 | } |
161 | | | 162 | |
162 | /* Enter config mode */ | | 163 | /* Enter config mode */ |
163 | bus_space_write_1(ia->ia_iot, ioh, SMSC_ADDR, SMSC_CONFIG_START); | | 164 | bus_space_write_1(ia->ia_iot, ioh, SMSC_ADDR, SMSC_CONFIG_START); |
164 | | | 165 | |
165 | /* | | 166 | /* |
166 | * While we have the base registers mapped, grab the chip | | 167 | * While we have the base registers mapped, grab the chip |
167 | * revision and device ID. | | 168 | * revision and device ID. |
168 | */ | | 169 | */ |
169 | rev = smsc_readreg(ia->ia_iot, ioh, SMSC_DEVICE_REVISION); | | 170 | rev = smsc_readreg(ia->ia_iot, ioh, SMSC_DEVICE_REVISION); |
170 | chipid = smsc_readreg(ia->ia_iot, ioh, SMSC_DEVICE_ID); | | 171 | chipid = smsc_readreg(ia->ia_iot, ioh, SMSC_DEVICE_ID); |
171 | | | 172 | |
172 | /* Select the Hardware Monitor LDN */ | | 173 | /* Select the Hardware Monitor LDN */ |
173 | smsc_writereg(ia->ia_iot, ioh, SMSC_LOGICAL_DEV_SEL, | | 174 | smsc_writereg(ia->ia_iot, ioh, SMSC_LOGICAL_DEV_SEL, |
174 | SMSC_LOGICAL_DEVICE); | | 175 | SMSC_LOGICAL_DEVICE); |
175 | | | 176 | |
176 | /* Read the base address for the registers. */ | | 177 | /* Read the base address for the registers. */ |
177 | msb = smsc_readreg(ia->ia_iot, ioh, SMSC_IO_BASE_MSB); | | 178 | msb = smsc_readreg(ia->ia_iot, ioh, SMSC_IO_BASE_MSB); |
178 | lsb = smsc_readreg(ia->ia_iot, ioh, SMSC_IO_BASE_LSB); | | 179 | lsb = smsc_readreg(ia->ia_iot, ioh, SMSC_IO_BASE_LSB); |
179 | address = (msb << 8) | lsb; | | 180 | address = (msb << 8) | lsb; |
180 | | | 181 | |
181 | /* Exit config mode */ | | 182 | /* Exit config mode */ |
182 | bus_space_write_1(ia->ia_iot, ioh, SMSC_ADDR, SMSC_CONFIG_END); | | 183 | bus_space_write_1(ia->ia_iot, ioh, SMSC_ADDR, SMSC_CONFIG_END); |
183 | bus_space_unmap(ia->ia_iot, ioh, 2); | | 184 | bus_space_unmap(ia->ia_iot, ioh, 2); |
184 | | | 185 | |
185 | /* Map the Hardware Monitor I/O space. */ | | 186 | /* Map the Hardware Monitor I/O space. */ |
186 | if (bus_space_map(ia->ia_iot, address, 2, 0, &sc->sc_ioh)) { | | 187 | if (bus_space_map(ia->ia_iot, address, 2, 0, &sc->sc_ioh)) { |
187 | aprint_error(": can't map register i/o space\n"); | | 188 | aprint_error(": can't map register i/o space\n"); |
188 | return; | | 189 | return; |
189 | } | | 190 | } |
190 | | | 191 | |
191 | sc->sc_sme = sysmon_envsys_create(); | | 192 | sc->sc_sme = sysmon_envsys_create(); |
192 | | | 193 | |
193 | #define INITSENSOR(index, string, reg, type) \ | | 194 | #define INITSENSOR(index, string, reg, type) \ |
194 | do { \ | | 195 | do { \ |
195 | strlcpy(sc->sc_sensor[index].desc, string, \ | | 196 | strlcpy(sc->sc_sensor[index].desc, string, \ |
196 | sizeof(sc->sc_sensor[index].desc)); \ | | 197 | sizeof(sc->sc_sensor[index].desc)); \ |
197 | sc->sc_sensor[index].units = type; \ | | 198 | sc->sc_sensor[index].units = type; \ |
198 | sc->sc_regs[index] = reg; \ | | 199 | sc->sc_regs[index] = reg; \ |
199 | sc->sc_sensor[index].state = ENVSYS_SVALID; \ | | 200 | sc->sc_sensor[index].state = ENVSYS_SVALID; \ |
200 | } while (/* CONSTCOND */ 0) | | 201 | } while (/* CONSTCOND */ 0) |
201 | | | 202 | |
202 | /* Temperature sensors */ | | 203 | /* Temperature sensors */ |
203 | INITSENSOR(0, "Temp0", SMSC_TEMP1, ENVSYS_STEMP); | | 204 | INITSENSOR(0, "Temp0", SMSC_TEMP1, ENVSYS_STEMP); |
204 | INITSENSOR(1, "Temp1", SMSC_TEMP2, ENVSYS_STEMP); | | 205 | INITSENSOR(1, "Temp1", SMSC_TEMP2, ENVSYS_STEMP); |
205 | INITSENSOR(2, "Temp2", SMSC_TEMP3, ENVSYS_STEMP); | | 206 | INITSENSOR(2, "Temp2", SMSC_TEMP3, ENVSYS_STEMP); |
206 | INITSENSOR(3, "Temp3", SMSC_TEMP4, ENVSYS_STEMP); | | 207 | INITSENSOR(3, "Temp3", SMSC_TEMP4, ENVSYS_STEMP); |
207 | | | 208 | |
208 | /* Fan sensors */ | | 209 | /* Fan sensors */ |
209 | INITSENSOR(4, "Fan0", SMSC_FAN1_LSB, ENVSYS_SFANRPM); | | 210 | INITSENSOR(4, "Fan0", SMSC_FAN1_LSB, ENVSYS_SFANRPM); |
210 | INITSENSOR(5, "Fan1", SMSC_FAN2_LSB, ENVSYS_SFANRPM); | | 211 | INITSENSOR(5, "Fan1", SMSC_FAN2_LSB, ENVSYS_SFANRPM); |
211 | INITSENSOR(6, "Fan2", SMSC_FAN3_LSB, ENVSYS_SFANRPM); | | 212 | INITSENSOR(6, "Fan2", SMSC_FAN3_LSB, ENVSYS_SFANRPM); |
212 | INITSENSOR(7, "Fan3", SMSC_FAN4_LSB, ENVSYS_SFANRPM); | | 213 | INITSENSOR(7, "Fan3", SMSC_FAN4_LSB, ENVSYS_SFANRPM); |
213 | | | 214 | |
214 | for (i = 0; i < SMSC_MAX_SENSORS; i++) { | | 215 | for (i = 0; i < SMSC_MAX_SENSORS; i++) { |
215 | sc->sc_sensor[i].state = ENVSYS_SINVALID; | | 216 | sc->sc_sensor[i].state = ENVSYS_SINVALID; |
216 | if (sysmon_envsys_sensor_attach(sc->sc_sme, | | 217 | if (sysmon_envsys_sensor_attach(sc->sc_sme, |
217 | &sc->sc_sensor[i])) { | | 218 | &sc->sc_sensor[i])) { |
218 | sysmon_envsys_destroy(sc->sc_sme); | | 219 | sysmon_envsys_destroy(sc->sc_sme); |
219 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, 2); | | 220 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, 2); |
220 | return; | | 221 | return; |
221 | } | | 222 | } |
222 | } | | 223 | } |
223 | | | 224 | |
224 | sc->sc_sme->sme_name = device_xname(self); | | 225 | sc->sc_sme->sme_name = device_xname(self); |
225 | sc->sc_sme->sme_cookie = sc; | | 226 | sc->sc_sme->sme_cookie = sc; |
226 | sc->sc_sme->sme_refresh = smsc_refresh; | | 227 | sc->sc_sme->sme_refresh = smsc_refresh; |
227 | | | 228 | |
228 | if ((i = sysmon_envsys_register(sc->sc_sme)) != 0) { | | 229 | if ((i = sysmon_envsys_register(sc->sc_sme)) != 0) { |
229 | aprint_error(": unable to register with sysmon (%d)\n", i); | | 230 | aprint_error(": unable to register with sysmon (%d)\n", i); |
230 | sysmon_envsys_destroy(sc->sc_sme); | | 231 | sysmon_envsys_destroy(sc->sc_sme); |
231 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, 2); | | 232 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, 2); |
232 | return; | | 233 | return; |
233 | } | | 234 | } |
234 | | | 235 | |
235 | switch (chipid) { | | 236 | switch (chipid) { |
236 | case SMSC_ID_47B397: | | 237 | case SMSC_ID_47B397: |
237 | aprint_normal(": SMSC LPC47B397 Super I/O"); | | 238 | aprint_normal(": SMSC LPC47B397 Super I/O"); |
238 | break; | | 239 | break; |
239 | case SMSC_ID_SCH5307NS: | | 240 | case SMSC_ID_SCH5307NS: |
240 | aprint_normal(": SMSC SCH5307-NS Super I/O"); | | 241 | aprint_normal(": SMSC SCH5307-NS Super I/O"); |
241 | break; | | 242 | break; |
242 | case SMSC_ID_SCH5317: | | 243 | case SMSC_ID_SCH5317: |
243 | aprint_normal(": SMSC SCH5317 Super I/O"); | | 244 | aprint_normal(": SMSC SCH5317 Super I/O"); |
244 | break; | | 245 | break; |
245 | } | | 246 | } |
246 | | | 247 | |
247 | aprint_normal(" (rev %u)\n", rev); | | 248 | aprint_normal(" (rev %u)\n", rev); |
248 | aprint_normal_dev(self, "Hardware Monitor registers at 0x%04x\n", | | 249 | aprint_normal_dev(self, "Hardware Monitor registers at 0x%04x\n", |
249 | address); | | 250 | address); |
250 | } | | 251 | } |
251 | | | 252 | |
252 | static int | | 253 | static int |
253 | smsc_detach(device_t self, int flags) | | 254 | smsc_detach(device_t self, int flags) |
254 | { | | 255 | { |
255 | struct smsc_softc *sc = device_private(self); | | 256 | struct smsc_softc *sc = device_private(self); |
256 | | | 257 | |
257 | sysmon_envsys_unregister(sc->sc_sme); | | 258 | sysmon_envsys_unregister(sc->sc_sme); |
258 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, 2); | | 259 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, 2); |
259 | return 0; | | 260 | return 0; |
260 | } | | 261 | } |
261 | | | 262 | |
262 | /* | | 263 | /* |
263 | * Read the value of the given register | | 264 | * Read the value of the given register |
264 | */ | | 265 | */ |
265 | static uint8_t | | 266 | static uint8_t |
266 | smsc_readreg(bus_space_tag_t iot, bus_space_handle_t ioh, int reg) | | 267 | smsc_readreg(bus_space_tag_t iot, bus_space_handle_t ioh, int reg) |
267 | { | | 268 | { |
268 | bus_space_write_1(iot, ioh, SMSC_ADDR, reg); | | 269 | bus_space_write_1(iot, ioh, SMSC_ADDR, reg); |
269 | return bus_space_read_1(iot, ioh, SMSC_DATA); | | 270 | return bus_space_read_1(iot, ioh, SMSC_DATA); |
270 | } | | 271 | } |
271 | | | 272 | |
272 | /* | | 273 | /* |
273 | * Write the given value to the given register. | | 274 | * Write the given value to the given register. |
274 | */ | | 275 | */ |
275 | static void | | 276 | static void |
276 | smsc_writereg(bus_space_tag_t iot, bus_space_handle_t ioh, int reg, int val) | | 277 | smsc_writereg(bus_space_tag_t iot, bus_space_handle_t ioh, int reg, int val) |
277 | { | | 278 | { |
278 | bus_space_write_1(iot, ioh, SMSC_ADDR, reg); | | 279 | bus_space_write_1(iot, ioh, SMSC_ADDR, reg); |
279 | bus_space_write_1(iot, ioh, SMSC_DATA, val); | | 280 | bus_space_write_1(iot, ioh, SMSC_DATA, val); |
280 | } | | 281 | } |
281 | | | 282 | |
282 | /* convert temperature read from the chip to micro kelvin */ | | 283 | /* convert temperature read from the chip to micro kelvin */ |
283 | static inline int | | 284 | static inline int |
284 | smsc_temp2muk(uint8_t t) | | 285 | smsc_temp2muk(uint8_t t) |
285 | { | | 286 | { |
286 | int temp=t; | | 287 | int temp=t; |
287 | | | 288 | |
288 | return temp * 1000000 + 273150000U; | | 289 | return temp * 1000000 + 273150000U; |
289 | } | | 290 | } |
290 | | | 291 | |
291 | /* | | 292 | /* |
292 | * convert register value read from chip into rpm using: | | 293 | * convert register value read from chip into rpm using: |
293 | * | | 294 | * |
294 | * RPM = 60/(Count * 11.111us) | | 295 | * RPM = 60/(Count * 11.111us) |
295 | * | | 296 | * |
296 | * 1/1.1111us = 90kHz | | 297 | * 1/1.1111us = 90kHz |
297 | * | | 298 | * |
298 | */ | | 299 | */ |
299 | static inline int | | 300 | static inline int |
300 | smsc_reg2rpm(unsigned int r) | | 301 | smsc_reg2rpm(unsigned int r) |
301 | { | | 302 | { |
302 | unsigned long rpm; | | 303 | unsigned long rpm; |
303 | | | 304 | |
304 | if (r == 0x0) | | 305 | if (r == 0x0) |
305 | return 0; | | 306 | return 0; |
306 | | | 307 | |
307 | rpm = (90000 * 60) / ((unsigned long) r); | | 308 | rpm = (90000 * 60) / ((unsigned long) r); |
308 | return (int) rpm; | | 309 | return (int) rpm; |
309 | } | | 310 | } |
310 | | | 311 | |
311 | /* min and max temperatures in uK */ | | 312 | /* min and max temperatures in uK */ |
312 | #define SMSC_MIN_TEMP_UK ((-127 * 1000000) + 273150000) | | 313 | #define SMSC_MIN_TEMP_UK ((-127 * 1000000) + 273150000) |
313 | #define SMSC_MAX_TEMP_UK ((127 * 1000000) + 273150000) | | 314 | #define SMSC_MAX_TEMP_UK ((127 * 1000000) + 273150000) |
314 | | | 315 | |
315 | /* | | 316 | /* |
316 | * Get the data for the requested sensor, update the sysmon structure | | 317 | * Get the data for the requested sensor, update the sysmon structure |
317 | * with the retrieved value. | | 318 | * with the retrieved value. |
318 | */ | | 319 | */ |
319 | static void | | 320 | static void |
320 | smsc_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) | | 321 | smsc_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) |
321 | { | | 322 | { |
322 | struct smsc_softc *sc = sme->sme_cookie; | | 323 | struct smsc_softc *sc = sme->sme_cookie; |
323 | int reg; | | 324 | int reg; |
324 | unsigned int rpm; | | 325 | unsigned int rpm; |
325 | uint8_t msb, lsb; | | 326 | uint8_t msb, lsb; |
326 | | | 327 | |
327 | reg = sc->sc_regs[edata->sensor]; | | 328 | reg = sc->sc_regs[edata->sensor]; |
328 | | | 329 | |
329 | switch (edata->units) { | | 330 | switch (edata->units) { |
330 | case ENVSYS_STEMP: | | 331 | case ENVSYS_STEMP: |
331 | edata->value_cur = | | 332 | edata->value_cur = |
332 | smsc_temp2muk(smsc_readreg(sc->sc_iot, sc->sc_ioh, reg)); | | 333 | smsc_temp2muk(smsc_readreg(sc->sc_iot, sc->sc_ioh, reg)); |
333 | break; | | 334 | break; |
334 | | | 335 | |
335 | case ENVSYS_SFANRPM: | | 336 | case ENVSYS_SFANRPM: |
336 | /* reading lsb first locks msb... */ | | 337 | /* reading lsb first locks msb... */ |
337 | lsb = smsc_readreg(sc->sc_iot, sc->sc_ioh, reg); | | 338 | lsb = smsc_readreg(sc->sc_iot, sc->sc_ioh, reg); |
338 | msb = smsc_readreg(sc->sc_iot, sc->sc_ioh, reg + 1); | | 339 | msb = smsc_readreg(sc->sc_iot, sc->sc_ioh, reg + 1); |
339 | rpm = (msb << 8) | lsb; | | 340 | rpm = (msb << 8) | lsb; |
340 | edata->value_cur = smsc_reg2rpm(rpm); | | 341 | edata->value_cur = smsc_reg2rpm(rpm); |
341 | break; | | 342 | break; |
342 | } | | 343 | } |
343 | } | | 344 | } |
| | | 345 | |
| | | 346 | MODULE(MODULE_CLASS_DRIVER, smsc, NULL); |
| | | 347 | |
| | | 348 | #ifdef _MODULE |
| | | 349 | #include "ioconf.c" |
| | | 350 | #endif |
| | | 351 | |
| | | 352 | static int |
| | | 353 | smsc_modcmd(modcmd_t cmd, void *opaque) |
| | | 354 | { |
| | | 355 | int error = 0; |
| | | 356 | |
| | | 357 | switch (cmd) { |
| | | 358 | case MODULE_CMD_INIT: |
| | | 359 | #ifdef _MODULE |
| | | 360 | error = config_init_component(cfdriver_ioconf_smsc, |
| | | 361 | cfattach_ioconf_smsc, cfdata_ioconf_smsc); |
| | | 362 | #endif |
| | | 363 | return error; |
| | | 364 | case MODULE_CMD_FINI: |
| | | 365 | #ifdef _MODULE |
| | | 366 | error = config_fini_component(cfdriver_ioconf_smsc, |
| | | 367 | cfattach_ioconf_smsc, cfdata_ioconf_smsc); |
| | | 368 | #endif |
| | | 369 | return error; |
| | | 370 | default: |
| | | 371 | return ENOTTY; |
| | | 372 | } |
| | | 373 | } |