1 /* $NetBSD: sdtemp.c,v 1.8 2010/01/01 15:43:49 pgoyette Exp $ */
4 * Copyright (c) 2009 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
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
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
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
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
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: sdtemp.c,v 1.8 2010/01/01 15:43:49 pgoyette Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
38 #include <sys/device.h>
39 #include <sys/kernel.h>
40 #include <sys/endian.h>
42 #include <dev/sysmon/sysmonvar.h>
44 #include <dev/i2c/i2cvar.h>
45 #include <dev/i2c/sdtemp_reg.h>
52 struct sysmon_envsys
*sc_sme
;
53 envsys_data_t
*sc_sensor
;
55 uint16_t sc_capability
;
58 static int sdtemp_match(device_t
, cfdata_t
, void *);
59 static void sdtemp_attach(device_t
, device_t
, void *);
61 CFATTACH_DECL_NEW(sdtemp
, sizeof(struct sdtemp_softc
),
62 sdtemp_match
, sdtemp_attach
, NULL
, NULL
);
64 static void sdtemp_refresh(struct sysmon_envsys
*, envsys_data_t
*);
65 static void sdtemp_get_limits(struct sysmon_envsys
*, envsys_data_t
*,
66 sysmon_envsys_lim_t
*);
67 static void sdtemp_set_limits(struct sysmon_envsys
*, envsys_data_t
*,
68 sysmon_envsys_lim_t
*);
70 static int sdtemp_read_8(struct sdtemp_softc
*, uint8_t, uint8_t *);
71 static int sdtemp_write_8(struct sdtemp_softc
*, uint8_t, uint8_t);
73 static int sdtemp_read_16(struct sdtemp_softc
*, uint8_t, uint16_t *);
74 static int sdtemp_write_16(struct sdtemp_softc
*, uint8_t, uint16_t);
75 static uint32_t sdtemp_decode_temp(struct sdtemp_softc
*, uint16_t);
76 static bool sdtemp_pmf_suspend(device_t
, pmf_qual_t
);
77 static bool sdtemp_pmf_resume(device_t
, pmf_qual_t
);
79 struct sdtemp_dev_entry
{
80 const uint16_t sdtemp_mfg_id
;
81 const uint8_t sdtemp_dev_id
;
82 const uint8_t sdtemp_rev_id
;
83 const uint8_t sdtemp_resolution
;
84 const char *sdtemp_desc
;
87 /* Convert sysmon_envsys uKelvin value to simple degC */
89 #define __UK2C(uk) (((uk) - 273150000) / 1000000)
92 * List of devices known to conform to JEDEC JC42.4
94 * NOTE: A non-negative value for resolution indicates that the sensor
95 * resolution is fixed at that number of fractional bits; a negative
96 * value indicates that the sensor needs to be configured. In either
97 * case, trip-point registers are fixed at two-bit (0.25C) resolution.
99 static const struct sdtemp_dev_entry
100 sdtemp_dev_table
[] = {
101 { MAXIM_MANUFACTURER_ID
, MAX_6604_DEVICE_ID
, 0xff, 3,
103 { MCP_MANUFACTURER_ID
, MCP_9805_DEVICE_ID
, 0xff, 2,
104 "Microchip Tech MCP9805" },
105 { MCP_MANUFACTURER_ID
, MCP_98242_DEVICE_ID
, 0xff, -4,
106 "Microchip Tech MCP98242" },
107 { ADT_MANUFACTURER_ID
, ADT_7408_DEVICE_ID
, 0xff, 4,
108 "Analog Devices ADT7408" },
109 { NXP_MANUFACTURER_ID
, NXP_SE97_DEVICE_ID
, 0xff, 3,
110 "NXP Semiconductors SE97/SE98" },
111 { STTS_MANUFACTURER_ID
, STTS_424E02_DEVICE_ID
, 0x00, 2,
112 "STmicroelectronics STTS424E02-DA" },
113 { STTS_MANUFACTURER_ID
, STTS_424E02_DEVICE_ID
, 0x01, 2,
114 "STmicroelectronics STTS424E02-DN" },
115 { CAT_MANUFACTURER_ID
, CAT_34TS02_DEVICE_ID
, 0xff, 4,
116 "Catalyst CAT34TS02/CAT6095" },
117 { 0, 0, 0, 2, "Unknown" }
121 sdtemp_lookup(uint16_t mfg
, uint16_t dev
, uint16_t rev
)
125 for (i
= 0; sdtemp_dev_table
[i
].sdtemp_mfg_id
; i
++)
126 if (sdtemp_dev_table
[i
].sdtemp_mfg_id
== mfg
&&
127 sdtemp_dev_table
[i
].sdtemp_dev_id
== dev
&&
128 (sdtemp_dev_table
[i
].sdtemp_rev_id
== 0xff ||
129 sdtemp_dev_table
[i
].sdtemp_rev_id
== rev
))
136 sdtemp_match(device_t parent
, cfdata_t cf
, void *aux
)
138 struct i2c_attach_args
*ia
= aux
;
139 uint16_t mfgid
, devid
;
140 struct sdtemp_softc sc
;
143 sc
.sc_tag
= ia
->ia_tag
;
144 sc
.sc_address
= ia
->ia_addr
;
146 if ((ia
->ia_addr
& SDTEMP_ADDRMASK
) != SDTEMP_ADDR
)
149 /* Verify that we can read the manufacturer ID & Device ID */
150 iic_acquire_bus(sc
.sc_tag
, 0);
151 error
= sdtemp_read_16(&sc
, SDTEMP_REG_MFG_ID
, &mfgid
) |
152 sdtemp_read_16(&sc
, SDTEMP_REG_DEV_REV
, &devid
);
153 iic_release_bus(sc
.sc_tag
, 0);
158 i
= sdtemp_lookup(mfgid
, devid
>> 8, devid
& 0xff);
159 if (sdtemp_dev_table
[i
].sdtemp_mfg_id
== 0) {
160 aprint_debug("sdtemp: No match for mfg 0x%04x dev 0x%02x "
161 "rev 0x%02x at address 0x%02x\n", mfgid
, devid
>> 8,
162 devid
& 0xff, sc
.sc_address
);
170 sdtemp_attach(device_t parent
, device_t self
, void *aux
)
172 struct sdtemp_softc
*sc
= device_private(self
);
173 struct i2c_attach_args
*ia
= aux
;
174 sysmon_envsys_lim_t limits
;
175 uint16_t mfgid
, devid
;
178 sc
->sc_tag
= ia
->ia_tag
;
179 sc
->sc_address
= ia
->ia_addr
;
182 iic_acquire_bus(sc
->sc_tag
, 0);
183 if ((error
= sdtemp_read_16(sc
, SDTEMP_REG_MFG_ID
, &mfgid
)) != 0 ||
184 (error
= sdtemp_read_16(sc
, SDTEMP_REG_DEV_REV
, &devid
)) != 0) {
185 iic_release_bus(sc
->sc_tag
, 0);
186 aprint_error(": attach error %d\n", error
);
189 i
= sdtemp_lookup(mfgid
, devid
>> 8, devid
& 0xff);
191 sdtemp_dev_table
[i
].sdtemp_resolution
;
193 aprint_naive(": Temp Sensor\n");
194 aprint_normal(": %s Temp Sensor\n", sdtemp_dev_table
[i
].sdtemp_desc
);
196 if (sdtemp_dev_table
[i
].sdtemp_mfg_id
== 0)
197 aprint_debug_dev(self
,
198 "mfg 0x%04x dev 0x%02x rev 0x%02x at addr 0x%02x\n",
199 mfgid
, devid
>> 8, devid
& 0xff, ia
->ia_addr
);
202 * Alarm capability is required; if not present, this is likely
203 * not a real sdtemp device.
205 error
= sdtemp_read_16(sc
, SDTEMP_REG_CAPABILITY
, &sc
->sc_capability
);
206 if (error
!= 0 || (sc
->sc_capability
& SDTEMP_CAP_HAS_ALARM
) == 0) {
207 iic_release_bus(sc
->sc_tag
, 0);
208 aprint_error_dev(self
,
209 "required alarm capability not present!\n");
212 /* Set the configuration to defaults. */
213 error
= sdtemp_write_16(sc
, SDTEMP_REG_CONFIG
, 0);
215 iic_release_bus(sc
->sc_tag
, 0);
216 aprint_error_dev(self
, "error %d writing config register\n",
220 /* If variable resolution, set to max */
221 if (sc
->sc_resolution
< 0) {
222 sc
->sc_resolution
= ~sc
->sc_resolution
;
223 error
= sdtemp_write_16(sc
, SDTEMP_REG_RESOLUTION
,
224 sc
->sc_resolution
& 0x3);
226 iic_release_bus(sc
->sc_tag
, 0);
227 aprint_error_dev(self
,
228 "error %d writing resolution register\n", error
);
233 iic_release_bus(sc
->sc_tag
, 0);
235 /* Hook us into the sysmon_envsys subsystem */
236 sc
->sc_sme
= sysmon_envsys_create();
237 sc
->sc_sme
->sme_name
= device_xname(self
);
238 sc
->sc_sme
->sme_cookie
= sc
;
239 sc
->sc_sme
->sme_refresh
= sdtemp_refresh
;
240 sc
->sc_sme
->sme_get_limits
= sdtemp_get_limits
;
241 sc
->sc_sme
->sme_set_limits
= sdtemp_set_limits
;
243 sc
->sc_sensor
= kmem_zalloc(sizeof(envsys_data_t
), KM_NOSLEEP
);
244 if (!sc
->sc_sensor
) {
245 aprint_error_dev(self
, "unable to allocate sc_sensor\n");
249 /* Initialize sensor data. */
250 sc
->sc_sensor
->units
= ENVSYS_STEMP
;
251 sc
->sc_sensor
->state
= ENVSYS_SINVALID
;
252 sc
->sc_sensor
->flags
|= ENVSYS_FMONLIMITS
;
253 sc
->sc_sensor
->monitor
= true;
254 (void)strlcpy(sc
->sc_sensor
->desc
, device_xname(self
),
255 sizeof(sc
->sc_sensor
->desc
));
257 /* Now attach the sensor */
258 if (sysmon_envsys_sensor_attach(sc
->sc_sme
, sc
->sc_sensor
)) {
259 aprint_error_dev(self
, "unable to attach sensor\n");
263 /* Register the device */
264 error
= sysmon_envsys_register(sc
->sc_sme
);
266 aprint_error_dev(self
, "error %d registering with sysmon\n",
271 if (!pmf_device_register(self
, sdtemp_pmf_suspend
, sdtemp_pmf_resume
))
272 aprint_error_dev(self
, "couldn't establish power handler\n");
274 /* Retrieve and display hardware monitor limits */
275 sdtemp_get_limits(sc
->sc_sme
, sc
->sc_sensor
, &limits
);
276 aprint_normal_dev(self
, "");
278 if (limits
.sel_flags
& PROP_WARNMIN
) {
279 aprint_normal("low limit %dC", __UK2C(limits
.sel_warnmin
));
282 if (limits
.sel_flags
& PROP_WARNMAX
) {
283 aprint_normal("%shigh limit %dC ", (i
)?", ":"",
284 __UK2C(limits
.sel_warnmax
));
287 if (limits
.sel_flags
& PROP_CRITMAX
) {
288 aprint_normal("%scritical limit %dC ", (i
)?", ":"",
289 __UK2C(limits
.sel_critmax
));
293 aprint_normal("no hardware limits set\n");
300 kmem_free(sc
->sc_sensor
, sizeof(envsys_data_t
));
302 sysmon_envsys_destroy(sc
->sc_sme
);
305 /* Retrieve current limits from device, and encode in uKelvins */
307 sdtemp_get_limits(struct sysmon_envsys
*sme
, envsys_data_t
*edata
,
308 sysmon_envsys_lim_t
*limits
)
310 struct sdtemp_softc
*sc
= sme
->sme_cookie
;
313 limits
->sel_flags
= 0;
314 iic_acquire_bus(sc
->sc_tag
, 0);
315 if (sdtemp_read_16(sc
, SDTEMP_REG_LOWER_LIM
, &lim
) == 0 && lim
!= 0) {
316 limits
->sel_warnmin
= sdtemp_decode_temp(sc
, lim
);
317 limits
->sel_flags
|= PROP_WARNMIN
;
319 if (sdtemp_read_16(sc
, SDTEMP_REG_UPPER_LIM
, &lim
) == 0 && lim
!= 0) {
320 limits
->sel_warnmax
= sdtemp_decode_temp(sc
, lim
);
321 limits
->sel_flags
|= PROP_WARNMAX
;
323 if (sdtemp_read_16(sc
, SDTEMP_REG_CRIT_LIM
, &lim
) == 0 && lim
!= 0) {
324 limits
->sel_critmax
= sdtemp_decode_temp(sc
, lim
);
325 limits
->sel_flags
|= PROP_CRITMAX
;
327 iic_release_bus(sc
->sc_tag
, 0);
328 if (limits
->sel_flags
!= 0)
329 limits
->sel_flags
|= PROP_DRIVER_LIMITS
;
332 /* Send current limit values to the device */
334 sdtemp_set_limits(struct sysmon_envsys
*sme
, envsys_data_t
*edata
,
335 sysmon_envsys_lim_t
*limits
)
338 struct sdtemp_softc
*sc
= sme
->sme_cookie
;
340 iic_acquire_bus(sc
->sc_tag
, 0);
341 if (limits
->sel_flags
& PROP_WARNMIN
) {
342 val
= __UK2C(limits
->sel_warnmin
);
343 (void)sdtemp_write_16(sc
, SDTEMP_REG_LOWER_LIM
,
344 (val
<< 4) & SDTEMP_TEMP_MASK
);
346 if (limits
->sel_flags
& PROP_WARNMAX
) {
347 val
= __UK2C(limits
->sel_warnmax
);
348 (void)sdtemp_write_16(sc
, SDTEMP_REG_UPPER_LIM
,
349 (val
<< 4) & SDTEMP_TEMP_MASK
);
351 if (limits
->sel_flags
& PROP_CRITMAX
) {
352 val
= __UK2C(limits
->sel_critmax
);
353 (void)sdtemp_write_16(sc
, SDTEMP_REG_CRIT_LIM
,
354 (val
<< 4) & SDTEMP_TEMP_MASK
);
356 iic_release_bus(sc
->sc_tag
, 0);
359 * If at least one limit is set that we can handle, and no
360 * limits are set that we cannot handle, tell sysmon that
361 * the driver will take care of monitoring the limits!
363 if (limits
->sel_flags
& (PROP_CRITMIN
| PROP_BATTCAP
| PROP_BATTWARN
))
364 limits
->sel_flags
&= ~PROP_DRIVER_LIMITS
;
365 else if (limits
->sel_flags
& PROP_LIMITS
)
366 limits
->sel_flags
|= PROP_DRIVER_LIMITS
;
368 limits
->sel_flags
&= ~PROP_DRIVER_LIMITS
;
371 #ifdef NOT_YET /* All registers on these sensors are 16-bits */
373 /* Read a 8-bit value from a register */
375 sdtemp_read_8(struct sdtemp_softc
*sc
, uint8_t reg
, uint8_t *valp
)
379 error
= iic_exec(sc
->sc_tag
, I2C_OP_READ_WITH_STOP
,
380 sc
->sc_address
, ®
, 1, valp
, sizeof(*valp
), 0);
386 sdtemp_write_8(struct sdtemp_softc
*sc
, uint8_t reg
, uint8_t val
)
388 return iic_exec(sc
->sc_tag
, I2C_OP_WRITE_WITH_STOP
,
389 sc
->sc_address
, ®
, 1, &val
, sizeof(val
), 0);
393 /* Read a 16-bit value from a register */
395 sdtemp_read_16(struct sdtemp_softc
*sc
, uint8_t reg
, uint16_t *valp
)
399 error
= iic_exec(sc
->sc_tag
, I2C_OP_READ_WITH_STOP
,
400 sc
->sc_address
, ®
, 1, valp
, sizeof(*valp
), 0);
404 *valp
= be16toh(*valp
);
410 sdtemp_write_16(struct sdtemp_softc
*sc
, uint8_t reg
, uint16_t val
)
415 return iic_exec(sc
->sc_tag
, I2C_OP_WRITE_WITH_STOP
,
416 sc
->sc_address
, ®
, 1, &temp
, sizeof(temp
), 0);
420 sdtemp_decode_temp(struct sdtemp_softc
*sc
, uint16_t temp
)
425 /* Get only the temperature bits */
426 temp
&= SDTEMP_TEMP_MASK
;
428 /* If necessary, extend the sign bit */
429 if ((sc
->sc_capability
& SDTEMP_CAP_WIDER_RANGE
) &&
430 (temp
& SDTEMP_TEMP_NEGATIVE
))
431 temp
|= SDTEMP_TEMP_SIGN_EXT
;
433 /* Mask off only bits valid within current resolution */
434 temp
&= ~(0xf >> sc
->sc_resolution
);
436 /* Treat as signed and extend to 32-bits */
437 stemp
= (int16_t)temp
;
439 /* Now convert from 0.0625 (1/16) deg C increments to microKelvins */
440 val
= (stemp
* 62500) + 273150000;
446 sdtemp_refresh(struct sysmon_envsys
*sme
, envsys_data_t
*edata
)
448 struct sdtemp_softc
*sc
= sme
->sme_cookie
;
452 iic_acquire_bus(sc
->sc_tag
, 0);
453 error
= sdtemp_read_16(sc
, SDTEMP_REG_AMBIENT_TEMP
, &val
);
454 iic_release_bus(sc
->sc_tag
, 0);
457 edata
->state
= ENVSYS_SINVALID
;
461 edata
->value_cur
= sdtemp_decode_temp(sc
, val
);
463 /* Now check for limits */
464 if ((edata
->upropset
& PROP_DRIVER_LIMITS
) == 0)
465 edata
->state
= ENVSYS_SVALID
;
466 else if (val
& SDTEMP_ABOVE_CRIT
)
467 edata
->state
= ENVSYS_SCRITOVER
;
468 else if (val
& SDTEMP_ABOVE_UPPER
)
469 edata
->state
= ENVSYS_SWARNOVER
;
470 else if (val
& SDTEMP_BELOW_LOWER
)
471 edata
->state
= ENVSYS_SWARNUNDER
;
473 edata
->state
= ENVSYS_SVALID
;
477 * power management functions
479 * We go into "shutdown" mode at suspend time, and return to normal
480 * mode upon resume. This reduces power consumption by disabling
485 sdtemp_pmf_suspend(device_t dev
, pmf_qual_t qual
)
487 struct sdtemp_softc
*sc
= device_private(dev
);
491 iic_acquire_bus(sc
->sc_tag
, 0);
492 error
= sdtemp_read_16(sc
, SDTEMP_REG_CONFIG
, &config
);
494 config
|= SDTEMP_CONFIG_SHUTDOWN_MODE
;
495 error
= sdtemp_write_16(sc
, SDTEMP_REG_CONFIG
, config
);
497 iic_release_bus(sc
->sc_tag
, 0);
502 sdtemp_pmf_resume(device_t dev
, pmf_qual_t qual
)
504 struct sdtemp_softc
*sc
= device_private(dev
);
508 iic_acquire_bus(sc
->sc_tag
, 0);
509 error
= sdtemp_read_16(sc
, SDTEMP_REG_CONFIG
, &config
);
511 config
&= ~SDTEMP_CONFIG_SHUTDOWN_MODE
;
512 error
= sdtemp_write_16(sc
, SDTEMP_REG_CONFIG
, config
);
514 iic_release_bus(sc
->sc_tag
, 0);