xref: /freebsd-src/sys/dev/iicbus/sensor/lm75.c (revision 7c569caa0a6fffa7e1cc0a7f61e986dbc7c59074)
1*7c569caaSEmmanuel Vadot /*-
2*7c569caaSEmmanuel Vadot  * Copyright (c) 2010 Andreas Tobler.
3*7c569caaSEmmanuel Vadot  * Copyright (c) 2013-2014 Luiz Otavio O Souza <loos@freebsd.org>
4*7c569caaSEmmanuel Vadot  * All rights reserved.
5*7c569caaSEmmanuel Vadot  *
6*7c569caaSEmmanuel Vadot  * Redistribution and use in source and binary forms, with or without
7*7c569caaSEmmanuel Vadot  * modification, are permitted provided that the following conditions
8*7c569caaSEmmanuel Vadot  * are met:
9*7c569caaSEmmanuel Vadot  * 1. Redistributions of source code must retain the above copyright
10*7c569caaSEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer.
11*7c569caaSEmmanuel Vadot  * 2. Redistributions in binary form must reproduce the above copyright
12*7c569caaSEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer in the
13*7c569caaSEmmanuel Vadot  *    documentation and/or other materials provided with the distribution.
14*7c569caaSEmmanuel Vadot  *
15*7c569caaSEmmanuel Vadot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16*7c569caaSEmmanuel Vadot  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17*7c569caaSEmmanuel Vadot  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18*7c569caaSEmmanuel Vadot  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19*7c569caaSEmmanuel Vadot  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20*7c569caaSEmmanuel Vadot  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21*7c569caaSEmmanuel Vadot  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22*7c569caaSEmmanuel Vadot  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23*7c569caaSEmmanuel Vadot  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*7c569caaSEmmanuel Vadot  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*7c569caaSEmmanuel Vadot  * SUCH DAMAGE.
26*7c569caaSEmmanuel Vadot  */
27*7c569caaSEmmanuel Vadot 
28*7c569caaSEmmanuel Vadot #include <sys/cdefs.h>
29*7c569caaSEmmanuel Vadot #include "opt_platform.h"
30*7c569caaSEmmanuel Vadot 
31*7c569caaSEmmanuel Vadot #include <sys/param.h>
32*7c569caaSEmmanuel Vadot #include <sys/bus.h>
33*7c569caaSEmmanuel Vadot #include <sys/endian.h>
34*7c569caaSEmmanuel Vadot #include <sys/kernel.h>
35*7c569caaSEmmanuel Vadot #include <sys/module.h>
36*7c569caaSEmmanuel Vadot #include <sys/sysctl.h>
37*7c569caaSEmmanuel Vadot #include <sys/systm.h>
38*7c569caaSEmmanuel Vadot 
39*7c569caaSEmmanuel Vadot #include <machine/bus.h>
40*7c569caaSEmmanuel Vadot 
41*7c569caaSEmmanuel Vadot #include <dev/iicbus/iicbus.h>
42*7c569caaSEmmanuel Vadot #include <dev/iicbus/iiconf.h>
43*7c569caaSEmmanuel Vadot 
44*7c569caaSEmmanuel Vadot #ifdef FDT
45*7c569caaSEmmanuel Vadot #include <dev/ofw/openfirm.h>
46*7c569caaSEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
47*7c569caaSEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
48*7c569caaSEmmanuel Vadot #endif
49*7c569caaSEmmanuel Vadot 
50*7c569caaSEmmanuel Vadot /* LM75 registers. */
51*7c569caaSEmmanuel Vadot #define	LM75_TEMP	0x0
52*7c569caaSEmmanuel Vadot #define	LM75_CONF	0x1
53*7c569caaSEmmanuel Vadot #define	LM75_CONF_FSHIFT	3
54*7c569caaSEmmanuel Vadot #define	LM75_CONF_FAULT		0x18
55*7c569caaSEmmanuel Vadot #define	LM75_CONF_POL		0x04
56*7c569caaSEmmanuel Vadot #define	LM75_CONF_MODE		0x02
57*7c569caaSEmmanuel Vadot #define	LM75_CONF_SHUTD		0x01
58*7c569caaSEmmanuel Vadot #define	LM75_CONF_MASK		0x1f
59*7c569caaSEmmanuel Vadot #define	LM75_THYST	0x2
60*7c569caaSEmmanuel Vadot #define	LM75_TOS	0x3
61*7c569caaSEmmanuel Vadot 
62*7c569caaSEmmanuel Vadot /* LM75 constants. */
63*7c569caaSEmmanuel Vadot #define	LM75_TEST_PATTERN	0xa
64*7c569caaSEmmanuel Vadot #define	LM75_MIN_TEMP		-55
65*7c569caaSEmmanuel Vadot #define	LM75_MAX_TEMP		125
66*7c569caaSEmmanuel Vadot #define	TZ_ZEROC		27315
67*7c569caaSEmmanuel Vadot #define	TZ_ZEROC_DIVIDER	100
68*7c569caaSEmmanuel Vadot 
69*7c569caaSEmmanuel Vadot enum max_resolution{
70*7c569caaSEmmanuel Vadot 	BITS_9 = 1,
71*7c569caaSEmmanuel Vadot 	BITS_11
72*7c569caaSEmmanuel Vadot };
73*7c569caaSEmmanuel Vadot 
74*7c569caaSEmmanuel Vadot /* Regular bus attachment functions */
75*7c569caaSEmmanuel Vadot static int  lm75_probe(device_t);
76*7c569caaSEmmanuel Vadot static int  lm75_attach(device_t);
77*7c569caaSEmmanuel Vadot 
78*7c569caaSEmmanuel Vadot struct lm75_softc {
79*7c569caaSEmmanuel Vadot 	device_t		sc_dev;
80*7c569caaSEmmanuel Vadot 	struct intr_config_hook enum_hook;
81*7c569caaSEmmanuel Vadot 	uint32_t		sc_addr;
82*7c569caaSEmmanuel Vadot 	uint32_t		sc_conf;
83*7c569caaSEmmanuel Vadot 	uint8_t			sc_resolution;
84*7c569caaSEmmanuel Vadot 	uint8_t			sc_max_resolution;
85*7c569caaSEmmanuel Vadot 	uint16_t		sc_multiplier;
86*7c569caaSEmmanuel Vadot };
87*7c569caaSEmmanuel Vadot 
88*7c569caaSEmmanuel Vadot /* Utility functions */
89*7c569caaSEmmanuel Vadot static int  lm75_conf_read(struct lm75_softc *);
90*7c569caaSEmmanuel Vadot static int  lm75_conf_write(struct lm75_softc *);
91*7c569caaSEmmanuel Vadot static int  lm75_temp_read(struct lm75_softc *, uint8_t, int *);
92*7c569caaSEmmanuel Vadot static int  lm75_temp_write(struct lm75_softc *, uint8_t, int);
93*7c569caaSEmmanuel Vadot static void lm75_start(void *);
94*7c569caaSEmmanuel Vadot static int  lm75_read(device_t, uint32_t, uint8_t, uint8_t *, size_t);
95*7c569caaSEmmanuel Vadot static int  lm75_write(device_t, uint32_t, uint8_t *, size_t);
96*7c569caaSEmmanuel Vadot static int  lm75_str_mode(char *);
97*7c569caaSEmmanuel Vadot static int  lm75_str_pol(char *);
98*7c569caaSEmmanuel Vadot static int  lm75_temp_sysctl(SYSCTL_HANDLER_ARGS);
99*7c569caaSEmmanuel Vadot static int  lm75_faults_sysctl(SYSCTL_HANDLER_ARGS);
100*7c569caaSEmmanuel Vadot static int  lm75_mode_sysctl(SYSCTL_HANDLER_ARGS);
101*7c569caaSEmmanuel Vadot static int  lm75_pol_sysctl(SYSCTL_HANDLER_ARGS);
102*7c569caaSEmmanuel Vadot static int  lm75_shutdown_sysctl(SYSCTL_HANDLER_ARGS);
103*7c569caaSEmmanuel Vadot static int  lm75_resolution_sysctl(SYSCTL_HANDLER_ARGS);
104*7c569caaSEmmanuel Vadot 
105*7c569caaSEmmanuel Vadot static device_method_t  lm75_methods[] = {
106*7c569caaSEmmanuel Vadot 	/* Device interface */
107*7c569caaSEmmanuel Vadot 	DEVMETHOD(device_probe,		lm75_probe),
108*7c569caaSEmmanuel Vadot 	DEVMETHOD(device_attach,	lm75_attach),
109*7c569caaSEmmanuel Vadot 
110*7c569caaSEmmanuel Vadot 	DEVMETHOD_END
111*7c569caaSEmmanuel Vadot };
112*7c569caaSEmmanuel Vadot 
113*7c569caaSEmmanuel Vadot static driver_t lm75_driver = {
114*7c569caaSEmmanuel Vadot 	"lm75",
115*7c569caaSEmmanuel Vadot 	lm75_methods,
116*7c569caaSEmmanuel Vadot 	sizeof(struct lm75_softc)
117*7c569caaSEmmanuel Vadot };
118*7c569caaSEmmanuel Vadot 
119*7c569caaSEmmanuel Vadot #ifdef FDT
120*7c569caaSEmmanuel Vadot static struct ofw_compat_data compat_data[] = {
121*7c569caaSEmmanuel Vadot 	{"national,lm75",	BITS_9},
122*7c569caaSEmmanuel Vadot 	{"ti,lm75",		BITS_9},
123*7c569caaSEmmanuel Vadot 	{0,0}
124*7c569caaSEmmanuel Vadot };
125*7c569caaSEmmanuel Vadot #endif
126*7c569caaSEmmanuel Vadot 
127*7c569caaSEmmanuel Vadot DRIVER_MODULE(lm75, iicbus, lm75_driver, 0, 0);
128*7c569caaSEmmanuel Vadot 
129*7c569caaSEmmanuel Vadot static int
lm75_read(device_t dev,uint32_t addr,uint8_t reg,uint8_t * data,size_t len)130*7c569caaSEmmanuel Vadot lm75_read(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data, size_t len)
131*7c569caaSEmmanuel Vadot {
132*7c569caaSEmmanuel Vadot 	struct iic_msg msg[2] = {
133*7c569caaSEmmanuel Vadot 	    { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &reg },
134*7c569caaSEmmanuel Vadot 	    { addr, IIC_M_RD, len, data },
135*7c569caaSEmmanuel Vadot 	};
136*7c569caaSEmmanuel Vadot 
137*7c569caaSEmmanuel Vadot 	if (iicbus_transfer(dev, msg, nitems(msg)) != 0)
138*7c569caaSEmmanuel Vadot 		return (-1);
139*7c569caaSEmmanuel Vadot 
140*7c569caaSEmmanuel Vadot 	return (0);
141*7c569caaSEmmanuel Vadot }
142*7c569caaSEmmanuel Vadot 
143*7c569caaSEmmanuel Vadot static int
lm75_write(device_t dev,uint32_t addr,uint8_t * data,size_t len)144*7c569caaSEmmanuel Vadot lm75_write(device_t dev, uint32_t addr, uint8_t *data, size_t len)
145*7c569caaSEmmanuel Vadot {
146*7c569caaSEmmanuel Vadot 	struct iic_msg msg[1] = {
147*7c569caaSEmmanuel Vadot 	    { addr, IIC_M_WR, len, data },
148*7c569caaSEmmanuel Vadot 	};
149*7c569caaSEmmanuel Vadot 
150*7c569caaSEmmanuel Vadot 	if (iicbus_transfer(dev, msg, nitems(msg)) != 0)
151*7c569caaSEmmanuel Vadot 		return (-1);
152*7c569caaSEmmanuel Vadot 
153*7c569caaSEmmanuel Vadot 	return (0);
154*7c569caaSEmmanuel Vadot }
155*7c569caaSEmmanuel Vadot 
156*7c569caaSEmmanuel Vadot static int
lm75_probe(device_t dev)157*7c569caaSEmmanuel Vadot lm75_probe(device_t dev)
158*7c569caaSEmmanuel Vadot {
159*7c569caaSEmmanuel Vadot #ifdef FDT
160*7c569caaSEmmanuel Vadot 	const struct ofw_compat_data *compat_ptr;
161*7c569caaSEmmanuel Vadot #endif
162*7c569caaSEmmanuel Vadot 	struct lm75_softc *sc;
163*7c569caaSEmmanuel Vadot 
164*7c569caaSEmmanuel Vadot 	sc = device_get_softc(dev);
165*7c569caaSEmmanuel Vadot 	sc->sc_max_resolution = 9;
166*7c569caaSEmmanuel Vadot 
167*7c569caaSEmmanuel Vadot #ifdef FDT
168*7c569caaSEmmanuel Vadot 	if (!ofw_bus_status_okay(dev))
169*7c569caaSEmmanuel Vadot 		return (ENXIO);
170*7c569caaSEmmanuel Vadot 
171*7c569caaSEmmanuel Vadot 	compat_ptr = ofw_bus_search_compatible(dev, compat_data);
172*7c569caaSEmmanuel Vadot 
173*7c569caaSEmmanuel Vadot 	switch (compat_ptr->ocd_data){
174*7c569caaSEmmanuel Vadot 	case BITS_9:
175*7c569caaSEmmanuel Vadot 		sc->sc_max_resolution = 9;
176*7c569caaSEmmanuel Vadot 		break;
177*7c569caaSEmmanuel Vadot 	case BITS_11:
178*7c569caaSEmmanuel Vadot 		sc->sc_max_resolution = 11;
179*7c569caaSEmmanuel Vadot 		break;
180*7c569caaSEmmanuel Vadot 	default:
181*7c569caaSEmmanuel Vadot 		return (ENXIO);
182*7c569caaSEmmanuel Vadot 	}
183*7c569caaSEmmanuel Vadot #endif
184*7c569caaSEmmanuel Vadot 	device_set_desc(dev, "LM75 temperature sensor");
185*7c569caaSEmmanuel Vadot 
186*7c569caaSEmmanuel Vadot 	return (BUS_PROBE_GENERIC);
187*7c569caaSEmmanuel Vadot }
188*7c569caaSEmmanuel Vadot 
189*7c569caaSEmmanuel Vadot static int
lm75_attach(device_t dev)190*7c569caaSEmmanuel Vadot lm75_attach(device_t dev)
191*7c569caaSEmmanuel Vadot {
192*7c569caaSEmmanuel Vadot 	struct lm75_softc *sc;
193*7c569caaSEmmanuel Vadot 
194*7c569caaSEmmanuel Vadot 	sc = device_get_softc(dev);
195*7c569caaSEmmanuel Vadot 	sc->sc_dev = dev;
196*7c569caaSEmmanuel Vadot 	sc->sc_addr = iicbus_get_addr(dev);
197*7c569caaSEmmanuel Vadot 
198*7c569caaSEmmanuel Vadot 	sc->enum_hook.ich_func = lm75_start;
199*7c569caaSEmmanuel Vadot 	sc->enum_hook.ich_arg = dev;
200*7c569caaSEmmanuel Vadot 
201*7c569caaSEmmanuel Vadot 	switch (sc->sc_max_resolution) {
202*7c569caaSEmmanuel Vadot 	case 9:
203*7c569caaSEmmanuel Vadot 		sc->sc_resolution = 9;
204*7c569caaSEmmanuel Vadot 		sc->sc_max_resolution = 9;
205*7c569caaSEmmanuel Vadot 		sc->sc_multiplier = 10;
206*7c569caaSEmmanuel Vadot 		break;
207*7c569caaSEmmanuel Vadot 	case 11:
208*7c569caaSEmmanuel Vadot 		sc->sc_resolution = 11;
209*7c569caaSEmmanuel Vadot 		sc->sc_max_resolution = 11;
210*7c569caaSEmmanuel Vadot 		sc->sc_multiplier = 1000;
211*7c569caaSEmmanuel Vadot 		break;
212*7c569caaSEmmanuel Vadot 	default:
213*7c569caaSEmmanuel Vadot 		return (ENXIO);
214*7c569caaSEmmanuel Vadot 	}
215*7c569caaSEmmanuel Vadot 
216*7c569caaSEmmanuel Vadot 	/*
217*7c569caaSEmmanuel Vadot 	 * We have to wait until interrupts are enabled.  Usually I2C read
218*7c569caaSEmmanuel Vadot 	 * and write only works when the interrupts are available.
219*7c569caaSEmmanuel Vadot 	 */
220*7c569caaSEmmanuel Vadot 	if (config_intrhook_establish(&sc->enum_hook) != 0)
221*7c569caaSEmmanuel Vadot 		return (ENOMEM);
222*7c569caaSEmmanuel Vadot 
223*7c569caaSEmmanuel Vadot 	return (0);
224*7c569caaSEmmanuel Vadot }
225*7c569caaSEmmanuel Vadot 
226*7c569caaSEmmanuel Vadot static int
lm75_type_detect(struct lm75_softc * sc)227*7c569caaSEmmanuel Vadot lm75_type_detect(struct lm75_softc *sc)
228*7c569caaSEmmanuel Vadot {
229*7c569caaSEmmanuel Vadot 	int i, lm75a;
230*7c569caaSEmmanuel Vadot 	uint8_t buf8;
231*7c569caaSEmmanuel Vadot 	uint32_t conf;
232*7c569caaSEmmanuel Vadot 
233*7c569caaSEmmanuel Vadot 	/* Save the contents of the configuration register. */
234*7c569caaSEmmanuel Vadot 	if (lm75_conf_read(sc) != 0)
235*7c569caaSEmmanuel Vadot 		return (-1);
236*7c569caaSEmmanuel Vadot 	conf = sc->sc_conf;
237*7c569caaSEmmanuel Vadot 
238*7c569caaSEmmanuel Vadot 	/*
239*7c569caaSEmmanuel Vadot 	 * Just write some pattern at configuration register so we can later
240*7c569caaSEmmanuel Vadot 	 * verify.  The test pattern should be pretty harmless.
241*7c569caaSEmmanuel Vadot 	 */
242*7c569caaSEmmanuel Vadot 	sc->sc_conf = LM75_TEST_PATTERN;
243*7c569caaSEmmanuel Vadot 	if (lm75_conf_write(sc) != 0)
244*7c569caaSEmmanuel Vadot 		return (-1);
245*7c569caaSEmmanuel Vadot 
246*7c569caaSEmmanuel Vadot 	/*
247*7c569caaSEmmanuel Vadot 	 * Read the configuration register again and check for our test
248*7c569caaSEmmanuel Vadot 	 * pattern.
249*7c569caaSEmmanuel Vadot 	 */
250*7c569caaSEmmanuel Vadot 	if (lm75_conf_read(sc) != 0)
251*7c569caaSEmmanuel Vadot 		return (-1);
252*7c569caaSEmmanuel Vadot 	if (sc->sc_conf != LM75_TEST_PATTERN)
253*7c569caaSEmmanuel Vadot 		return (-1);
254*7c569caaSEmmanuel Vadot 
255*7c569caaSEmmanuel Vadot 	/*
256*7c569caaSEmmanuel Vadot 	 * Read from nonexistent registers (0x4 ~ 0x6).
257*7c569caaSEmmanuel Vadot 	 * LM75A always return 0xff for nonexistent registers.
258*7c569caaSEmmanuel Vadot 	 * LM75 will return the last read value - our test pattern written to
259*7c569caaSEmmanuel Vadot 	 * configuration register.
260*7c569caaSEmmanuel Vadot 	 */
261*7c569caaSEmmanuel Vadot 	lm75a = 0;
262*7c569caaSEmmanuel Vadot 	for (i = 4; i <= 6; i++) {
263*7c569caaSEmmanuel Vadot 		if (lm75_read(sc->sc_dev, sc->sc_addr, i,
264*7c569caaSEmmanuel Vadot 		    &buf8, sizeof(buf8)) < 0)
265*7c569caaSEmmanuel Vadot 			return (-1);
266*7c569caaSEmmanuel Vadot 		if (buf8 != LM75_TEST_PATTERN && buf8 != 0xff)
267*7c569caaSEmmanuel Vadot 			return (-1);
268*7c569caaSEmmanuel Vadot 		if (buf8 == 0xff)
269*7c569caaSEmmanuel Vadot 			lm75a++;
270*7c569caaSEmmanuel Vadot 	}
271*7c569caaSEmmanuel Vadot 	if (lm75a == 3){
272*7c569caaSEmmanuel Vadot 		sc->sc_multiplier = 1000;
273*7c569caaSEmmanuel Vadot 		sc->sc_resolution = 11;
274*7c569caaSEmmanuel Vadot 		sc->sc_max_resolution = 11;
275*7c569caaSEmmanuel Vadot 	}
276*7c569caaSEmmanuel Vadot 
277*7c569caaSEmmanuel Vadot 	/* Restore the configuration register. */
278*7c569caaSEmmanuel Vadot 	sc->sc_conf = conf;
279*7c569caaSEmmanuel Vadot 	if (lm75_conf_write(sc) != 0)
280*7c569caaSEmmanuel Vadot 		return (-1);
281*7c569caaSEmmanuel Vadot 
282*7c569caaSEmmanuel Vadot 	return (0);
283*7c569caaSEmmanuel Vadot }
284*7c569caaSEmmanuel Vadot 
285*7c569caaSEmmanuel Vadot static void
lm75_start(void * xdev)286*7c569caaSEmmanuel Vadot lm75_start(void *xdev)
287*7c569caaSEmmanuel Vadot {
288*7c569caaSEmmanuel Vadot 	device_t dev;
289*7c569caaSEmmanuel Vadot 	struct lm75_softc *sc;
290*7c569caaSEmmanuel Vadot 	struct sysctl_ctx_list *ctx;
291*7c569caaSEmmanuel Vadot 	struct sysctl_oid *tree_node;
292*7c569caaSEmmanuel Vadot 	struct sysctl_oid_list *tree;
293*7c569caaSEmmanuel Vadot 	char *mult_format;
294*7c569caaSEmmanuel Vadot 
295*7c569caaSEmmanuel Vadot 	dev = (device_t)xdev;
296*7c569caaSEmmanuel Vadot 	sc = device_get_softc(dev);
297*7c569caaSEmmanuel Vadot 	ctx = device_get_sysctl_ctx(dev);
298*7c569caaSEmmanuel Vadot 	tree_node = device_get_sysctl_tree(dev);
299*7c569caaSEmmanuel Vadot 	tree = SYSCTL_CHILDREN(tree_node);
300*7c569caaSEmmanuel Vadot 
301*7c569caaSEmmanuel Vadot 	config_intrhook_disestablish(&sc->enum_hook);
302*7c569caaSEmmanuel Vadot 
303*7c569caaSEmmanuel Vadot 	/*
304*7c569caaSEmmanuel Vadot 	 * Detect the kind of chip we are attaching to.
305*7c569caaSEmmanuel Vadot 	 * This may not work for LM75 clones.
306*7c569caaSEmmanuel Vadot 	 */
307*7c569caaSEmmanuel Vadot 	if (lm75_type_detect(sc) != 0) {
308*7c569caaSEmmanuel Vadot 		device_printf(dev, "cannot detect sensor.\n");
309*7c569caaSEmmanuel Vadot #ifndef FDT
310*7c569caaSEmmanuel Vadot 		return;
311*7c569caaSEmmanuel Vadot #endif
312*7c569caaSEmmanuel Vadot 	}
313*7c569caaSEmmanuel Vadot 
314*7c569caaSEmmanuel Vadot 	device_printf(dev,"%d bit resolution sensor attached.\n",
315*7c569caaSEmmanuel Vadot 			sc->sc_resolution);
316*7c569caaSEmmanuel Vadot 
317*7c569caaSEmmanuel Vadot 	if (sc->sc_multiplier == 1000)
318*7c569caaSEmmanuel Vadot 		mult_format = "IK3";
319*7c569caaSEmmanuel Vadot 	else
320*7c569caaSEmmanuel Vadot 		mult_format = "IK";
321*7c569caaSEmmanuel Vadot 
322*7c569caaSEmmanuel Vadot 	/* Temperature. */
323*7c569caaSEmmanuel Vadot 	SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "temperature",
324*7c569caaSEmmanuel Vadot 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, LM75_TEMP,
325*7c569caaSEmmanuel Vadot 	    lm75_temp_sysctl, mult_format, "Current temperature");
326*7c569caaSEmmanuel Vadot 	SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "thyst",
327*7c569caaSEmmanuel Vadot 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, LM75_THYST,
328*7c569caaSEmmanuel Vadot 	    lm75_temp_sysctl, mult_format, "Hysteresis temperature");
329*7c569caaSEmmanuel Vadot 	SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "tos",
330*7c569caaSEmmanuel Vadot 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, LM75_TOS,
331*7c569caaSEmmanuel Vadot 	    lm75_temp_sysctl, mult_format, "Overtemperature");
332*7c569caaSEmmanuel Vadot 
333*7c569caaSEmmanuel Vadot 	/* Configuration parameters. */
334*7c569caaSEmmanuel Vadot 	SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "faults",
335*7c569caaSEmmanuel Vadot 	    CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, dev, 0,
336*7c569caaSEmmanuel Vadot 	    lm75_faults_sysctl, "IU", "LM75 fault queue");
337*7c569caaSEmmanuel Vadot 	SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "mode",
338*7c569caaSEmmanuel Vadot 	    CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_MPSAFE, dev, 0,
339*7c569caaSEmmanuel Vadot 	    lm75_mode_sysctl, "A", "LM75 mode");
340*7c569caaSEmmanuel Vadot 	SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "polarity",
341*7c569caaSEmmanuel Vadot 	    CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_MPSAFE, dev, 0,
342*7c569caaSEmmanuel Vadot 	    lm75_pol_sysctl, "A", "LM75 OS polarity");
343*7c569caaSEmmanuel Vadot 	SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "shutdown",
344*7c569caaSEmmanuel Vadot 	    CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, dev, 0,
345*7c569caaSEmmanuel Vadot 	    lm75_shutdown_sysctl, "IU", "LM75 shutdown");
346*7c569caaSEmmanuel Vadot 	SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "resolution",
347*7c569caaSEmmanuel Vadot 	    CTLFLAG_RW | CTLTYPE_INT | CTLFLAG_MPSAFE, dev, 0,
348*7c569caaSEmmanuel Vadot 	    lm75_resolution_sysctl, "IU", "LM75 resolution");
349*7c569caaSEmmanuel Vadot }
350*7c569caaSEmmanuel Vadot 
351*7c569caaSEmmanuel Vadot static int
lm75_conf_read(struct lm75_softc * sc)352*7c569caaSEmmanuel Vadot lm75_conf_read(struct lm75_softc *sc)
353*7c569caaSEmmanuel Vadot {
354*7c569caaSEmmanuel Vadot 	uint8_t buf8;
355*7c569caaSEmmanuel Vadot 
356*7c569caaSEmmanuel Vadot 	if (lm75_read(sc->sc_dev, sc->sc_addr, LM75_CONF,
357*7c569caaSEmmanuel Vadot 	    &buf8, sizeof(buf8)) < 0)
358*7c569caaSEmmanuel Vadot 		return (-1);
359*7c569caaSEmmanuel Vadot 	sc->sc_conf = (uint32_t)buf8;
360*7c569caaSEmmanuel Vadot 
361*7c569caaSEmmanuel Vadot 	return (0);
362*7c569caaSEmmanuel Vadot }
363*7c569caaSEmmanuel Vadot 
364*7c569caaSEmmanuel Vadot static int
lm75_conf_write(struct lm75_softc * sc)365*7c569caaSEmmanuel Vadot lm75_conf_write(struct lm75_softc *sc)
366*7c569caaSEmmanuel Vadot {
367*7c569caaSEmmanuel Vadot 	uint8_t buf8[2];
368*7c569caaSEmmanuel Vadot 
369*7c569caaSEmmanuel Vadot 	buf8[0] = LM75_CONF;
370*7c569caaSEmmanuel Vadot 	buf8[1] = (uint8_t)sc->sc_conf & LM75_CONF_MASK;
371*7c569caaSEmmanuel Vadot 	if (lm75_write(sc->sc_dev, sc->sc_addr, buf8, sizeof(buf8)) < 0)
372*7c569caaSEmmanuel Vadot 		return (-1);
373*7c569caaSEmmanuel Vadot 
374*7c569caaSEmmanuel Vadot 	return (0);
375*7c569caaSEmmanuel Vadot }
376*7c569caaSEmmanuel Vadot 
377*7c569caaSEmmanuel Vadot static int
lm75_temp_read(struct lm75_softc * sc,uint8_t reg,int32_t * temp)378*7c569caaSEmmanuel Vadot lm75_temp_read(struct lm75_softc *sc, uint8_t reg, int32_t *temp)
379*7c569caaSEmmanuel Vadot {
380*7c569caaSEmmanuel Vadot 	int32_t buf;
381*7c569caaSEmmanuel Vadot 	uint8_t buf8[2];
382*7c569caaSEmmanuel Vadot 	uint8_t resolution = sc->sc_resolution;
383*7c569caaSEmmanuel Vadot 	uint16_t multiplier = sc->sc_multiplier;
384*7c569caaSEmmanuel Vadot 
385*7c569caaSEmmanuel Vadot 	if (lm75_read(sc->sc_dev, sc->sc_addr, reg, buf8, sizeof(buf8)) < 0)
386*7c569caaSEmmanuel Vadot 		return (-1);
387*7c569caaSEmmanuel Vadot 
388*7c569caaSEmmanuel Vadot 	buf = (int16_t)((buf8[0] << 8) | buf8[1]);
389*7c569caaSEmmanuel Vadot 	*temp = ((buf >> (16 - resolution)) * multiplier) >> (resolution - 8);
390*7c569caaSEmmanuel Vadot 
391*7c569caaSEmmanuel Vadot 	*temp += TZ_ZEROC * sc->sc_multiplier / TZ_ZEROC_DIVIDER;
392*7c569caaSEmmanuel Vadot 
393*7c569caaSEmmanuel Vadot 	return (0);
394*7c569caaSEmmanuel Vadot }
395*7c569caaSEmmanuel Vadot 
396*7c569caaSEmmanuel Vadot static int
lm75_temp_write(struct lm75_softc * sc,uint8_t reg,int32_t temp)397*7c569caaSEmmanuel Vadot lm75_temp_write(struct lm75_softc *sc, uint8_t reg, int32_t temp)
398*7c569caaSEmmanuel Vadot {
399*7c569caaSEmmanuel Vadot 	int32_t buf;
400*7c569caaSEmmanuel Vadot 	uint8_t buf8[3], resolution = sc->sc_resolution;
401*7c569caaSEmmanuel Vadot 	uint16_t multiplier = sc->sc_multiplier;
402*7c569caaSEmmanuel Vadot 
403*7c569caaSEmmanuel Vadot 	temp -= TZ_ZEROC * multiplier / TZ_ZEROC_DIVIDER;
404*7c569caaSEmmanuel Vadot 	if (temp > LM75_MAX_TEMP * multiplier)
405*7c569caaSEmmanuel Vadot 		temp = LM75_MAX_TEMP * multiplier;
406*7c569caaSEmmanuel Vadot 	if (temp < LM75_MIN_TEMP * multiplier)
407*7c569caaSEmmanuel Vadot 		temp = LM75_MIN_TEMP * multiplier;
408*7c569caaSEmmanuel Vadot 
409*7c569caaSEmmanuel Vadot 	buf = ((temp << (resolution - 8)) / multiplier) << (16 - resolution);
410*7c569caaSEmmanuel Vadot 
411*7c569caaSEmmanuel Vadot 	buf8[0] = reg;
412*7c569caaSEmmanuel Vadot 	buf8[1] = (buf >> 8) & 0xff;
413*7c569caaSEmmanuel Vadot 	buf8[2] = buf & 0xff;
414*7c569caaSEmmanuel Vadot 
415*7c569caaSEmmanuel Vadot 	if (lm75_write(sc->sc_dev, sc->sc_addr, buf8, sizeof(buf8)) < 0)
416*7c569caaSEmmanuel Vadot 		return (-1);
417*7c569caaSEmmanuel Vadot 
418*7c569caaSEmmanuel Vadot 	return (0);
419*7c569caaSEmmanuel Vadot }
420*7c569caaSEmmanuel Vadot 
421*7c569caaSEmmanuel Vadot static int
lm75_str_mode(char * buf)422*7c569caaSEmmanuel Vadot lm75_str_mode(char *buf)
423*7c569caaSEmmanuel Vadot {
424*7c569caaSEmmanuel Vadot 	int len, rtrn;
425*7c569caaSEmmanuel Vadot 
426*7c569caaSEmmanuel Vadot 	rtrn = -1;
427*7c569caaSEmmanuel Vadot 	len = strlen(buf);
428*7c569caaSEmmanuel Vadot 	if (len > 2 && strncasecmp("interrupt", buf, len) == 0)
429*7c569caaSEmmanuel Vadot 		rtrn = 1;
430*7c569caaSEmmanuel Vadot 	else if (len > 2 && strncasecmp("comparator", buf, len) == 0)
431*7c569caaSEmmanuel Vadot 		rtrn = 0;
432*7c569caaSEmmanuel Vadot 
433*7c569caaSEmmanuel Vadot 	return (rtrn);
434*7c569caaSEmmanuel Vadot }
435*7c569caaSEmmanuel Vadot 
436*7c569caaSEmmanuel Vadot static int
lm75_str_pol(char * buf)437*7c569caaSEmmanuel Vadot lm75_str_pol(char *buf)
438*7c569caaSEmmanuel Vadot {
439*7c569caaSEmmanuel Vadot 	int len, rtrn;
440*7c569caaSEmmanuel Vadot 
441*7c569caaSEmmanuel Vadot 	rtrn = -1;
442*7c569caaSEmmanuel Vadot 	len = strlen(buf);
443*7c569caaSEmmanuel Vadot 	if (len > 1 && strncasecmp("high", buf, len) == 0)
444*7c569caaSEmmanuel Vadot 		rtrn = 1;
445*7c569caaSEmmanuel Vadot 	else if (len > 1 && strncasecmp("low", buf, len) == 0)
446*7c569caaSEmmanuel Vadot 		rtrn = 0;
447*7c569caaSEmmanuel Vadot 	else if (len > 8 && strncasecmp("active-high", buf, len) == 0)
448*7c569caaSEmmanuel Vadot 		rtrn = 1;
449*7c569caaSEmmanuel Vadot 	else if (len > 8 && strncasecmp("active-low", buf, len) == 0)
450*7c569caaSEmmanuel Vadot 		rtrn = 0;
451*7c569caaSEmmanuel Vadot 
452*7c569caaSEmmanuel Vadot 	return (rtrn);
453*7c569caaSEmmanuel Vadot }
454*7c569caaSEmmanuel Vadot 
455*7c569caaSEmmanuel Vadot static int
lm75_temp_sysctl(SYSCTL_HANDLER_ARGS)456*7c569caaSEmmanuel Vadot lm75_temp_sysctl(SYSCTL_HANDLER_ARGS)
457*7c569caaSEmmanuel Vadot {
458*7c569caaSEmmanuel Vadot 	device_t dev;
459*7c569caaSEmmanuel Vadot 	int error;
460*7c569caaSEmmanuel Vadot 	int32_t temp;
461*7c569caaSEmmanuel Vadot 	struct lm75_softc *sc;
462*7c569caaSEmmanuel Vadot 	uint8_t reg;
463*7c569caaSEmmanuel Vadot 
464*7c569caaSEmmanuel Vadot 	dev = (device_t)arg1;
465*7c569caaSEmmanuel Vadot 	reg = (uint8_t)arg2;
466*7c569caaSEmmanuel Vadot 	sc = device_get_softc(dev);
467*7c569caaSEmmanuel Vadot 
468*7c569caaSEmmanuel Vadot 	if (lm75_temp_read(sc, reg, &temp) != 0)
469*7c569caaSEmmanuel Vadot 		return (EIO);
470*7c569caaSEmmanuel Vadot 
471*7c569caaSEmmanuel Vadot 	error = sysctl_handle_int(oidp, &temp, 0, req);
472*7c569caaSEmmanuel Vadot 	if (error != 0 || req->newptr == NULL)
473*7c569caaSEmmanuel Vadot 		return (error);
474*7c569caaSEmmanuel Vadot 
475*7c569caaSEmmanuel Vadot 	if (lm75_temp_write(sc, reg, temp) != 0)
476*7c569caaSEmmanuel Vadot 		return (EIO);
477*7c569caaSEmmanuel Vadot 
478*7c569caaSEmmanuel Vadot 	return (error);
479*7c569caaSEmmanuel Vadot }
480*7c569caaSEmmanuel Vadot 
481*7c569caaSEmmanuel Vadot static int
lm75_faults_sysctl(SYSCTL_HANDLER_ARGS)482*7c569caaSEmmanuel Vadot lm75_faults_sysctl(SYSCTL_HANDLER_ARGS)
483*7c569caaSEmmanuel Vadot {
484*7c569caaSEmmanuel Vadot 	device_t dev;
485*7c569caaSEmmanuel Vadot 	int lm75_faults[] = { 1, 2, 4, 6 };
486*7c569caaSEmmanuel Vadot 	int error, faults, i, newf, tmp;
487*7c569caaSEmmanuel Vadot 	struct lm75_softc *sc;
488*7c569caaSEmmanuel Vadot 
489*7c569caaSEmmanuel Vadot 	dev = (device_t)arg1;
490*7c569caaSEmmanuel Vadot 	sc = device_get_softc(dev);
491*7c569caaSEmmanuel Vadot 	tmp = (sc->sc_conf & LM75_CONF_FAULT) >> LM75_CONF_FSHIFT;
492*7c569caaSEmmanuel Vadot 	if (tmp >= nitems(lm75_faults))
493*7c569caaSEmmanuel Vadot 		tmp = nitems(lm75_faults) - 1;
494*7c569caaSEmmanuel Vadot 	faults = lm75_faults[tmp];
495*7c569caaSEmmanuel Vadot 
496*7c569caaSEmmanuel Vadot 	error = sysctl_handle_int(oidp, &faults, 0, req);
497*7c569caaSEmmanuel Vadot 	if (error != 0 || req->newptr == NULL)
498*7c569caaSEmmanuel Vadot 		return (error);
499*7c569caaSEmmanuel Vadot 
500*7c569caaSEmmanuel Vadot 	if (faults != lm75_faults[tmp]) {
501*7c569caaSEmmanuel Vadot 		newf = 0;
502*7c569caaSEmmanuel Vadot 		for (i = 0; i < nitems(lm75_faults); i++)
503*7c569caaSEmmanuel Vadot 			if (faults >= lm75_faults[i])
504*7c569caaSEmmanuel Vadot 				newf = i;
505*7c569caaSEmmanuel Vadot 		sc->sc_conf &= ~LM75_CONF_FAULT;
506*7c569caaSEmmanuel Vadot 		sc->sc_conf |= newf << LM75_CONF_FSHIFT;
507*7c569caaSEmmanuel Vadot 		if (lm75_conf_write(sc) != 0)
508*7c569caaSEmmanuel Vadot 			return (EIO);
509*7c569caaSEmmanuel Vadot 	}
510*7c569caaSEmmanuel Vadot 
511*7c569caaSEmmanuel Vadot 	return (error);
512*7c569caaSEmmanuel Vadot }
513*7c569caaSEmmanuel Vadot 
514*7c569caaSEmmanuel Vadot static int
lm75_mode_sysctl(SYSCTL_HANDLER_ARGS)515*7c569caaSEmmanuel Vadot lm75_mode_sysctl(SYSCTL_HANDLER_ARGS)
516*7c569caaSEmmanuel Vadot {
517*7c569caaSEmmanuel Vadot 	char buf[16];
518*7c569caaSEmmanuel Vadot 	device_t dev;
519*7c569caaSEmmanuel Vadot 	int error, mode, newm;
520*7c569caaSEmmanuel Vadot 	struct lm75_softc *sc;
521*7c569caaSEmmanuel Vadot 
522*7c569caaSEmmanuel Vadot 	dev = (device_t)arg1;
523*7c569caaSEmmanuel Vadot 	sc = device_get_softc(dev);
524*7c569caaSEmmanuel Vadot 	if (sc->sc_conf & LM75_CONF_MODE) {
525*7c569caaSEmmanuel Vadot 		mode = 1;
526*7c569caaSEmmanuel Vadot 		strlcpy(buf, "interrupt", sizeof(buf));
527*7c569caaSEmmanuel Vadot 	} else {
528*7c569caaSEmmanuel Vadot 		mode = 0;
529*7c569caaSEmmanuel Vadot 		strlcpy(buf, "comparator", sizeof(buf));
530*7c569caaSEmmanuel Vadot 	}
531*7c569caaSEmmanuel Vadot 
532*7c569caaSEmmanuel Vadot 	error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
533*7c569caaSEmmanuel Vadot 	if (error != 0 || req->newptr == NULL)
534*7c569caaSEmmanuel Vadot 		return (error);
535*7c569caaSEmmanuel Vadot 
536*7c569caaSEmmanuel Vadot 	newm = lm75_str_mode(buf);
537*7c569caaSEmmanuel Vadot 	if (newm != -1 && mode != newm) {
538*7c569caaSEmmanuel Vadot 		sc->sc_conf &= ~LM75_CONF_MODE;
539*7c569caaSEmmanuel Vadot 		if (newm == 1)
540*7c569caaSEmmanuel Vadot 			sc->sc_conf |= LM75_CONF_MODE;
541*7c569caaSEmmanuel Vadot 		if (lm75_conf_write(sc) != 0)
542*7c569caaSEmmanuel Vadot 			return (EIO);
543*7c569caaSEmmanuel Vadot 	}
544*7c569caaSEmmanuel Vadot 
545*7c569caaSEmmanuel Vadot 	return (error);
546*7c569caaSEmmanuel Vadot }
547*7c569caaSEmmanuel Vadot 
548*7c569caaSEmmanuel Vadot static int
lm75_pol_sysctl(SYSCTL_HANDLER_ARGS)549*7c569caaSEmmanuel Vadot lm75_pol_sysctl(SYSCTL_HANDLER_ARGS)
550*7c569caaSEmmanuel Vadot {
551*7c569caaSEmmanuel Vadot 	char buf[16];
552*7c569caaSEmmanuel Vadot 	device_t dev;
553*7c569caaSEmmanuel Vadot 	int error, newp, pol;
554*7c569caaSEmmanuel Vadot 	struct lm75_softc *sc;
555*7c569caaSEmmanuel Vadot 
556*7c569caaSEmmanuel Vadot 	dev = (device_t)arg1;
557*7c569caaSEmmanuel Vadot 	sc = device_get_softc(dev);
558*7c569caaSEmmanuel Vadot 	if (sc->sc_conf & LM75_CONF_POL) {
559*7c569caaSEmmanuel Vadot 		pol = 1;
560*7c569caaSEmmanuel Vadot 		strlcpy(buf, "active-high", sizeof(buf));
561*7c569caaSEmmanuel Vadot 	} else {
562*7c569caaSEmmanuel Vadot 		pol = 0;
563*7c569caaSEmmanuel Vadot 		strlcpy(buf, "active-low", sizeof(buf));
564*7c569caaSEmmanuel Vadot 	}
565*7c569caaSEmmanuel Vadot 
566*7c569caaSEmmanuel Vadot 	error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
567*7c569caaSEmmanuel Vadot 	if (error != 0 || req->newptr == NULL)
568*7c569caaSEmmanuel Vadot 		return (error);
569*7c569caaSEmmanuel Vadot 
570*7c569caaSEmmanuel Vadot 	newp = lm75_str_pol(buf);
571*7c569caaSEmmanuel Vadot 	if (newp != -1 && pol != newp) {
572*7c569caaSEmmanuel Vadot 		sc->sc_conf &= ~LM75_CONF_POL;
573*7c569caaSEmmanuel Vadot 		if (newp == 1)
574*7c569caaSEmmanuel Vadot 			sc->sc_conf |= LM75_CONF_POL;
575*7c569caaSEmmanuel Vadot 		if (lm75_conf_write(sc) != 0)
576*7c569caaSEmmanuel Vadot 			return (EIO);
577*7c569caaSEmmanuel Vadot 	}
578*7c569caaSEmmanuel Vadot 
579*7c569caaSEmmanuel Vadot 	return (error);
580*7c569caaSEmmanuel Vadot }
581*7c569caaSEmmanuel Vadot 
582*7c569caaSEmmanuel Vadot static int
lm75_shutdown_sysctl(SYSCTL_HANDLER_ARGS)583*7c569caaSEmmanuel Vadot lm75_shutdown_sysctl(SYSCTL_HANDLER_ARGS)
584*7c569caaSEmmanuel Vadot {
585*7c569caaSEmmanuel Vadot 	device_t dev;
586*7c569caaSEmmanuel Vadot 	int error, shutdown, tmp;
587*7c569caaSEmmanuel Vadot 	struct lm75_softc *sc;
588*7c569caaSEmmanuel Vadot 
589*7c569caaSEmmanuel Vadot 	dev = (device_t)arg1;
590*7c569caaSEmmanuel Vadot 	sc = device_get_softc(dev);
591*7c569caaSEmmanuel Vadot 	tmp = shutdown = (sc->sc_conf & LM75_CONF_SHUTD) ? 1 : 0;
592*7c569caaSEmmanuel Vadot 
593*7c569caaSEmmanuel Vadot 	error = sysctl_handle_int(oidp, &shutdown, 0, req);
594*7c569caaSEmmanuel Vadot 	if (error != 0 || req->newptr == NULL)
595*7c569caaSEmmanuel Vadot 		return (error);
596*7c569caaSEmmanuel Vadot 
597*7c569caaSEmmanuel Vadot 	if (shutdown != tmp) {
598*7c569caaSEmmanuel Vadot 		sc->sc_conf &= ~LM75_CONF_SHUTD;
599*7c569caaSEmmanuel Vadot 		if (shutdown)
600*7c569caaSEmmanuel Vadot 			sc->sc_conf |= LM75_CONF_SHUTD;
601*7c569caaSEmmanuel Vadot 		if (lm75_conf_write(sc) != 0)
602*7c569caaSEmmanuel Vadot 			return (EIO);
603*7c569caaSEmmanuel Vadot 	}
604*7c569caaSEmmanuel Vadot 
605*7c569caaSEmmanuel Vadot 	return (error);
606*7c569caaSEmmanuel Vadot }
607*7c569caaSEmmanuel Vadot 
608*7c569caaSEmmanuel Vadot static int
lm75_resolution_sysctl(SYSCTL_HANDLER_ARGS)609*7c569caaSEmmanuel Vadot lm75_resolution_sysctl(SYSCTL_HANDLER_ARGS)
610*7c569caaSEmmanuel Vadot {
611*7c569caaSEmmanuel Vadot 	device_t dev;
612*7c569caaSEmmanuel Vadot 	int error;
613*7c569caaSEmmanuel Vadot 	struct lm75_softc *sc;
614*7c569caaSEmmanuel Vadot 	int resolution;
615*7c569caaSEmmanuel Vadot 
616*7c569caaSEmmanuel Vadot 	dev = (device_t)arg1;
617*7c569caaSEmmanuel Vadot 	sc = device_get_softc(dev);
618*7c569caaSEmmanuel Vadot 	resolution = sc->sc_resolution;
619*7c569caaSEmmanuel Vadot 
620*7c569caaSEmmanuel Vadot 	error = sysctl_handle_int(oidp, &resolution, 0, req);
621*7c569caaSEmmanuel Vadot 	if (error != 0 || req->newptr == NULL)
622*7c569caaSEmmanuel Vadot 		return (error);
623*7c569caaSEmmanuel Vadot 
624*7c569caaSEmmanuel Vadot 	if (resolution > sc->sc_max_resolution || resolution < 9)
625*7c569caaSEmmanuel Vadot 		return (EINVAL);
626*7c569caaSEmmanuel Vadot 
627*7c569caaSEmmanuel Vadot 	sc->sc_resolution = (uint8_t) resolution;
628*7c569caaSEmmanuel Vadot 
629*7c569caaSEmmanuel Vadot 	return (0);
630*7c569caaSEmmanuel Vadot }
631