| @@ -18,27 +18,27 @@ | | | @@ -18,27 +18,27 @@ |
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 */ |
| @@ -88,89 +88,94 @@ struct adm1026_softc { | | | @@ -88,89 +88,94 @@ struct adm1026_softc { |
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; |
| @@ -179,27 +184,27 @@ adm1026_attach(device_t parent, device_t | | | @@ -179,27 +184,27 @@ adm1026_attach(device_t parent, device_t |
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, |
| @@ -472,71 +477,72 @@ adm1026_read_volt(struct adm1026_softc * | | | @@ -472,71 +477,72 @@ adm1026_read_volt(struct adm1026_softc * |
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); |