1/*      $NetBSD: sdtemp.c,v 1.41 2021/12/01 21:33:19 msaitoh Exp $        */
2
3/*
4 * Copyright (c) 2009 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Paul Goyette.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 *
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.
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: sdtemp.c,v 1.41 2021/12/01 21:33:19 msaitoh Exp $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kmem.h>
38#include <sys/device.h>
39#include <sys/kernel.h>
40#include <sys/endian.h>
41#include <sys/module.h>
42
43#include <dev/sysmon/sysmonvar.h>
44
45#include <dev/i2c/i2cvar.h>
46#include <dev/i2c/sdtemp_reg.h>
47
48struct sdtemp_softc {
49	device_t sc_dev;
50	i2c_tag_t sc_tag;
51	int sc_address;
52
53	struct sysmon_envsys *sc_sme;
54	envsys_data_t *sc_sensor;
55	sysmon_envsys_lim_t sc_deflims;
56	uint32_t sc_defprops;
57	int sc_resolution;
58	uint16_t sc_mfgid;
59	uint16_t sc_devid;
60	uint16_t sc_devid_masked;
61	uint16_t sc_capability;
62};
63
64static int  sdtemp_match(device_t, cfdata_t, void *);
65static void sdtemp_attach(device_t, device_t, void *);
66static int  sdtemp_detach(device_t, int);
67
68CFATTACH_DECL_NEW(sdtemp, sizeof(struct sdtemp_softc),
69	sdtemp_match, sdtemp_attach, sdtemp_detach, NULL);
70
71static void	sdtemp_refresh(struct sysmon_envsys *, envsys_data_t *);
72static void	sdtemp_get_limits(struct sysmon_envsys *, envsys_data_t *,
73				  sysmon_envsys_lim_t *, uint32_t *);
74static void	sdtemp_set_limits(struct sysmon_envsys *, envsys_data_t *,
75				  sysmon_envsys_lim_t *, uint32_t *);
76#ifdef NOT_YET
77static int	sdtemp_read_8(struct sdtemp_softc *, uint8_t, uint8_t *);
78static int	sdtemp_write_8(struct sdtemp_softc *, uint8_t, uint8_t);
79#endif /* NOT YET */
80static int	sdtemp_read_16(struct sdtemp_softc *, uint8_t, uint16_t *);
81static int	sdtemp_write_16(struct sdtemp_softc *, uint8_t, uint16_t);
82static uint32_t	sdtemp_decode_temp(struct sdtemp_softc *, uint16_t);
83static bool	sdtemp_pmf_suspend(device_t, const pmf_qual_t *);
84static bool	sdtemp_pmf_resume(device_t, const pmf_qual_t *);
85/* Device dependent config functions */
86static void	sdtemp_config_mcp(struct sdtemp_softc *);
87static void	sdtemp_config_idt(struct sdtemp_softc *);
88
89struct sdtemp_dev_entry {
90	const uint16_t sdtemp_mfg_id;
91	const uint16_t sdtemp_devrev;
92	const uint16_t sdtemp_mask;
93	void         (*sdtemp_config)(struct sdtemp_softc *);
94	const char    *sdtemp_desc;
95};
96
97/* Convert sysmon_envsys uKelvin value to simple degC */
98
99#define	__UK2C(uk) (((uk) - 273150000) / 1000000)
100
101/* List of devices known to conform to JEDEC JC42.4 */
102
103#define	CMCP sdtemp_config_mcp
104#define	CIDT sdtemp_config_idt
105
106static const struct sdtemp_dev_entry
107sdtemp_dev_table[] = {
108    { AT_MANUFACTURER_ID,   AT_30TS00_DEVICE_ID,     AT_30TS00_MASK,	  NULL,
109	"Atmel AT30TS00" },
110    { AT2_MANUFACTURER_ID,  AT2_30TSE004_DEVICE_ID,  AT2_30TSE004_MASK,	  NULL,
111	"Atmel AT30TSE004" },
112    { GT_MANUFACTURER_ID,   GT_30TS00_DEVICE_ID,     GT_30TS00_MASK,	  NULL,
113	"Giantec GT30TS00" },
114    { GT2_MANUFACTURER_ID,  GT2_34TS02_DEVICE_ID,    GT2_34TS02_MASK,	  NULL,
115	"Giantec GT34TS02" },
116    { MAXIM_MANUFACTURER_ID, MAX_6604_DEVICE_ID,     MAX_6604_MASK,	  NULL,
117	"Maxim MAX6604" },
118    { MAXIM_MANUFACTURER_ID, MAX_6604_2_DEVICE_ID,   MAX_6604_MASK,	  NULL,
119	"Maxim MAX6604" },
120    { MCP_MANUFACTURER_ID,  MCP_9804_DEVICE_ID,	     MCP_9804_MASK,	  CMCP,
121	"Microchip Tech MCP9804" },
122    { MCP_MANUFACTURER_ID,  MCP_9805_DEVICE_ID,	     MCP_9805_MASK,	  NULL,
123	"Microchip Tech MCP9805/MCP9843" },
124    { MCP_MANUFACTURER_ID,  MCP_98242_DEVICE_ID,     MCP_98242_MASK,	  CMCP,
125	"Microchip Tech MCP98242" },
126    { MCP_MANUFACTURER_ID,  MCP_98243_DEVICE_ID,     MCP_98243_MASK,	  CMCP,
127	"Microchip Tech MCP98243" },
128    { MCP_MANUFACTURER_ID,  MCP_98244_DEVICE_ID,     MCP_98244_MASK,	  CMCP,
129	"Microchip Tech MCP98244" },
130    { MCP2_MANUFACTURER_ID, MCP2_EMC1501_DEVICE_ID,  MCP2_EMC1501_MASK,	  NULL,
131	"Microchip Tech EMC1501" },
132    { ADT_MANUFACTURER_ID,  ADT_7408_DEVICE_ID,	     ADT_7408_MASK,	  NULL,
133	"Analog Devices ADT7408" },
134    { NXP_MANUFACTURER_ID,  NXP_SE98_DEVICE_ID,	     NXP_SE98_MASK,	  NULL,
135	"NXP Semiconductors SE97B/SE98" },
136    { NXP_MANUFACTURER_ID,  NXP_SE97_DEVICE_ID,	     NXP_SE97_MASK,	  NULL,
137	"NXP Semiconductors SE97" },
138    { STTS_MANUFACTURER_ID, STTS_424E_DEVICE_ID,     STTS_424E_MASK,	  NULL,
139	"STmicroelectronics STTS424E" },
140    { STTS_MANUFACTURER_ID, STTS_424_DEVICE_ID,	     STTS_424_MASK,	  NULL,
141	"STmicroelectronics STTS424" },
142    { STTS_MANUFACTURER_ID, STTS_2002_DEVICE_ID,     STTS_2002_MASK,	  NULL,
143	"STmicroelectronics STTS2002" },
144    { STTS_MANUFACTURER_ID, STTS_2004_DEVICE_ID,     STTS_2004_MASK,	  NULL,
145	"STmicroelectronics STTS2004" },
146    { STTS_MANUFACTURER_ID, STTS_3000_DEVICE_ID,     STTS_3000_MASK,	  NULL,
147	"STmicroelectronics STTS3000" },
148    { CAT_MANUFACTURER_ID,  CAT_34TS02_DEVICE_ID,    CAT_34TS02_MASK,	  NULL,
149	"Catalyst CAT34TS02/CAT6095" },
150    { CAT_MANUFACTURER_ID,  CAT_34TS02C_DEVICE_ID,   CAT_34TS02C_MASK,	  NULL,
151	"Catalyst CAT34TS02C" },
152    { CAT_MANUFACTURER_ID,  CAT_34TS04_DEVICE_ID,    CAT_34TS04_MASK,	  NULL,
153	"Catalyst CAT34TS04" },
154    { IDT_MANUFACTURER_ID,  IDT_TSE2004GB2_DEVICE_ID,IDT_TSE2004GB2_MASK, NULL,
155	"Integrated Device Technology TSE2004GB2" },
156    { IDT_MANUFACTURER_ID,  IDT_TS3000B3_DEVICE_ID,  IDT_TS3000B3_MASK,	  CIDT,
157	"Integrated Device Technology TS3000B3/TSE2002B3" },
158    { IDT_MANUFACTURER_ID,  IDT_TS3000GB0_DEVICE_ID, IDT_TS3000GB0_MASK,  CIDT,
159	"Integrated Device Technology TS3000GB0" },
160    { IDT_MANUFACTURER_ID,  IDT_TS3000GB2_DEVICE_ID, IDT_TS3000GB2_MASK,  CIDT,
161	"Integrated Device Technology TS3000GB2" },
162    { IDT_MANUFACTURER_ID,  IDT_TS3001GB2_DEVICE_ID, IDT_TS3001GB2_MASK,  CIDT,
163	"Integrated Device Technology TS3001GB2" },
164    /*
165     * Don't change the location of the following two entries. Device specific
166     * entry must be located at above.
167     */
168    { 0,		    TSE2004AV_ID,	     TSE2004AV_MASK,	  NULL,
169	"TSE2004av compliant device (generic driver)" },
170    { 0, 0, 0, NULL, "Unknown" }
171};
172
173#undef CMCP
174#undef CIDT
175
176static const char *temp_resl[] = {
177	"0.5C",
178	"0.25C",
179	"0.125C",
180	"0.0625C"
181};
182
183static int
184sdtemp_lookup(uint16_t mfg, uint16_t devrev)
185{
186	int i;
187
188	for (i = 0; sdtemp_dev_table[i].sdtemp_mfg_id; i++) {
189		if (mfg != sdtemp_dev_table[i].sdtemp_mfg_id)
190			continue;
191		if ((devrev & sdtemp_dev_table[i].sdtemp_mask) ==
192		    sdtemp_dev_table[i].sdtemp_devrev)
193			break;
194	}
195	/* Check TSE2004av */
196	if ((sdtemp_dev_table[i].sdtemp_mfg_id == 0)
197	    && (SDTEMP_IS_TSE2004AV(devrev) == 0))
198			i++; /* Unknown */
199
200	return i;
201}
202
203static int
204sdtemp_match(device_t parent, cfdata_t cf, void *aux)
205{
206	struct i2c_attach_args *ia = aux;
207	uint16_t mfgid, devid, cap;
208	struct sdtemp_softc sc;
209	int i, error;
210
211	sc.sc_tag = ia->ia_tag;
212	sc.sc_address = ia->ia_addr;
213
214	if ((ia->ia_addr & SDTEMP_ADDRMASK) != SDTEMP_ADDR)
215		return 0;
216
217	/*
218	 * Verify that we can read the manufacturer ID, Device ID and the
219	 * capability
220	 */
221	error = iic_acquire_bus(sc.sc_tag, 0);
222	if (error)
223		return 0;
224	error = sdtemp_read_16(&sc, SDTEMP_REG_MFG_ID,  &mfgid) |
225		sdtemp_read_16(&sc, SDTEMP_REG_DEV_REV, &devid) |
226		sdtemp_read_16(&sc, SDTEMP_REG_CAPABILITY, &cap);
227	iic_release_bus(sc.sc_tag, 0);
228
229	if (error)
230		return 0;
231
232	i = sdtemp_lookup(mfgid, devid);
233	if ((sdtemp_dev_table[i].sdtemp_mfg_id == 0) &&
234	    (sdtemp_dev_table[i].sdtemp_devrev == 0)) {
235		aprint_debug("sdtemp: No match for mfg 0x%04x dev 0x%02x "
236		    "rev 0x%02x at address 0x%02x\n", mfgid, devid >> 8,
237		    devid & 0xff, sc.sc_address);
238		return 0;
239	}
240
241	/*
242	 * Check by SDTEMP_IS_TSE2004AV() might not be enough, so check the
243	 * alarm capability, too.
244	 */
245	if ((cap & SDTEMP_CAP_HAS_ALARM) == 0)
246		return 0;
247
248	return I2C_MATCH_ADDRESS_AND_PROBE;
249}
250
251static void
252sdtemp_attach(device_t parent, device_t self, void *aux)
253{
254	struct sdtemp_softc *sc = device_private(self);
255	struct i2c_attach_args *ia = aux;
256	uint16_t mfgid, devid;
257	int i, error;
258
259	sc->sc_tag = ia->ia_tag;
260	sc->sc_address = ia->ia_addr;
261	sc->sc_dev = self;
262
263	error = iic_acquire_bus(sc->sc_tag, 0);
264	if (error)
265		return;
266
267	if ((error = sdtemp_read_16(sc, SDTEMP_REG_MFG_ID,  &mfgid)) != 0 ||
268	    (error = sdtemp_read_16(sc, SDTEMP_REG_DEV_REV, &devid)) != 0) {
269		iic_release_bus(sc->sc_tag, 0);
270		aprint_error(": attach error %d\n", error);
271		return;
272	}
273	sc->sc_mfgid = mfgid;
274	sc->sc_devid = devid;
275	i = sdtemp_lookup(mfgid, devid);
276	sc->sc_devid_masked = devid & sdtemp_dev_table[i].sdtemp_mask;
277
278	aprint_naive(": Temp Sensor\n");
279	aprint_normal(": %s Temp Sensor\n", sdtemp_dev_table[i].sdtemp_desc);
280
281	if (sdtemp_dev_table[i].sdtemp_mfg_id == 0) {
282		if (SDTEMP_IS_TSE2004AV(devid))
283			aprint_normal_dev(self, "TSE2004av compliant. "
284			    "Manufacturer ID 0x%04hx, Device revision 0x%02x\n",
285			    mfgid, devid & TSE2004AV_REV);
286		else {
287			aprint_error_dev(self,
288			    "mfg 0x%04x dev 0x%02x rev 0x%02x at addr 0x%02x\n",
289			    mfgid, devid >> 8, devid & 0xff, ia->ia_addr);
290			iic_release_bus(sc->sc_tag, 0);
291			aprint_error_dev(self, "It should no happen. "
292			    "Why attach() found me?\n");
293			return;
294		}
295	}
296
297	error = sdtemp_read_16(sc, SDTEMP_REG_CAPABILITY, &sc->sc_capability);
298	aprint_debug_dev(self, "capability reg = %04x\n", sc->sc_capability);
299	sc->sc_resolution
300	    = __SHIFTOUT(sc->sc_capability, SDTEMP_CAP_RESOLUTION);
301	/*
302	 * Call device dependent function here. Currently, it's used for
303	 * the resolution.
304	 *
305	 * IDT's devices and some Microchip's devices have the resolution
306	 * register in the vendor specific registers area. The devices'
307	 * resolution bits in the capability register are not the maximum
308	 * resolution but the current value of the setting.
309	 */
310	if (sdtemp_dev_table[i].sdtemp_config != NULL)
311		sdtemp_dev_table[i].sdtemp_config(sc);
312
313	aprint_normal_dev(self, "%s accuracy",
314	    (sc->sc_capability & SDTEMP_CAP_ACCURACY_1C) ? "high" : "default");
315	if ((sc->sc_capability & SDTEMP_CAP_WIDER_RANGE) != 0)
316		aprint_normal(", wider range");
317	aprint_normal(", %s resolution", temp_resl[sc->sc_resolution]);
318	if ((sc->sc_capability & SDTEMP_CAP_VHV) != 0)
319		aprint_debug(", high voltage standoff");
320	aprint_debug(", %s timeout",
321	    (sc->sc_capability & SDTEMP_CAP_TMOUT) ? "25-35ms" : "10-60ms");
322	if ((sc->sc_capability & SDTEMP_CAP_EVSD) != 0)
323		aprint_normal(", event with shutdown");
324	aprint_normal("\n");
325	/*
326	 * Alarm capability is required;  if not present, this is likely
327	 * not a real sdtemp device.
328	 */
329	if (error != 0 || (sc->sc_capability & SDTEMP_CAP_HAS_ALARM) == 0) {
330		iic_release_bus(sc->sc_tag, 0);
331		aprint_error_dev(self,
332		    "required alarm capability not present!\n");
333		return;
334	}
335	/* Set the configuration to defaults. */
336	error = sdtemp_write_16(sc, SDTEMP_REG_CONFIG, 0);
337	if (error != 0) {
338		iic_release_bus(sc->sc_tag, 0);
339		aprint_error_dev(self, "error %d writing config register\n",
340		    error);
341		return;
342	}
343	iic_release_bus(sc->sc_tag, 0);
344
345	/* Hook us into the sysmon_envsys subsystem */
346	sc->sc_sme = sysmon_envsys_create();
347	sc->sc_sme->sme_name = device_xname(self);
348	sc->sc_sme->sme_cookie = sc;
349	sc->sc_sme->sme_refresh = sdtemp_refresh;
350	sc->sc_sme->sme_get_limits = sdtemp_get_limits;
351	sc->sc_sme->sme_set_limits = sdtemp_set_limits;
352
353	sc->sc_sensor = kmem_zalloc(sizeof(envsys_data_t), KM_SLEEP);
354
355	/* Initialize sensor data. */
356	sc->sc_sensor->units =  ENVSYS_STEMP;
357	sc->sc_sensor->state = ENVSYS_SINVALID;
358	sc->sc_sensor->flags |= ENVSYS_FMONLIMITS;
359	(void)strlcpy(sc->sc_sensor->desc, device_xname(self),
360	    sizeof(sc->sc_sensor->desc));
361	snprintf(sc->sc_sensor->desc, sizeof(sc->sc_sensor->desc),
362	    "DIMM %d temperature", sc->sc_address - SDTEMP_ADDR);
363
364	/* Now attach the sensor */
365	if (sysmon_envsys_sensor_attach(sc->sc_sme, sc->sc_sensor)) {
366		aprint_error_dev(self, "unable to attach sensor\n");
367		goto bad;
368	}
369
370	/* Register the device */
371	error = sysmon_envsys_register(sc->sc_sme);
372	if (error) {
373		aprint_error_dev(self, "error %d registering with sysmon\n",
374		    error);
375		goto bad;
376	}
377
378	if (!pmf_device_register(self, sdtemp_pmf_suspend, sdtemp_pmf_resume))
379		aprint_error_dev(self, "couldn't establish power handler\n");
380
381	/* Retrieve and display hardware monitor limits */
382	sdtemp_get_limits(sc->sc_sme, sc->sc_sensor, &sc->sc_deflims,
383	    &sc->sc_defprops);
384	aprint_normal_dev(self, "Hardware limits: ");
385	i = 0;
386	if (sc->sc_defprops & PROP_WARNMIN) {
387		aprint_normal("low %dC",
388		              __UK2C(sc->sc_deflims.sel_warnmin));
389		i++;
390	}
391	if (sc->sc_defprops & PROP_WARNMAX) {
392		aprint_normal("%shigh %dC ", (i)?", ":"",
393			      __UK2C(sc->sc_deflims.sel_warnmax));
394		i++;
395	}
396	if (sc->sc_defprops & PROP_CRITMAX) {
397		aprint_normal("%scritical %dC ", (i)?", ":"",
398			      __UK2C(sc->sc_deflims.sel_critmax));
399		i++;
400	}
401	aprint_normal("%s\n", (i)?"":"none set");
402
403	return;
404
405bad:
406	kmem_free(sc->sc_sensor, sizeof(envsys_data_t));
407	sysmon_envsys_destroy(sc->sc_sme);
408	sc->sc_sme = NULL;
409}
410
411static int
412sdtemp_detach(device_t self, int flags)
413{
414	struct sdtemp_softc *sc = device_private(self);
415
416	pmf_device_deregister(self);
417
418	if (sc->sc_sme)
419		sysmon_envsys_unregister(sc->sc_sme);
420	if (sc->sc_sensor)
421		kmem_free(sc->sc_sensor, sizeof(envsys_data_t));
422
423	return 0;
424}
425
426/* Retrieve current limits from device, and encode in uKelvins */
427static void
428sdtemp_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
429		  sysmon_envsys_lim_t *limits, uint32_t *props)
430{
431	struct sdtemp_softc *sc = sme->sme_cookie;
432	uint16_t lim;
433
434	*props = 0;
435	if (iic_acquire_bus(sc->sc_tag, 0) != 0)
436		return;
437
438	if (sdtemp_read_16(sc, SDTEMP_REG_LOWER_LIM, &lim) == 0 && lim != 0) {
439		limits->sel_warnmin = sdtemp_decode_temp(sc, lim);
440		*props |= PROP_WARNMIN;
441	}
442	if (sdtemp_read_16(sc, SDTEMP_REG_UPPER_LIM, &lim) == 0 && lim != 0) {
443		limits->sel_warnmax = sdtemp_decode_temp(sc, lim);
444		*props |= PROP_WARNMAX;
445	}
446	if (sdtemp_read_16(sc, SDTEMP_REG_CRIT_LIM, &lim) == 0 && lim != 0) {
447		limits->sel_critmax = sdtemp_decode_temp(sc, lim);
448		*props |= PROP_CRITMAX;
449	}
450	iic_release_bus(sc->sc_tag, 0);
451	if (*props != 0)
452		*props |= PROP_DRIVER_LIMITS;
453}
454
455/* Send current limit values to the device */
456static void
457sdtemp_set_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
458		  sysmon_envsys_lim_t *limits, uint32_t *props)
459{
460	uint16_t val;
461	struct sdtemp_softc *sc = sme->sme_cookie;
462
463	if (limits == NULL) {
464		limits = &sc->sc_deflims;
465		props  = &sc->sc_defprops;
466	}
467	if (iic_acquire_bus(sc->sc_tag, 0) != 0)
468		return;
469
470	if (*props & PROP_WARNMIN) {
471		val = __UK2C(limits->sel_warnmin);
472		(void)sdtemp_write_16(sc, SDTEMP_REG_LOWER_LIM,
473					(val << 4) & SDTEMP_TEMP_MASK);
474	}
475	if (*props & PROP_WARNMAX) {
476		val = __UK2C(limits->sel_warnmax);
477		(void)sdtemp_write_16(sc, SDTEMP_REG_UPPER_LIM,
478					(val << 4) & SDTEMP_TEMP_MASK);
479	}
480	if (*props & PROP_CRITMAX) {
481		val = __UK2C(limits->sel_critmax);
482		(void)sdtemp_write_16(sc, SDTEMP_REG_CRIT_LIM,
483					(val << 4) & SDTEMP_TEMP_MASK);
484	}
485	iic_release_bus(sc->sc_tag, 0);
486
487	/*
488	 * If at least one limit is set that we can handle, and no
489	 * limits are set that we cannot handle, tell sysmon that
490	 * the driver will take care of monitoring the limits!
491	 */
492	if (*props & (PROP_CRITMIN | PROP_BATTCAP | PROP_BATTWARN))
493		*props &= ~PROP_DRIVER_LIMITS;
494	else if (*props & PROP_LIMITS)
495		*props |= PROP_DRIVER_LIMITS;
496	else
497		*props &= ~PROP_DRIVER_LIMITS;
498}
499
500#ifdef NOT_YET	/* All registers on these sensors are 16-bits */
501
502/* Read a 8-bit value from a register */
503static int
504sdtemp_read_8(struct sdtemp_softc *sc, uint8_t reg, uint8_t *valp)
505{
506	int error;
507
508	error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
509	    sc->sc_address, &reg, 1, valp, sizeof(*valp), 0);
510
511	return error;
512}
513
514static int
515sdtemp_write_8(struct sdtemp_softc *sc, uint8_t reg, uint8_t val)
516{
517	return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
518	    sc->sc_address, &reg, 1, &val, sizeof(val), 0);
519}
520#endif /* NOT_YET */
521
522/* Read a 16-bit value from a register */
523static int
524sdtemp_read_16(struct sdtemp_softc *sc, uint8_t reg, uint16_t *valp)
525{
526	int error;
527
528	error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
529	    sc->sc_address, &reg, 1, valp, sizeof(*valp), 0);
530	if (error)
531		return error;
532
533	*valp = be16toh(*valp);
534
535	return 0;
536}
537
538static int
539sdtemp_write_16(struct sdtemp_softc *sc, uint8_t reg, uint16_t val)
540{
541	uint16_t temp;
542
543	temp = htobe16(val);
544	return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
545	    sc->sc_address, &reg, 1, &temp, sizeof(temp), 0);
546}
547
548static uint32_t
549sdtemp_decode_temp(struct sdtemp_softc *sc, uint16_t temp)
550{
551	uint32_t val;
552	int32_t stemp;
553
554	/* Get only the temperature bits */
555	temp &= SDTEMP_TEMP_MASK;
556
557	/* If necessary, extend the sign bit */
558	if ((sc->sc_capability & SDTEMP_CAP_WIDER_RANGE) &&
559	    (temp & SDTEMP_TEMP_NEGATIVE))
560		temp |= SDTEMP_TEMP_SIGN_EXT;
561
562	/* Mask off only bits valid within current resolution */
563	temp &= ~(0x7 >> sc->sc_resolution);
564
565	/* Treat as signed and extend to 32-bits */
566	stemp = (int16_t)temp;
567
568	/* Now convert from 0.0625 (1/16) deg C increments to microKelvins */
569	val = (stemp * 62500) + 273150000;
570
571	return val;
572}
573
574static void
575sdtemp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
576{
577	struct sdtemp_softc *sc = sme->sme_cookie;
578	uint16_t val;
579	int error;
580
581	error = iic_acquire_bus(sc->sc_tag, 0);
582	if (error) {
583		edata->state = ENVSYS_SINVALID;
584		return;
585	}
586
587	error = sdtemp_read_16(sc, SDTEMP_REG_AMBIENT_TEMP, &val);
588	iic_release_bus(sc->sc_tag, 0);
589
590	if (error) {
591		edata->state = ENVSYS_SINVALID;
592		return;
593	}
594
595	edata->value_cur = sdtemp_decode_temp(sc, val);
596
597	/* Now check for limits */
598	if ((edata->upropset & PROP_DRIVER_LIMITS) == 0)
599		edata->state = ENVSYS_SVALID;
600	else if ((val & SDTEMP_ABOVE_CRIT) &&
601		    (edata->upropset & PROP_CRITMAX))
602		edata->state = ENVSYS_SCRITOVER;
603	else if ((val & SDTEMP_ABOVE_UPPER) &&
604		    (edata->upropset & PROP_WARNMAX))
605		edata->state = ENVSYS_SWARNOVER;
606	else if ((val & SDTEMP_BELOW_LOWER) &&
607		    (edata->upropset & PROP_WARNMIN))
608		edata->state = ENVSYS_SWARNUNDER;
609	else
610		edata->state = ENVSYS_SVALID;
611}
612
613/*
614 * Power management functions
615 *
616 * We go into "shutdown" mode at suspend time, and return to normal
617 * mode upon resume.  This reduces power consumption by disabling
618 * the A/D converter.
619 */
620
621static bool
622sdtemp_pmf_suspend(device_t dev, const pmf_qual_t *qual)
623{
624	struct sdtemp_softc *sc = device_private(dev);
625	int error;
626	uint16_t config;
627
628	error = iic_acquire_bus(sc->sc_tag, 0);
629	if (error != 0)
630		return false;
631
632	error = sdtemp_read_16(sc, SDTEMP_REG_CONFIG, &config);
633	if (error == 0) {
634		config |= SDTEMP_CONFIG_SHUTDOWN_MODE;
635		error = sdtemp_write_16(sc, SDTEMP_REG_CONFIG, config);
636	}
637	iic_release_bus(sc->sc_tag, 0);
638	return (error == 0);
639}
640
641static bool
642sdtemp_pmf_resume(device_t dev, const pmf_qual_t *qual)
643{
644	struct sdtemp_softc *sc = device_private(dev);
645	int error;
646	uint16_t config;
647
648	error = iic_acquire_bus(sc->sc_tag, 0);
649	if (error != 0)
650		return false;
651
652	error = sdtemp_read_16(sc, SDTEMP_REG_CONFIG, &config);
653	if (error == 0) {
654		config &= ~SDTEMP_CONFIG_SHUTDOWN_MODE;
655		error = sdtemp_write_16(sc, SDTEMP_REG_CONFIG, config);
656	}
657	iic_release_bus(sc->sc_tag, 0);
658	return (error == 0);
659}
660
661/* Device dependent config functions */
662
663static void
664sdtemp_config_mcp(struct sdtemp_softc *sc)
665{
666	int rv;
667	uint8_t resolreg;
668
669	/* Note that MCP9805 has no resolution register */
670	switch (sc->sc_devid_masked) {
671	case MCP_9804_DEVICE_ID:
672	case MCP_98242_DEVICE_ID:
673	case MCP_98243_DEVICE_ID:
674		resolreg = SDTEMP_REG_MCP_RESOLUTION_9804;
675		break;
676	case MCP_98244_DEVICE_ID:
677		resolreg = SDTEMP_REG_MCP_RESOLUTION_98244;
678		break;
679	default:
680		aprint_error("%s: %s: unknown device ID (%04hx)\n",
681		    device_xname(sc->sc_dev), __func__, sc->sc_devid_masked);
682		return;
683	}
684
685	/*
686	 * Set resolution to the max.
687	 *
688	 * Even if it fails, the resolution will be the default. It's not a
689	 * fatal error.
690	 */
691	rv = sdtemp_write_16(sc, resolreg, SDTEMP_CAP_RESOLUTION_MAX);
692	if (rv == 0)
693		sc->sc_resolution = SDTEMP_CAP_RESOLUTION_MAX;
694	else
695		aprint_debug_dev(sc->sc_dev,
696		    "error %d writing resolution register\n", rv);
697}
698
699static void
700sdtemp_config_idt(struct sdtemp_softc *sc)
701{
702	int rv;
703
704	/*
705	 * Set resolution to the max.
706	 *
707	 * Even if it fails, the resolution will be the default. It's not a
708	 * fatal error.
709	 */
710	rv = sdtemp_write_16(sc, SDTEMP_REG_IDT_RESOLUTION,
711	    __SHIFTIN(SDTEMP_CAP_RESOLUTION_MAX, SDTEMP_CAP_RESOLUTION));
712	if (rv == 0)
713		sc->sc_resolution = SDTEMP_CAP_RESOLUTION_MAX;
714	else
715		aprint_debug_dev(sc->sc_dev,
716		    "error %d writing resolution register\n", rv);
717}
718
719MODULE(MODULE_CLASS_DRIVER, sdtemp, "i2cexec,sysmon_envsys");
720
721#ifdef _MODULE
722#include "ioconf.c"
723#endif
724
725static int
726sdtemp_modcmd(modcmd_t cmd, void *opaque)
727{
728	int error = 0;
729
730	switch (cmd) {
731	case MODULE_CMD_INIT:
732#ifdef _MODULE
733		error = config_init_component(cfdriver_ioconf_sdtemp,
734		    cfattach_ioconf_sdtemp, cfdata_ioconf_sdtemp);
735#endif
736		return error;
737	case MODULE_CMD_FINI:
738#ifdef _MODULE
739		error = config_fini_component(cfdriver_ioconf_sdtemp,
740		    cfattach_ioconf_sdtemp, cfdata_ioconf_sdtemp);
741#endif
742		return error;
743	default:
744		return ENOTTY;
745	}
746}
747