| @@ -1,544 +1,550 @@ | | | @@ -1,544 +1,550 @@ |
1 | /*- | | 1 | /*- |
2 | * Copyright (c) 2015 The NetBSD Foundation, Inc. | | 2 | * Copyright (c) 2015 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 | #include <sys/cdefs.h> | | 30 | #include <sys/cdefs.h> |
31 | __KERNEL_RCSID(0, "$NetBSD: adm1026.c,v 1.7 2019/12/23 02:25:28 thorpej Exp $"); | | 31 | __KERNEL_RCSID(0, "$NetBSD: adm1026.c,v 1.8 2020/06/26 10:06:57 martin Exp $"); |
32 | | | 32 | |
33 | #include <sys/param.h> | | 33 | #include <sys/param.h> |
34 | #include <sys/systm.h> | | 34 | #include <sys/systm.h> |
35 | #include <sys/device.h> | | 35 | #include <sys/device.h> |
36 | #include <sys/kernel.h> | | 36 | #include <sys/kernel.h> |
37 | #include <sys/sysctl.h> | | 37 | #include <sys/sysctl.h> |
38 | | | 38 | |
39 | #include <dev/sysmon/sysmonvar.h> | | 39 | #include <dev/sysmon/sysmonvar.h> |
40 | | | 40 | |
41 | #include <dev/i2c/i2cvar.h> | | 41 | #include <dev/i2c/i2cvar.h> |
42 | #include <dev/i2c/adm1026reg.h> | | 42 | #include <dev/i2c/adm1026reg.h> |
43 | | | 43 | |
44 | /* Voltage/analog sensors descriptions and registers */ | | 44 | /* Voltage/analog sensors descriptions and registers */ |
45 | struct adm1026_volts_info { | | 45 | struct adm1026_volts_info { |
46 | const char* desc; | | 46 | const char* desc; |
47 | int incr; | | 47 | int incr; |
48 | uint8_t reg, check_tdm2; | | 48 | uint8_t reg, check_tdm2; |
49 | }; | | 49 | }; |
50 | | | 50 | |
51 | /* Voltage maximums (in mV) from datasheet table 7 divided by 255 increments */ | | 51 | /* Voltage maximums (in mV) from datasheet table 7 divided by 255 increments */ |
52 | static struct adm1026_volts_info adm1026_volts_table[] = { | | 52 | static struct adm1026_volts_info adm1026_volts_table[] = { |
53 | { "Vbatt", 15624, ADM1026_VBAT_VAL, 0 }, | | 53 | { "Vbatt", 15624, ADM1026_VBAT_VAL, 0 }, |
54 | { "V3.3 standby", 17345, ADM1026_33VSTBY_VAL, 0 }, | | 54 | { "V3.3 standby", 17345, ADM1026_33VSTBY_VAL, 0 }, |
55 | { "V3.3 main", 17345, ADM1026_33VMAIN_VAL, 0 }, | | 55 | { "V3.3 main", 17345, ADM1026_33VMAIN_VAL, 0 }, |
56 | { "V5.0", 26016, ADM1026_50V_VAL, 0 }, | | 56 | { "V5.0", 26016, ADM1026_50V_VAL, 0 }, |
57 | { "Vccp", 11718, ADM1026_VCCP_VAL, 0 }, | | 57 | { "Vccp", 11718, ADM1026_VCCP_VAL, 0 }, |
58 | { "V+12", 62502, ADM1026_12V_VAL, 0 }, | | 58 | { "V+12", 62502, ADM1026_12V_VAL, 0 }, |
59 | { "V-12", -62502, ADM1026_N12V_VAL, 0 }, | | 59 | { "V-12", -62502, ADM1026_N12V_VAL, 0 }, |
60 | { "V3.0 0", 11718, ADM1026_AIN_VAL(0), 0 }, | | 60 | { "V3.0 0", 11718, ADM1026_AIN_VAL(0), 0 }, |
61 | { "V3.0 1", 11718, ADM1026_AIN_VAL(1), 0 }, | | 61 | { "V3.0 1", 11718, ADM1026_AIN_VAL(1), 0 }, |
62 | { "V3.0 2", 11718, ADM1026_AIN_VAL(2), 0 }, | | 62 | { "V3.0 2", 11718, ADM1026_AIN_VAL(2), 0 }, |
63 | { "V3.0 3", 11718, ADM1026_AIN_VAL(3), 0 }, | | 63 | { "V3.0 3", 11718, ADM1026_AIN_VAL(3), 0 }, |
64 | { "V3.0 4", 11718, ADM1026_AIN_VAL(4), 0 }, | | 64 | { "V3.0 4", 11718, ADM1026_AIN_VAL(4), 0 }, |
65 | { "V3.0 5", 11718, ADM1026_AIN_VAL(5), 0 }, | | 65 | { "V3.0 5", 11718, ADM1026_AIN_VAL(5), 0 }, |
66 | { "V2.5 0", 9765, ADM1026_AIN_VAL(6), 0 }, | | 66 | { "V2.5 0", 9765, ADM1026_AIN_VAL(6), 0 }, |
67 | { "V2.5 1", 9765, ADM1026_AIN_VAL(7), 0 }, | | 67 | { "V2.5 1", 9765, ADM1026_AIN_VAL(7), 0 }, |
68 | { "V2.5 2", 9765, ADM1026_AIN8_VAL, 1 }, | | 68 | { "V2.5 2", 9765, ADM1026_AIN8_VAL, 1 }, |
69 | { "V2.5 3", 9765, ADM1026_TDM2_AIN9_VAL, 1 } | | 69 | { "V2.5 3", 9765, ADM1026_TDM2_AIN9_VAL, 1 } |
70 | }; | | 70 | }; |
71 | | | 71 | |
72 | /* Maximum number of each type of sensor */ | | 72 | /* Maximum number of each type of sensor */ |
73 | #define ADM1026_MAX_FANS 8 | | 73 | #define ADM1026_MAX_FANS 8 |
74 | #define ADM1026_MAX_TEMPS 3 | | 74 | #define ADM1026_MAX_TEMPS 3 |
75 | #define ADM1026_MAX_VOLTS (sizeof(adm1026_volts_table) / \ | | 75 | #define ADM1026_MAX_VOLTS (sizeof(adm1026_volts_table) / \ |
76 | sizeof (adm1026_volts_table[0])) | | 76 | sizeof (adm1026_volts_table[0])) |
77 | | | 77 | |
78 | /* Map sensor to/from sysmon numbers */ | | 78 | /* Map sensor to/from sysmon numbers */ |
79 | #define ADM1026_FAN_NUM(x) (x) | | 79 | #define ADM1026_FAN_NUM(x) (x) |
80 | #define ADM1026_TEMP_NUM(x) (x + sc->sc_nfans) | | 80 | #define ADM1026_TEMP_NUM(x) (x + sc->sc_nfans) |
81 | #define ADM1026_VOLT_NUM(x) (x + sc->sc_nfans + sc->sc_ntemps) | | 81 | #define ADM1026_VOLT_NUM(x) (x + sc->sc_nfans + sc->sc_ntemps) |
82 | #define ADM1026_NUM_FAN(x) (x) | | 82 | #define ADM1026_NUM_FAN(x) (x) |
83 | #define ADM1026_NUM_TEMP(x) (x - sc->sc_nfans) | | 83 | #define ADM1026_NUM_TEMP(x) (x - sc->sc_nfans) |
84 | #define ADM1026_NUM_VOLT(x) (x - sc->sc_nfans - sc->sc_ntemps) | | 84 | #define ADM1026_NUM_VOLT(x) (x - sc->sc_nfans - sc->sc_ntemps) |
85 | | | 85 | |
86 | struct adm1026_softc { | | 86 | struct adm1026_softc { |
87 | device_t sc_dev; | | 87 | device_t sc_dev; |
88 | i2c_tag_t sc_tag; | | 88 | i2c_tag_t sc_tag; |
89 | int sc_address; | | 89 | int sc_address; |
90 | bool sc_multi_read; | | 90 | bool sc_multi_read; |
91 | | | 91 | |
92 | uint8_t sc_rev, sc_cfg[2]; | | 92 | uint8_t sc_rev, sc_cfg[2]; |
93 | int sc_nfans, sc_ntemps; /* Map sysmon numbers to sensors */ | | 93 | int sc_nfans, sc_ntemps; /* Map sysmon numbers to sensors */ |
94 | int sc_fandiv[ADM1026_MAX_FANS], sc_temp_off[ADM1026_MAX_TEMPS]; | | 94 | int sc_fandiv[ADM1026_MAX_FANS], sc_temp_off[ADM1026_MAX_TEMPS]; |
95 | struct sysmon_envsys *sc_sme; | | 95 | struct sysmon_envsys *sc_sme; |
96 | envsys_data_t sc_sensor[ADM1026_MAX_FANS + ADM1026_MAX_TEMPS + | | 96 | envsys_data_t sc_sensor[ADM1026_MAX_FANS + ADM1026_MAX_TEMPS + |
97 | ADM1026_MAX_VOLTS]; | | 97 | ADM1026_MAX_VOLTS]; |
98 | }; | | 98 | }; |
99 | | | 99 | |
100 | static int adm1026_match(device_t, cfdata_t, void *); | | 100 | static int adm1026_match(device_t, cfdata_t, void *); |
101 | static int adm1026_ident(struct adm1026_softc *, int); | | 101 | static int adm1026_ident(i2c_tag_t, i2c_addr_t, int, uint8_t*); |
102 | static void adm1026_attach(device_t, device_t, void *); | | 102 | static void adm1026_attach(device_t, device_t, void *); |
103 | static int adm1026_detach(device_t, int); | | 103 | static int adm1026_detach(device_t, int); |
104 | bool adm1026_pmf_suspend(device_t, const pmf_qual_t *); | | 104 | bool adm1026_pmf_suspend(device_t, const pmf_qual_t *); |
105 | bool adm1026_pmf_resume(device_t, const pmf_qual_t *); | | 105 | bool adm1026_pmf_resume(device_t, const pmf_qual_t *); |
106 | | | 106 | |
107 | static void adm1026_setup_fans(struct adm1026_softc *sc, int div2_val); | | 107 | static void adm1026_setup_fans(struct adm1026_softc *sc, int div2_val); |
108 | static void adm1026_setup_temps(struct adm1026_softc *sc); | | 108 | static void adm1026_setup_temps(struct adm1026_softc *sc); |
109 | static void adm1026_setup_volts(struct adm1026_softc *sc); | | 109 | static void adm1026_setup_volts(struct adm1026_softc *sc); |
110 | | | 110 | |
111 | void adm1026_refresh(struct sysmon_envsys *sme, envsys_data_t *edata); | | 111 | void adm1026_refresh(struct sysmon_envsys *sme, envsys_data_t *edata); |
112 | static void adm1026_read_fan(struct adm1026_softc *sc, envsys_data_t *edata); | | 112 | static void adm1026_read_fan(struct adm1026_softc *sc, envsys_data_t *edata); |
113 | static void adm1026_read_temp(struct adm1026_softc *sc, envsys_data_t *edata); | | 113 | static void adm1026_read_temp(struct adm1026_softc *sc, envsys_data_t *edata); |
114 | static void adm1026_read_volt(struct adm1026_softc *sc, envsys_data_t *edata); | | 114 | static void adm1026_read_volt(struct adm1026_softc *sc, envsys_data_t *edata); |
115 | | | 115 | |
116 | static int adm1026_read_reg(struct adm1026_softc *sc, | | 116 | static int adm1026_read_reg_int(i2c_tag_t, i2c_addr_t, |
117 | uint8_t reg, uint8_t *val); | | 117 | uint8_t reg, bool multi_read, uint8_t *val); |
118 | static int adm1026_write_reg(struct adm1026_softc *sc, | | 118 | static int adm1026_write_reg(struct adm1026_softc *sc, |
119 | uint8_t reg, uint8_t val); | | 119 | uint8_t reg, uint8_t val); |
120 | | | 120 | |
| | | 121 | static inline int |
| | | 122 | adm1026_read_reg(struct adm1026_softc *sc, uint8_t reg, uint8_t *val) |
| | | 123 | { |
| | | 124 | return adm1026_read_reg_int(sc->sc_tag, sc->sc_address, reg, |
| | | 125 | sc->sc_multi_read, val); |
| | | 126 | } |
| | | 127 | |
121 | CFATTACH_DECL_NEW(adm1026hm, sizeof(struct adm1026_softc), | | 128 | CFATTACH_DECL_NEW(adm1026hm, sizeof(struct adm1026_softc), |
122 | adm1026_match, adm1026_attach, adm1026_detach, NULL); | | 129 | adm1026_match, adm1026_attach, adm1026_detach, NULL); |
123 | | | 130 | |
124 | static const struct device_compatible_entry compat_data[] = { | | 131 | static const struct device_compatible_entry compat_data[] = { |
125 | { "i2c-adm1026", 0 }, | | 132 | { "i2c-adm1026", 0 }, |
126 | { NULL, 0 } | | 133 | { NULL, 0 } |
127 | }; | | 134 | }; |
128 | | | 135 | |
129 | static int | | 136 | static int |
130 | adm1026_match(device_t parent, cfdata_t cf, void *aux) | | 137 | adm1026_match(device_t parent, cfdata_t cf, void *aux) |
131 | { | | 138 | { |
132 | struct i2c_attach_args *ia = aux; | | 139 | struct i2c_attach_args *ia = aux; |
133 | struct adm1026_softc sc; /* For chip ident */ | | | |
134 | int match_result; | | 140 | int match_result; |
135 | | | 141 | uint8_t rev; |
136 | sc.sc_tag = ia->ia_tag; | | | |
137 | sc.sc_address = ia->ia_addr; | | | |
138 | | | 142 | |
139 | if (iic_use_direct_match(ia, cf, compat_data, &match_result)) | | 143 | if (iic_use_direct_match(ia, cf, compat_data, &match_result)) |
140 | return match_result; | | 144 | return match_result; |
141 | | | 145 | |
142 | if (ia->ia_addr == ADM1026_ADDR1 && adm1026_ident(&sc, 1)) | | 146 | if (ia->ia_addr == ADM1026_ADDR1 |
| | | 147 | && adm1026_ident(ia->ia_tag, ia->ia_addr, 1, &rev)) |
143 | return I2C_MATCH_ADDRESS_AND_PROBE; | | 148 | return I2C_MATCH_ADDRESS_AND_PROBE; |
144 | | | 149 | |
145 | return 0; | | 150 | return 0; |
146 | } | | 151 | } |
147 | | | 152 | |
148 | static int | | 153 | static int |
149 | adm1026_ident(struct adm1026_softc *sc, int probe_only) | | 154 | adm1026_ident(i2c_tag_t tag, i2c_addr_t addr, int probe_only, uint8_t *rev) |
150 | { | | 155 | { |
151 | uint8_t val; | | 156 | uint8_t val; |
152 | int err; | | 157 | int err; |
153 | | | 158 | |
154 | /* Manufacturer ID and revision/stepping */ | | 159 | /* Manufacturer ID and revision/stepping */ |
155 | err = adm1026_read_reg(sc, ADM1026_ID, &val); | | 160 | err = adm1026_read_reg_int(tag, addr, ADM1026_ID, false, &val); |
156 | if (err || val != ADM1026_MANF_ID) { | | 161 | if (err || val != ADM1026_MANF_ID) { |
157 | if (!probe_only) | | 162 | if (!probe_only) |
158 | aprint_verbose("adm1026_ident: " | | 163 | aprint_verbose("adm1026_ident: " |
159 | "manufacturer ID invalid or missing\n"); | | 164 | "manufacturer ID invalid or missing\n"); |
160 | return 0; | | 165 | return 0; |
161 | } | | 166 | } |
162 | err = adm1026_read_reg(sc, ADM1026_REV, &sc->sc_rev); | | 167 | err = adm1026_read_reg_int(tag, addr, ADM1026_REV, false, rev); |
163 | if (err || ADM1026_REVISION(sc->sc_rev) != ADM1026_MANF_REV) { | | 168 | if (err || ADM1026_REVISION(*rev) != ADM1026_MANF_REV) { |
164 | if (!probe_only) | | 169 | if (!probe_only) |
165 | aprint_verbose("adm1026_ident: " | | 170 | aprint_verbose("adm1026_ident: " |
166 | "manufacturer revision invalid or missing\n"); | | 171 | "manufacturer revision invalid or missing\n"); |
167 | return 0; | | 172 | return 0; |
168 | } | | 173 | } |
169 | return 1; | | 174 | return 1; |
170 | } | | 175 | } |
171 | | | 176 | |
172 | static void | | 177 | static void |
173 | adm1026_attach(device_t parent, device_t self, void *aux) | | 178 | adm1026_attach(device_t parent, device_t self, void *aux) |
174 | { | | 179 | { |
175 | struct adm1026_softc *sc = device_private(self); | | 180 | struct adm1026_softc *sc = device_private(self); |
176 | struct i2c_attach_args *ia = aux; | | 181 | struct i2c_attach_args *ia = aux; |
177 | prop_dictionary_t props = device_properties(self); | | 182 | prop_dictionary_t props = device_properties(self); |
178 | uint8_t val, fan_div2; | | 183 | uint8_t val, fan_div2; |
179 | int err, div2_val; | | 184 | int err, div2_val; |
180 | | | 185 | |
181 | sc->sc_tag = ia->ia_tag; | | 186 | sc->sc_tag = ia->ia_tag; |
182 | sc->sc_address = ia->ia_addr; | | 187 | sc->sc_address = ia->ia_addr; |
183 | sc->sc_dev = self; | | 188 | sc->sc_dev = self; |
184 | | | 189 | |
185 | sc->sc_multi_read = false; | | 190 | sc->sc_multi_read = false; |
186 | prop_dictionary_get_bool(props, "multi_read", &sc->sc_multi_read); | | 191 | prop_dictionary_get_bool(props, "multi_read", &sc->sc_multi_read); |
187 | if (prop_dictionary_get_uint8(props, "fan_div2", &fan_div2) != 0) | | 192 | if (prop_dictionary_get_uint8(props, "fan_div2", &fan_div2) != 0) |
188 | div2_val = fan_div2; | | 193 | div2_val = fan_div2; |
189 | else | | 194 | else |
190 | div2_val = -1; | | 195 | div2_val = -1; |
191 | | | 196 | |
192 | (void) adm1026_ident(sc, 0); | | 197 | (void) adm1026_ident(sc->sc_tag, sc->sc_address, 0, &sc->sc_rev); |
193 | aprint_normal(": ADM1026 hardware monitor: rev. 0x%x, step. 0x%x\n", | | 198 | aprint_normal(": ADM1026 hardware monitor: rev. 0x%x, step. 0x%x\n", |
194 | ADM1026_REVISION(sc->sc_rev), ADM1026_STEPPING(sc->sc_rev)); | | 199 | ADM1026_REVISION(sc->sc_rev), ADM1026_STEPPING(sc->sc_rev)); |
195 | | | 200 | |
196 | /* | | 201 | /* |
197 | * Start monitoring if not already monitoring. | | 202 | * Start monitoring if not already monitoring. |
198 | * Wait 1.8s for the fan readings to stabilise. | | 203 | * Wait 1.8s for the fan readings to stabilise. |
199 | */ | | 204 | */ |
200 | if ((err = adm1026_read_reg(sc, ADM1026_CONF1, &val)) != 0) { | | 205 | if ((err = adm1026_read_reg(sc, ADM1026_CONF1, &val)) != 0) { |
201 | aprint_error_dev(sc->sc_dev, ": unable to read conf1\n"); | | 206 | aprint_error_dev(sc->sc_dev, ": unable to read conf1\n"); |
202 | return; | | 207 | return; |
203 | } | | 208 | } |
204 | if (!(val & ADM1026_CONF1_MONITOR)) { | | 209 | if (!(val & ADM1026_CONF1_MONITOR)) { |
205 | aprint_normal_dev(sc->sc_dev, | | 210 | aprint_normal_dev(sc->sc_dev, |
206 | ": starting monitoring, waiting 1.8s for readings\n"); | | 211 | ": starting monitoring, waiting 1.8s for readings\n"); |
207 | val |= ADM1026_CONF1_MONITOR; | | 212 | val |= ADM1026_CONF1_MONITOR; |
208 | if ((err = adm1026_write_reg(sc, ADM1026_CONF1, val)) != 0) { | | 213 | if ((err = adm1026_write_reg(sc, ADM1026_CONF1, val)) != 0) { |
209 | aprint_error_dev(sc->sc_dev, | | 214 | aprint_error_dev(sc->sc_dev, |
210 | ": unable to write conf1\n"); | | 215 | ": unable to write conf1\n"); |
211 | return; | | 216 | return; |
212 | } | | 217 | } |
213 | delay(1800000); | | 218 | delay(1800000); |
214 | } | | 219 | } |
215 | sc->sc_cfg[0] = val; | | 220 | sc->sc_cfg[0] = val; |
216 | | | 221 | |
217 | sc->sc_sme = sysmon_envsys_create(); | | 222 | sc->sc_sme = sysmon_envsys_create(); |
218 | sc->sc_nfans = 0; | | 223 | sc->sc_nfans = 0; |
219 | adm1026_setup_fans(sc, div2_val); | | 224 | adm1026_setup_fans(sc, div2_val); |
220 | sc->sc_ntemps = 0; | | 225 | sc->sc_ntemps = 0; |
221 | adm1026_setup_temps(sc); | | 226 | adm1026_setup_temps(sc); |
222 | adm1026_setup_volts(sc); | | 227 | adm1026_setup_volts(sc); |
223 | aprint_normal_dev(self, "%d fans, %d temperatures, %d voltages\n", | | 228 | aprint_normal_dev(self, "%d fans, %d temperatures, %d voltages\n", |
224 | sc->sc_nfans, sc->sc_ntemps, sc->sc_ntemps == 3 ? 15 : 17); | | 229 | sc->sc_nfans, sc->sc_ntemps, sc->sc_ntemps == 3 ? 15 : 17); |
225 | | | 230 | |
226 | sc->sc_sme->sme_name = device_xname(self); | | 231 | sc->sc_sme->sme_name = device_xname(self); |
227 | sc->sc_sme->sme_cookie = sc; | | 232 | sc->sc_sme->sme_cookie = sc; |
228 | sc->sc_sme->sme_refresh = adm1026_refresh; | | 233 | sc->sc_sme->sme_refresh = adm1026_refresh; |
229 | if (sysmon_envsys_register(sc->sc_sme)) { | | 234 | if (sysmon_envsys_register(sc->sc_sme)) { |
230 | aprint_error_dev(self, | | 235 | aprint_error_dev(self, |
231 | "unable to register with sysmon\n"); | | 236 | "unable to register with sysmon\n"); |
232 | sysmon_envsys_destroy(sc->sc_sme); | | 237 | sysmon_envsys_destroy(sc->sc_sme); |
233 | return; | | 238 | return; |
234 | } | | 239 | } |
235 | | | 240 | |
236 | if (!pmf_device_register(self, adm1026_pmf_suspend, adm1026_pmf_resume)) | | 241 | if (!pmf_device_register(self, adm1026_pmf_suspend, adm1026_pmf_resume)) |
237 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 242 | aprint_error_dev(self, "couldn't establish power handler\n"); |
238 | | | 243 | |
239 | return; | | 244 | return; |
240 | } | | 245 | } |
241 | | | 246 | |
242 | /* | | 247 | /* |
243 | * We could stop (suspend/detach) and restart (resume) monitoring, | | 248 | * We could stop (suspend/detach) and restart (resume) monitoring, |
244 | * but we don't do that because some machines have separate | | 249 | * but we don't do that because some machines have separate |
245 | * management hardware which can read the sensors. | | 250 | * management hardware which can read the sensors. |
246 | */ | | 251 | */ |
247 | bool | | 252 | bool |
248 | adm1026_pmf_suspend(device_t dev, const pmf_qual_t *qual) | | 253 | adm1026_pmf_suspend(device_t dev, const pmf_qual_t *qual) |
249 | { | | 254 | { |
250 | return true; | | 255 | return true; |
251 | } | | 256 | } |
252 | | | 257 | |
253 | bool | | 258 | bool |
254 | adm1026_pmf_resume(device_t dev, const pmf_qual_t *qual) | | 259 | adm1026_pmf_resume(device_t dev, const pmf_qual_t *qual) |
255 | { | | 260 | { |
256 | return true; | | 261 | return true; |
257 | } | | 262 | } |
258 | | | 263 | |
259 | static int | | 264 | static int |
260 | adm1026_detach(device_t self, int flags) | | 265 | adm1026_detach(device_t self, int flags) |
261 | { | | 266 | { |
262 | struct adm1026_softc *sc = device_private(self); | | 267 | struct adm1026_softc *sc = device_private(self); |
263 | | | 268 | |
264 | pmf_device_deregister(self); | | 269 | pmf_device_deregister(self); |
265 | | | 270 | |
266 | sysmon_envsys_unregister(sc->sc_sme); | | 271 | sysmon_envsys_unregister(sc->sc_sme); |
267 | sc->sc_sme = NULL; | | 272 | sc->sc_sme = NULL; |
268 | | | 273 | |
269 | return 0; | | 274 | return 0; |
270 | } | | 275 | } |
271 | | | 276 | |
272 | static void | | 277 | static void |
273 | adm1026_setup_fans(struct adm1026_softc *sc, int div2_val) | | 278 | adm1026_setup_fans(struct adm1026_softc *sc, int div2_val) |
274 | { | | 279 | { |
275 | int i, err = 0; | | 280 | int i, err = 0; |
276 | uint8_t div1, div2; | | 281 | uint8_t div1, div2; |
277 | | | 282 | |
278 | /* Read fan-related registers (configuration and divisors) */ | | 283 | /* Read fan-related registers (configuration and divisors) */ |
279 | if ((err = adm1026_read_reg(sc, ADM1026_CONF2, &sc->sc_cfg[1])) != 0) { | | 284 | if ((err = adm1026_read_reg(sc, ADM1026_CONF2, &sc->sc_cfg[1])) != 0) { |
280 | aprint_error_dev(sc->sc_dev, "unable to read conf2\n"); | | 285 | aprint_error_dev(sc->sc_dev, "unable to read conf2\n"); |
281 | return; | | 286 | return; |
282 | } | | 287 | } |
283 | if ((err = adm1026_read_reg(sc, ADM1026_FAN_DIV1, &div1)) != 0) { | | 288 | if ((err = adm1026_read_reg(sc, ADM1026_FAN_DIV1, &div1)) != 0) { |
284 | aprint_error_dev(sc->sc_dev, "unable to read fan_div1\n"); | | 289 | aprint_error_dev(sc->sc_dev, "unable to read fan_div1\n"); |
285 | return; | | 290 | return; |
286 | } | | 291 | } |
287 | sc->sc_fandiv[0] = 1 << ADM1026_FAN0_DIV(div1); | | 292 | sc->sc_fandiv[0] = 1 << ADM1026_FAN0_DIV(div1); |
288 | sc->sc_fandiv[1] = 1 << ADM1026_FAN1_DIV(div1); | | 293 | sc->sc_fandiv[1] = 1 << ADM1026_FAN1_DIV(div1); |
289 | sc->sc_fandiv[2] = 1 << ADM1026_FAN2_DIV(div1); | | 294 | sc->sc_fandiv[2] = 1 << ADM1026_FAN2_DIV(div1); |
290 | sc->sc_fandiv[3] = 1 << ADM1026_FAN3_DIV(div1); | | 295 | sc->sc_fandiv[3] = 1 << ADM1026_FAN3_DIV(div1); |
291 | if (div2_val < 0) { | | 296 | if (div2_val < 0) { |
292 | if ((err = | | 297 | if ((err = |
293 | adm1026_read_reg(sc, ADM1026_FAN_DIV2, &div2)) != 0) { | | 298 | adm1026_read_reg(sc, ADM1026_FAN_DIV2, &div2)) != 0) { |
294 | aprint_error_dev(sc->sc_dev, | | 299 | aprint_error_dev(sc->sc_dev, |
295 | "unable to read fan_div2\n"); | | 300 | "unable to read fan_div2\n"); |
296 | return; | | 301 | return; |
297 | } | | 302 | } |
298 | } else | | 303 | } else |
299 | div2 = div2_val; | | 304 | div2 = div2_val; |
300 | sc->sc_fandiv[4] = 1 << ADM1026_FAN4_DIV(div2); | | 305 | sc->sc_fandiv[4] = 1 << ADM1026_FAN4_DIV(div2); |
301 | sc->sc_fandiv[5] = 1 << ADM1026_FAN5_DIV(div2); | | 306 | sc->sc_fandiv[5] = 1 << ADM1026_FAN5_DIV(div2); |
302 | sc->sc_fandiv[6] = 1 << ADM1026_FAN6_DIV(div2); | | 307 | sc->sc_fandiv[6] = 1 << ADM1026_FAN6_DIV(div2); |
303 | sc->sc_fandiv[7] = 1 << ADM1026_FAN7_DIV(div2); | | 308 | sc->sc_fandiv[7] = 1 << ADM1026_FAN7_DIV(div2); |
304 | | | 309 | |
305 | for (i = 0; i < ADM1026_MAX_FANS; i++) { | | 310 | for (i = 0; i < ADM1026_MAX_FANS; i++) { |
306 | sc->sc_sensor[ADM1026_FAN_NUM(i)].state = ENVSYS_SINVALID; | | 311 | sc->sc_sensor[ADM1026_FAN_NUM(i)].state = ENVSYS_SINVALID; |
307 | /* Check configuration2 register to see which pins are fans. */ | | 312 | /* Check configuration2 register to see which pins are fans. */ |
308 | if (ADM1026_PIN_IS_FAN(sc->sc_cfg[1], i)) { | | 313 | if (ADM1026_PIN_IS_FAN(sc->sc_cfg[1], i)) { |
309 | sc->sc_sensor[ADM1026_FAN_NUM(i)].units = | | 314 | sc->sc_sensor[ADM1026_FAN_NUM(i)].units = |
310 | ENVSYS_SFANRPM; | | 315 | ENVSYS_SFANRPM; |
311 | snprintf(sc->sc_sensor[ADM1026_FAN_NUM(i)].desc, | | 316 | snprintf(sc->sc_sensor[ADM1026_FAN_NUM(i)].desc, |
312 | sizeof(sc->sc_sensor[ADM1026_FAN_NUM(i)].desc), | | 317 | sizeof(sc->sc_sensor[ADM1026_FAN_NUM(i)].desc), |
313 | "fan %d", ADM1026_FAN_NUM(i)); | | 318 | "fan %d", ADM1026_FAN_NUM(i)); |
314 | sc->sc_nfans++; | | 319 | sc->sc_nfans++; |
315 | if (sysmon_envsys_sensor_attach( | | 320 | if (sysmon_envsys_sensor_attach( |
316 | sc->sc_sme, &sc->sc_sensor[ADM1026_FAN_NUM(i)])) { | | 321 | sc->sc_sme, &sc->sc_sensor[ADM1026_FAN_NUM(i)])) { |
317 | sysmon_envsys_destroy(sc->sc_sme); | | 322 | sysmon_envsys_destroy(sc->sc_sme); |
318 | aprint_error_dev(sc->sc_dev, | | 323 | aprint_error_dev(sc->sc_dev, |
319 | "unable to attach fan %d at sysmon\n", i); | | 324 | "unable to attach fan %d at sysmon\n", i); |
320 | return; | | 325 | return; |
321 | } | | 326 | } |
322 | } | | 327 | } |
323 | } | | 328 | } |
324 | } | | 329 | } |
325 | | | 330 | |
326 | static void | | 331 | static void |
327 | adm1026_setup_temps(struct adm1026_softc *sc) | | 332 | adm1026_setup_temps(struct adm1026_softc *sc) |
328 | { | | 333 | { |
329 | int i; | | 334 | int i; |
330 | uint8_t val; | | 335 | uint8_t val; |
331 | | | 336 | |
332 | /* Temperature offsets */ | | 337 | /* Temperature offsets */ |
333 | if (adm1026_read_reg(sc, ADM1026_INT_TEMP_OFF, &val) | | 338 | if (adm1026_read_reg(sc, ADM1026_INT_TEMP_OFF, &val) |
334 | != 0) { | | 339 | != 0) { |
335 | aprint_error_dev(sc->sc_dev, "unable to read int temp. off.\n"); | | 340 | aprint_error_dev(sc->sc_dev, "unable to read int temp. off.\n"); |
336 | return; | | 341 | return; |
337 | } | | 342 | } |
338 | if (val & 0x80) | | 343 | if (val & 0x80) |
339 | sc->sc_temp_off[0] = 0 - 1000000 * (val & 0x7f); | | 344 | sc->sc_temp_off[0] = 0 - 1000000 * (val & 0x7f); |
340 | else | | 345 | else |
341 | sc->sc_temp_off[0] = 1000000 * (val & 0x7f); | | 346 | sc->sc_temp_off[0] = 1000000 * (val & 0x7f); |
342 | if (adm1026_read_reg(sc, ADM1026_TDM1_OFF, &val) != 0) { | | 347 | if (adm1026_read_reg(sc, ADM1026_TDM1_OFF, &val) != 0) { |
343 | aprint_error_dev(sc->sc_dev, "unable to read tdm1 off.\n"); | | 348 | aprint_error_dev(sc->sc_dev, "unable to read tdm1 off.\n"); |
344 | return; | | 349 | return; |
345 | } | | 350 | } |
346 | if (val & 0x80) | | 351 | if (val & 0x80) |
347 | sc->sc_temp_off[1] = 0 - 1000000 * (val & 0x7f); | | 352 | sc->sc_temp_off[1] = 0 - 1000000 * (val & 0x7f); |
348 | else | | 353 | else |
349 | sc->sc_temp_off[1] = 1000000 * (val & 0x7f); | | 354 | sc->sc_temp_off[1] = 1000000 * (val & 0x7f); |
350 | if (adm1026_read_reg(sc, ADM1026_TDM2_OFF, &val) != 0) { | | 355 | if (adm1026_read_reg(sc, ADM1026_TDM2_OFF, &val) != 0) { |
351 | aprint_error_dev(sc->sc_dev, "unable to read tdm2 off.\n"); | | 356 | aprint_error_dev(sc->sc_dev, "unable to read tdm2 off.\n"); |
352 | return; | | 357 | return; |
353 | } | | 358 | } |
354 | if (val & 0x80) | | 359 | if (val & 0x80) |
355 | sc->sc_temp_off[2] = 0 - 1000000 * (val & 0x7f); | | 360 | sc->sc_temp_off[2] = 0 - 1000000 * (val & 0x7f); |
356 | else | | 361 | else |
357 | sc->sc_temp_off[2] = 1000000 * (val & 0x7f); | | 362 | sc->sc_temp_off[2] = 1000000 * (val & 0x7f); |
358 | | | 363 | |
359 | strlcpy(sc->sc_sensor[ADM1026_TEMP_NUM(0)].desc, "internal", | | 364 | strlcpy(sc->sc_sensor[ADM1026_TEMP_NUM(0)].desc, "internal", |
360 | sizeof(sc->sc_sensor[ADM1026_TEMP_NUM(0)].desc)); | | 365 | sizeof(sc->sc_sensor[ADM1026_TEMP_NUM(0)].desc)); |
361 | strlcpy(sc->sc_sensor[ADM1026_TEMP_NUM(1)].desc, "external 1", | | 366 | strlcpy(sc->sc_sensor[ADM1026_TEMP_NUM(1)].desc, "external 1", |
362 | sizeof(sc->sc_sensor[ADM1026_TEMP_NUM(1)].desc)); | | 367 | sizeof(sc->sc_sensor[ADM1026_TEMP_NUM(1)].desc)); |
363 | strlcpy(sc->sc_sensor[ADM1026_TEMP_NUM(2)].desc, "external 2", | | 368 | strlcpy(sc->sc_sensor[ADM1026_TEMP_NUM(2)].desc, "external 2", |
364 | sizeof(sc->sc_sensor[ADM1026_TEMP_NUM(2)].desc)); | | 369 | sizeof(sc->sc_sensor[ADM1026_TEMP_NUM(2)].desc)); |
365 | for (i = 0; i < ADM1026_MAX_TEMPS; i++) { | | 370 | for (i = 0; i < ADM1026_MAX_TEMPS; i++) { |
366 | /* Check configuration1 register to see if TDM2 is configured */ | | 371 | /* Check configuration1 register to see if TDM2 is configured */ |
367 | if (i == 2 && !ADM1026_PIN_IS_TDM2(sc->sc_cfg[0])) | | 372 | if (i == 2 && !ADM1026_PIN_IS_TDM2(sc->sc_cfg[0])) |
368 | continue; | | 373 | continue; |
369 | sc->sc_sensor[ADM1026_TEMP_NUM(i)].units = ENVSYS_STEMP; | | 374 | sc->sc_sensor[ADM1026_TEMP_NUM(i)].units = ENVSYS_STEMP; |
370 | sc->sc_sensor[ADM1026_TEMP_NUM(i)].state = ENVSYS_SINVALID; | | 375 | sc->sc_sensor[ADM1026_TEMP_NUM(i)].state = ENVSYS_SINVALID; |
371 | sc->sc_ntemps++; | | 376 | sc->sc_ntemps++; |
372 | if (sysmon_envsys_sensor_attach( | | 377 | if (sysmon_envsys_sensor_attach( |
373 | sc->sc_sme, &sc->sc_sensor[ADM1026_TEMP_NUM(i)])) { | | 378 | sc->sc_sme, &sc->sc_sensor[ADM1026_TEMP_NUM(i)])) { |
374 | sysmon_envsys_destroy(sc->sc_sme); | | 379 | sysmon_envsys_destroy(sc->sc_sme); |
375 | aprint_error_dev(sc->sc_dev, | | 380 | aprint_error_dev(sc->sc_dev, |
376 | "unable to attach temp %d at sysmon\n", i); | | 381 | "unable to attach temp %d at sysmon\n", i); |
377 | return; | | 382 | return; |
378 | } | | 383 | } |
379 | } | | 384 | } |
380 | } | | 385 | } |
381 | | | 386 | |
382 | static void | | 387 | static void |
383 | adm1026_setup_volts(struct adm1026_softc *sc) | | 388 | adm1026_setup_volts(struct adm1026_softc *sc) |
384 | { | | 389 | { |
385 | int i; | | 390 | int i; |
386 | | | 391 | |
387 | for (i = 0; i < ADM1026_MAX_VOLTS; i++) { | | 392 | for (i = 0; i < ADM1026_MAX_VOLTS; i++) { |
388 | /* Check configuration1 register to see if TDM2 is configured */ | | 393 | /* Check configuration1 register to see if TDM2 is configured */ |
389 | if (adm1026_volts_table[i].check_tdm2 && | | 394 | if (adm1026_volts_table[i].check_tdm2 && |
390 | ADM1026_PIN_IS_TDM2(sc->sc_cfg[0])) | | 395 | ADM1026_PIN_IS_TDM2(sc->sc_cfg[0])) |
391 | continue; | | 396 | continue; |
392 | strlcpy(sc->sc_sensor[ADM1026_VOLT_NUM(i)].desc, | | 397 | strlcpy(sc->sc_sensor[ADM1026_VOLT_NUM(i)].desc, |
393 | adm1026_volts_table[i].desc, | | 398 | adm1026_volts_table[i].desc, |
394 | sizeof(sc->sc_sensor[ADM1026_VOLT_NUM(i)].desc)); | | 399 | sizeof(sc->sc_sensor[ADM1026_VOLT_NUM(i)].desc)); |
395 | sc->sc_sensor[ADM1026_VOLT_NUM(i)].units = ENVSYS_SVOLTS_DC; | | 400 | sc->sc_sensor[ADM1026_VOLT_NUM(i)].units = ENVSYS_SVOLTS_DC; |
396 | sc->sc_sensor[ADM1026_VOLT_NUM(i)].state = ENVSYS_SINVALID; | | 401 | sc->sc_sensor[ADM1026_VOLT_NUM(i)].state = ENVSYS_SINVALID; |
397 | if (sysmon_envsys_sensor_attach( | | 402 | if (sysmon_envsys_sensor_attach( |
398 | sc->sc_sme, &sc->sc_sensor[ADM1026_VOLT_NUM(i)])) { | | 403 | sc->sc_sme, &sc->sc_sensor[ADM1026_VOLT_NUM(i)])) { |
399 | sysmon_envsys_destroy(sc->sc_sme); | | 404 | sysmon_envsys_destroy(sc->sc_sme); |
400 | aprint_error_dev(sc->sc_dev, | | 405 | aprint_error_dev(sc->sc_dev, |
401 | "unable to attach volts %d at sysmon\n", i); | | 406 | "unable to attach volts %d at sysmon\n", i); |
402 | return; | | 407 | return; |
403 | } | | 408 | } |
404 | } | | 409 | } |
405 | } | | 410 | } |
406 | | | 411 | |
407 | void | | 412 | void |
408 | adm1026_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) | | 413 | adm1026_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) |
409 | { | | 414 | { |
410 | struct adm1026_softc *sc = sme->sme_cookie; | | 415 | struct adm1026_softc *sc = sme->sme_cookie; |
411 | | | 416 | |
412 | if (edata->sensor < sc->sc_nfans) | | 417 | if (edata->sensor < sc->sc_nfans) |
413 | adm1026_read_fan(sc, edata); | | 418 | adm1026_read_fan(sc, edata); |
414 | else if (edata->sensor < sc->sc_nfans + sc->sc_ntemps) | | 419 | else if (edata->sensor < sc->sc_nfans + sc->sc_ntemps) |
415 | adm1026_read_temp(sc, edata); | | 420 | adm1026_read_temp(sc, edata); |
416 | else | | 421 | else |
417 | adm1026_read_volt(sc, edata); | | 422 | adm1026_read_volt(sc, edata); |
418 | } | | 423 | } |
419 | | | 424 | |
420 | static void | | 425 | static void |
421 | adm1026_read_fan(struct adm1026_softc *sc, envsys_data_t *edata) | | 426 | adm1026_read_fan(struct adm1026_softc *sc, envsys_data_t *edata) |
422 | { | | 427 | { |
423 | int fan = ADM1026_NUM_FAN(edata->sensor); | | 428 | int fan = ADM1026_NUM_FAN(edata->sensor); |
424 | int err; | | 429 | int err; |
425 | uint8_t val; | | 430 | uint8_t val; |
426 | | | 431 | |
427 | if ((err = adm1026_read_reg(sc, ADM1026_FAN_VAL(fan), &val)) != 0) { | | 432 | if ((err = adm1026_read_reg(sc, ADM1026_FAN_VAL(fan), &val)) != 0) { |
428 | edata->state = ENVSYS_SINVALID; | | 433 | edata->state = ENVSYS_SINVALID; |
429 | return; | | 434 | return; |
430 | } | | 435 | } |
431 | if (val == 0xff || val == 0x00) /* Fan missing or stopped */ | | 436 | if (val == 0xff || val == 0x00) /* Fan missing or stopped */ |
432 | edata->value_cur = 0; | | 437 | edata->value_cur = 0; |
433 | else | | 438 | else |
434 | edata->value_cur = 1350000 / (val * sc->sc_fandiv[fan]); | | 439 | edata->value_cur = 1350000 / (val * sc->sc_fandiv[fan]); |
435 | edata->state = ENVSYS_SVALID; | | 440 | edata->state = ENVSYS_SVALID; |
436 | } | | 441 | } |
437 | | | 442 | |
438 | static void | | 443 | static void |
439 | adm1026_read_temp(struct adm1026_softc *sc, envsys_data_t *edata) | | 444 | adm1026_read_temp(struct adm1026_softc *sc, envsys_data_t *edata) |
440 | { | | 445 | { |
441 | int temp = ADM1026_NUM_TEMP(edata->sensor); | | 446 | int temp = ADM1026_NUM_TEMP(edata->sensor); |
442 | int err; | | 447 | int err; |
443 | uint8_t val; | | 448 | uint8_t val; |
444 | | | 449 | |
445 | if (temp == 0) | | 450 | if (temp == 0) |
446 | err = adm1026_read_reg(sc, ADM1026_INT_TEMP_VAL, &val); | | 451 | err = adm1026_read_reg(sc, ADM1026_INT_TEMP_VAL, &val); |
447 | else if (temp == 1) | | 452 | else if (temp == 1) |
448 | err = adm1026_read_reg(sc, ADM1026_TDM1_VAL, &val); | | 453 | err = adm1026_read_reg(sc, ADM1026_TDM1_VAL, &val); |
449 | else | | 454 | else |
450 | err = adm1026_read_reg(sc, ADM1026_TDM2_AIN9_VAL, &val); | | 455 | err = adm1026_read_reg(sc, ADM1026_TDM2_AIN9_VAL, &val); |
451 | if (err) { | | 456 | if (err) { |
452 | edata->state = ENVSYS_SINVALID; | | 457 | edata->state = ENVSYS_SINVALID; |
453 | return; | | 458 | return; |
454 | } | | 459 | } |
455 | | | 460 | |
456 | if (val & 0x80) /* Negative temperature */ | | 461 | if (val & 0x80) /* Negative temperature */ |
457 | edata->value_cur = 273150000 - sc->sc_temp_off[temp] - | | 462 | edata->value_cur = 273150000 - sc->sc_temp_off[temp] - |
458 | 1000000 * (val & 0x7f); | | 463 | 1000000 * (val & 0x7f); |
459 | else /* Positive temperature */ | | 464 | else /* Positive temperature */ |
460 | edata->value_cur = 273150000 - sc->sc_temp_off[temp] + | | 465 | edata->value_cur = 273150000 - sc->sc_temp_off[temp] + |
461 | 1000000 * val; | | 466 | 1000000 * val; |
462 | edata->state = ENVSYS_SVALID; | | 467 | edata->state = ENVSYS_SVALID; |
463 | } | | 468 | } |
464 | | | 469 | |
465 | static void | | 470 | static void |
466 | adm1026_read_volt(struct adm1026_softc *sc, envsys_data_t *edata) | | 471 | adm1026_read_volt(struct adm1026_softc *sc, envsys_data_t *edata) |
467 | { | | 472 | { |
468 | int volt = ADM1026_NUM_VOLT(edata->sensor); | | 473 | int volt = ADM1026_NUM_VOLT(edata->sensor); |
469 | int err; | | 474 | int err; |
470 | uint8_t val; | | 475 | uint8_t val; |
471 | | | 476 | |
472 | err = adm1026_read_reg(sc, adm1026_volts_table[volt].reg, &val); | | 477 | err = adm1026_read_reg(sc, adm1026_volts_table[volt].reg, &val); |
473 | if (err) { | | 478 | if (err) { |
474 | edata->state = ENVSYS_SINVALID; | | 479 | edata->state = ENVSYS_SINVALID; |
475 | return; | | 480 | return; |
476 | } | | 481 | } |
477 | /* Vbatt is not valid for < 1.5V */ | | 482 | /* Vbatt is not valid for < 1.5V */ |
478 | if (volt == 0 && val < 0x60) | | 483 | if (volt == 0 && val < 0x60) |
479 | edata->state = ENVSYS_SINVALID; | | 484 | edata->state = ENVSYS_SINVALID; |
480 | edata->value_cur = (int) val * adm1026_volts_table[volt].incr; | | 485 | edata->value_cur = (int) val * adm1026_volts_table[volt].incr; |
481 | edata->state = ENVSYS_SVALID; | | 486 | edata->state = ENVSYS_SVALID; |
482 | } | | 487 | } |
483 | | | 488 | |
484 | static int | | 489 | static int |
485 | adm1026_read_reg(struct adm1026_softc *sc, uint8_t reg, uint8_t *val) | | 490 | adm1026_read_reg_int(i2c_tag_t tag, i2c_addr_t addr, uint8_t reg, |
| | | 491 | bool multi_read, uint8_t *val) |
486 | { | | 492 | { |
487 | #define ADM1026_READ_RETRIES 5 | | 493 | #define ADM1026_READ_RETRIES 5 |
488 | int i, j, err = 0; | | 494 | int i, j, err = 0; |
489 | uint8_t creg, cval, tmp[ADM1026_READ_RETRIES + 1]; | | 495 | uint8_t creg, cval, tmp[ADM1026_READ_RETRIES + 1]; |
490 | | | 496 | |
491 | if ((err = iic_acquire_bus(sc->sc_tag, 0)) != 0) | | 497 | if ((err = iic_acquire_bus(tag, 0)) != 0) |
492 | return err; | | 498 | return err; |
493 | /* Standard ADM1026 */ | | 499 | /* Standard ADM1026 */ |
494 | if (sc->sc_multi_read == false) { | | 500 | if (multi_read == false) { |
495 | err = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, | | 501 | err = iic_exec(tag, I2C_OP_READ_WITH_STOP, |
496 | sc->sc_address, ®, 1, val, 1, 0); | | 502 | addr, ®, 1, val, 1, 0); |
497 | /* | | 503 | /* |
498 | * The ADM1026 found in some Sun machines sometimes reads bogus values. | | 504 | * The ADM1026 found in some Sun machines sometimes reads bogus values. |
499 | * We'll read at least twice and check that we get (nearly) the same | | 505 | * We'll read at least twice and check that we get (nearly) the same |
500 | * value. If not, we'll read another register and then re-read the | | 506 | * value. If not, we'll read another register and then re-read the |
501 | * first. | | 507 | * first. |
502 | */ | | 508 | */ |
503 | } else { | | 509 | } else { |
504 | if (reg == ADM1026_CONF1) | | 510 | if (reg == ADM1026_CONF1) |
505 | creg = ADM1026_CONF2; | | 511 | creg = ADM1026_CONF2; |
506 | else | | 512 | else |
507 | creg = ADM1026_CONF1; | | 513 | creg = ADM1026_CONF1; |
508 | if ((err = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, | | 514 | if ((err = iic_exec(tag, I2C_OP_READ_WITH_STOP, |
509 | sc->sc_address, ®, 1, &tmp[0], 1, 0)) != 0) { | | 515 | addr, ®, 1, &tmp[0], 1, 0)) != 0) { |
510 | iic_release_bus(sc->sc_tag, 0); | | 516 | iic_release_bus(tag, 0); |
511 | return err; | | 517 | return err; |
512 | } | | 518 | } |
513 | for (i = 1; i <= ADM1026_READ_RETRIES; i++) { | | 519 | for (i = 1; i <= ADM1026_READ_RETRIES; i++) { |
514 | if ((err = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, | | 520 | if ((err = iic_exec(tag, I2C_OP_READ_WITH_STOP, |
515 | sc->sc_address, ®, 1, &tmp[i], 1, 0)) != 0) | | 521 | addr, ®, 1, &tmp[i], 1, 0)) != 0) |
516 | break; | | 522 | break; |
517 | for (j = 0; j < i; j++) | | 523 | for (j = 0; j < i; j++) |
518 | if (abs(tmp[j] - tmp[i]) < 3) { | | 524 | if (abs(tmp[j] - tmp[i]) < 3) { |
519 | *val = tmp[i]; | | 525 | *val = tmp[i]; |
520 | iic_release_bus(sc->sc_tag, 0); | | 526 | iic_release_bus(tag, 0); |
521 | return 0; | | 527 | return 0; |
522 | } | | 528 | } |
523 | if ((err = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, | | 529 | if ((err = iic_exec(tag, I2C_OP_READ_WITH_STOP, |
524 | sc->sc_address, &creg, 1, &cval, 1, 0)) != 0) | | 530 | addr, &creg, 1, &cval, 1, 0)) != 0) |
525 | break; | | 531 | break; |
526 | err = -1; /* Return error if we don't match. */ | | 532 | err = -1; /* Return error if we don't match. */ |
527 | } | | 533 | } |
528 | } | | 534 | } |
529 | iic_release_bus(sc->sc_tag, 0); | | 535 | iic_release_bus(tag, 0); |
530 | return err; | | 536 | return err; |
531 | } | | 537 | } |
532 | | | 538 | |
533 | static int | | 539 | static int |
534 | adm1026_write_reg(struct adm1026_softc *sc, uint8_t reg, uint8_t val) | | 540 | adm1026_write_reg(struct adm1026_softc *sc, uint8_t reg, uint8_t val) |
535 | { | | 541 | { |
536 | int err = 0; | | 542 | int err = 0; |
537 | | | 543 | |
538 | if ((err = iic_acquire_bus(sc->sc_tag, 0)) != 0) | | 544 | if ((err = iic_acquire_bus(sc->sc_tag, 0)) != 0) |
539 | return err; | | 545 | return err; |
540 | err = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address, | | 546 | err = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address, |
541 | ®, 1, &val, 1, 0); | | 547 | ®, 1, &val, 1, 0); |
542 | iic_release_bus(sc->sc_tag, 0); | | 548 | iic_release_bus(sc->sc_tag, 0); |
543 | return err; | | 549 | return err; |
544 | } | | 550 | } |