1 /*	$NetBSD: mcp980x.c,v 1.5 2013/10/28 11:24:08 rkujawa Exp $ */
2 
3 /*-
4  * Copyright (c) 2013 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Radoslaw Kujawa.
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 /*
33  * Microchip MCP9800/1/2/3 2-Wire High-Accuracy Temperature Sensor driver.
34  *
35  * TODO: better error checking, particurarly in user settable limits.
36  *
37  * Note: MCP9805 is different and is supported by the sdtemp(4) driver.
38  */
39 
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: mcp980x.c,v 1.5 2013/10/28 11:24:08 rkujawa Exp $");
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/device.h>
46 #include <sys/kernel.h>
47 #include <sys/mutex.h>
48 #include <sys/endian.h>
49 #include <sys/sysctl.h>
50 
51 #include <sys/bus.h>
52 #include <dev/i2c/i2cvar.h>
53 
54 #include <dev/sysmon/sysmonvar.h>
55 
56 #include <dev/i2c/mcp980xreg.h>
57 
58 struct mcp980x_softc {
59 	device_t		sc_dev;
60 
61 	i2c_tag_t		sc_tag;
62 	i2c_addr_t		sc_addr;
63 
64 	int			sc_res;
65 	int			sc_hyst;
66 	int			sc_limit;
67 
68 	/* envsys(4) stuff */
69 	struct sysmon_envsys	*sc_sme;
70 	envsys_data_t		sc_sensor;
71 	kmutex_t		sc_lock;
72 };
73 
74 
75 static int mcp980x_match(device_t, cfdata_t, void *);
76 static void mcp980x_attach(device_t, device_t, void *);
77 
78 static uint8_t mcp980x_reg_read_1(struct mcp980x_softc *, uint8_t);
79 static uint16_t mcp980x_reg_read_2(struct mcp980x_softc *, uint8_t);
80 static void mcp980x_reg_write_1(struct mcp980x_softc *, uint8_t, uint8_t);
81 
82 static uint8_t mcp980x_resolution_get(struct mcp980x_softc *);
83 static void mcp980x_resolution_set(struct mcp980x_softc *, uint8_t);
84 
85 static int8_t mcp980x_hysteresis_get(struct mcp980x_softc *);
86 static void mcp980x_hysteresis_set(struct mcp980x_softc *, int8_t);
87 static int8_t mcp980x_templimit_get(struct mcp980x_softc *);
88 static void mcp980x_templimit_set(struct mcp980x_softc *, int8_t);
89 
90 static int8_t mcp980x_s8b_get(struct mcp980x_softc *, uint8_t);
91 static void mcp980x_s8b_set(struct mcp980x_softc *, uint8_t, int8_t);
92 
93 static uint32_t mcp980x_temperature(struct mcp980x_softc *);
94 
95 static void mcp980x_envsys_register(struct mcp980x_softc *);
96 static void mcp980x_envsys_refresh(struct sysmon_envsys *, envsys_data_t *);
97 
98 static void mcp980x_setup_sysctl(struct mcp980x_softc *);
99 static int sysctl_mcp980x_res(SYSCTLFN_ARGS);
100 static int sysctl_mcp980x_hysteresis(SYSCTLFN_ARGS);
101 static int sysctl_mcp980x_templimit(SYSCTLFN_ARGS);
102 
103 CFATTACH_DECL_NEW(mcp980x, sizeof (struct mcp980x_softc),
104     mcp980x_match, mcp980x_attach, NULL, NULL);
105 
106 static int
mcp980x_match(device_t parent,cfdata_t cf,void * aux)107 mcp980x_match(device_t parent, cfdata_t cf, void *aux)
108 {
109 	/*
110 	 * No sane way to probe? Perhaps at least try to match constant part
111 	 * of the I2Caddress.
112 	 */
113 
114 	return 1;
115 }
116 
117 static void
mcp980x_attach(device_t parent,device_t self,void * aux)118 mcp980x_attach(device_t parent, device_t self, void *aux)
119 {
120 	struct mcp980x_softc *sc = device_private(self);
121 	struct i2c_attach_args *ia = aux;
122 
123 	sc->sc_dev = self;
124 	sc->sc_addr = ia->ia_addr;
125 	sc->sc_tag = ia->ia_tag;
126 
127 	aprint_normal(": Microchip MCP980x Temperature Sensor\n");
128 
129 	sc->sc_res = MCP980X_CONFIG_ADC_RES_12BIT;
130 	mcp980x_resolution_set(sc, sc->sc_res);
131 
132 	sc->sc_hyst = mcp980x_hysteresis_get(sc);
133 	sc->sc_limit = mcp980x_templimit_get(sc);
134 
135 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
136 
137 	mcp980x_setup_sysctl(sc);
138 	mcp980x_envsys_register(sc);
139 }
140 
141 static uint16_t
mcp980x_reg_read_2(struct mcp980x_softc * sc,uint8_t reg)142 mcp980x_reg_read_2(struct mcp980x_softc *sc, uint8_t reg)
143 {
144 	uint16_t rv;
145 
146 	if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL) != 0) {
147 		aprint_error_dev(sc->sc_dev, "cannot acquire bus for read\n");
148 		return 0;
149 	}
150 
151 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &reg,
152 	    1, &rv, 2, I2C_F_POLL)) {
153 		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
154 		iic_release_bus(sc->sc_tag, I2C_F_POLL);
155 		return 0;
156 	}
157 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
158 
159 	return be16toh(rv);
160 }
161 
162 static uint8_t
mcp980x_reg_read_1(struct mcp980x_softc * sc,uint8_t reg)163 mcp980x_reg_read_1(struct mcp980x_softc *sc, uint8_t reg)
164 {
165 	uint8_t rv;
166 
167 	if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL) != 0) {
168 		aprint_error_dev(sc->sc_dev, "cannot acquire bus for read\n");
169 		return 0;
170 	}
171 
172 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &reg,
173 	    1, &rv, 1, I2C_F_POLL)) {
174 		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
175 		iic_release_bus(sc->sc_tag, I2C_F_POLL);
176 		return 0;
177 	}
178 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
179 
180 	return rv;
181 }
182 
183 static void
mcp980x_reg_write_2(struct mcp980x_softc * sc,uint8_t reg,uint16_t val)184 mcp980x_reg_write_2(struct mcp980x_softc *sc, uint8_t reg, uint16_t val)
185 {
186 	uint16_t beval;
187 
188 	beval = htobe16(val);
189 
190         if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL) != 0) {
191 		aprint_error_dev(sc->sc_dev, "cannot acquire bus for write\n");
192 		return;
193 	}
194 
195         if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, &reg,
196 	    1, &beval, 2, I2C_F_POLL)) {
197 		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
198         }
199 
200 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
201 
202 }
203 
204 static void
mcp980x_reg_write_1(struct mcp980x_softc * sc,uint8_t reg,uint8_t val)205 mcp980x_reg_write_1(struct mcp980x_softc *sc, uint8_t reg, uint8_t val)
206 {
207         if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL) != 0) {
208 		aprint_error_dev(sc->sc_dev, "cannot acquire bus for write\n");
209 		return;
210 	}
211 
212         if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, &reg,
213 	    1, &val, 1, I2C_F_POLL)) {
214 		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
215         }
216 
217 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
218 
219 }
220 
221 static int8_t
mcp980x_templimit_get(struct mcp980x_softc * sc)222 mcp980x_templimit_get(struct mcp980x_softc *sc)
223 {
224 	return mcp980x_s8b_get(sc, MCP980X_TEMP_LIMIT);
225 }
226 
227 static void
mcp980x_templimit_set(struct mcp980x_softc * sc,int8_t val)228 mcp980x_templimit_set(struct mcp980x_softc *sc, int8_t val)
229 {
230 	mcp980x_s8b_set(sc, MCP980X_TEMP_LIMIT, val);
231 }
232 
233 static int8_t
mcp980x_hysteresis_get(struct mcp980x_softc * sc)234 mcp980x_hysteresis_get(struct mcp980x_softc *sc)
235 {
236 	return mcp980x_s8b_get(sc, MCP980X_TEMP_HYSTERESIS);
237 }
238 
239 static void
mcp980x_hysteresis_set(struct mcp980x_softc * sc,int8_t val)240 mcp980x_hysteresis_set(struct mcp980x_softc *sc, int8_t val)
241 {
242 	mcp980x_s8b_set(sc, MCP980X_TEMP_HYSTERESIS, val);
243 }
244 
245 static int8_t
mcp980x_s8b_get(struct mcp980x_softc * sc,uint8_t reg)246 mcp980x_s8b_get(struct mcp980x_softc *sc, uint8_t reg)
247 {
248 	return mcp980x_reg_read_2(sc, reg) >> MCP980X_TEMP_HYSTLIMIT_INT_SHIFT;
249 }
250 
251 static void
mcp980x_s8b_set(struct mcp980x_softc * sc,uint8_t reg,int8_t val)252 mcp980x_s8b_set(struct mcp980x_softc *sc, uint8_t reg, int8_t val)
253 {
254 	mcp980x_reg_write_2(sc, reg, val << MCP980X_TEMP_HYSTLIMIT_INT_SHIFT);
255 }
256 
257 static uint8_t
mcp980x_resolution_get(struct mcp980x_softc * sc)258 mcp980x_resolution_get(struct mcp980x_softc *sc)
259 {
260 	uint8_t cfg, res;
261 
262 	cfg = mcp980x_reg_read_1(sc, MCP980X_CONFIG);
263 	res = (cfg & MCP980X_CONFIG_ADC_RES) >>
264 	    MCP980X_CONFIG_ADC_RES_SHIFT;
265 
266 	return res;
267 }
268 
269 static void
mcp980x_resolution_set(struct mcp980x_softc * sc,uint8_t res)270 mcp980x_resolution_set(struct mcp980x_softc *sc, uint8_t res)
271 {
272 	uint8_t cfg;
273 
274 	/* read config register but discard resolution bits */
275 	cfg = mcp980x_reg_read_1(sc, MCP980X_CONFIG) & ~MCP980X_CONFIG_ADC_RES;
276 	/* set resolution bits to new value */
277 	cfg |= res << MCP980X_CONFIG_ADC_RES_SHIFT;
278 
279 	mcp980x_reg_write_1(sc, MCP980X_CONFIG, cfg);
280 }
281 
282 /* Get temperature in microKelvins. */
283 static uint32_t
mcp980x_temperature(struct mcp980x_softc * sc)284 mcp980x_temperature(struct mcp980x_softc *sc)
285 {
286 	uint16_t raw;
287 	uint32_t rv, uk, basedegc;
288 
289 	raw = mcp980x_reg_read_2(sc, MCP980X_AMBIENT_TEMP);
290 
291 	basedegc = (raw & MCP980X_AMBIENT_TEMP_DEGREES) >>
292 	    MCP980X_AMBIENT_TEMP_DEGREES_SHIFT;
293 
294 	uk = 1000000 * basedegc;
295 
296 	if (raw & MCP980X_AMBIENT_TEMP_05DEGREE)
297 		uk += 500000;
298 	if (raw & MCP980X_AMBIENT_TEMP_025DEGREE)
299 		uk += 250000;
300 	if (raw & MCP980X_AMBIENT_TEMP_0125DEGREE)
301 		uk += 125000;
302 	if (raw & MCP980X_AMBIENT_TEMP_00625DEGREE)
303 		uk += 62500;
304 
305 	if (raw & MCP980X_AMBIENT_TEMP_SIGN)
306 		rv = 273150000U - uk;
307 	else
308 		rv = 273150000U + uk;
309 
310 	return rv;
311 }
312 
313 static void
mcp980x_envsys_register(struct mcp980x_softc * sc)314 mcp980x_envsys_register(struct mcp980x_softc *sc)
315 {
316 	sc->sc_sme = sysmon_envsys_create();
317 
318 	strlcpy(sc->sc_sensor.desc, "Ambient temp",
319 	    sizeof(sc->sc_sensor.desc));
320 	sc->sc_sensor.units = ENVSYS_STEMP;
321 	sc->sc_sensor.state = ENVSYS_SINVALID;
322 
323 	if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) {
324 		aprint_error_dev(sc->sc_dev,
325 		    "error attaching sensor\n");
326 		return;
327 	}
328 
329 	sc->sc_sme->sme_name = device_xname(sc->sc_dev);
330 	sc->sc_sme->sme_cookie = sc;
331 	sc->sc_sme->sme_refresh = mcp980x_envsys_refresh;
332 
333 	if (sysmon_envsys_register(sc->sc_sme)) {
334 		aprint_error_dev(sc->sc_dev, "unable to register in sysmon\n");
335 		sysmon_envsys_destroy(sc->sc_sme);
336 	}
337 }
338 
339 static void
mcp980x_envsys_refresh(struct sysmon_envsys * sme,envsys_data_t * edata)340 mcp980x_envsys_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
341 {
342 	struct mcp980x_softc *sc = sme->sme_cookie;
343 
344 	mutex_enter(&sc->sc_lock);
345 
346 	edata->value_cur = mcp980x_temperature(sc);
347 	edata->state = ENVSYS_SVALID;
348 
349 	mutex_exit(&sc->sc_lock);
350 }
351 
352 static void
mcp980x_setup_sysctl(struct mcp980x_softc * sc)353 mcp980x_setup_sysctl(struct mcp980x_softc *sc)
354 {
355 	const struct sysctlnode *me = NULL, *node = NULL;
356 
357 	sysctl_createv(NULL, 0, NULL, &me,
358 	    CTLFLAG_READWRITE,
359 	    CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
360 	    NULL, 0, NULL, 0,
361 	    CTL_MACHDEP, CTL_CREATE, CTL_EOL);
362 
363 	sysctl_createv(NULL, 0, NULL, &node,
364 	    CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
365 	    CTLTYPE_INT, "res", "Resolution",
366 	    sysctl_mcp980x_res, 1, (void *)sc, 0,
367 	    CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
368 
369 	sysctl_createv(NULL, 0, NULL, &node,
370 	    CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
371 	    CTLTYPE_INT, "hysteresis", "Temperature hysteresis",
372 	    sysctl_mcp980x_hysteresis, 1, (void *)sc, 0,
373 	    CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
374 
375 	sysctl_createv(NULL, 0, NULL, &node,
376 	    CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
377 	    CTLTYPE_INT, "templimit", "Temperature limit",
378 	    sysctl_mcp980x_templimit, 1, (void *)sc, 0,
379 	    CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
380 }
381 
382 
383 SYSCTL_SETUP(sysctl_mcp980x_setup, "sysctl mcp980x subtree setup")
384 {
385 	sysctl_createv(NULL, 0, NULL, NULL, CTLFLAG_PERMANENT,
386 	    CTLTYPE_NODE, "machdep", NULL, NULL, 0, NULL, 0,
387 	    CTL_MACHDEP, CTL_EOL);
388 }
389 
390 
391 static int
sysctl_mcp980x_res(SYSCTLFN_ARGS)392 sysctl_mcp980x_res(SYSCTLFN_ARGS)
393 {
394 	struct sysctlnode node = *rnode;
395 	struct mcp980x_softc *sc = node.sysctl_data;
396 	int newres, err;
397 
398 	node.sysctl_data = &sc->sc_res;
399 	if ((err = (sysctl_lookup(SYSCTLFN_CALL(&node)))) != 0)
400 		return err;
401 
402 	if (newp) {
403 		newres = *(int *)node.sysctl_data;
404 		if (newres > MCP980X_CONFIG_ADC_RES_12BIT)
405 			return EINVAL;
406 		sc->sc_res = (uint8_t) newres;
407 		mcp980x_resolution_set(sc, sc->sc_res);
408 		return 0;
409 	} else {
410 		sc->sc_res = mcp980x_resolution_get(sc);
411 		node.sysctl_size = 4;
412 	}
413 
414 	return err;
415 }
416 
417 static int
sysctl_mcp980x_hysteresis(SYSCTLFN_ARGS)418 sysctl_mcp980x_hysteresis(SYSCTLFN_ARGS)
419 {
420 	struct sysctlnode node = *rnode;
421 	struct mcp980x_softc *sc = node.sysctl_data;
422 	int newhyst, err;
423 
424 	node.sysctl_data = &sc->sc_hyst;
425 	if ((err = (sysctl_lookup(SYSCTLFN_CALL(&node)))) != 0)
426 		return err;
427 
428 	if (newp) {
429 		newhyst = *(int *)node.sysctl_data;
430 		sc->sc_hyst = newhyst;
431 		mcp980x_hysteresis_set(sc, sc->sc_hyst);
432 		return 0;
433 	} else {
434 		sc->sc_hyst = mcp980x_hysteresis_get(sc);
435 		node.sysctl_size = 4;
436 	}
437 
438 	return err;
439 }
440 
441 static int
sysctl_mcp980x_templimit(SYSCTLFN_ARGS)442 sysctl_mcp980x_templimit(SYSCTLFN_ARGS)
443 {
444 	struct sysctlnode node = *rnode;
445 	struct mcp980x_softc *sc = node.sysctl_data;
446 	int newlimit, err;
447 
448 	node.sysctl_data = &sc->sc_limit;
449 	if ((err = (sysctl_lookup(SYSCTLFN_CALL(&node)))) != 0)
450 		return err;
451 
452 	if (newp) {
453 		newlimit = *(int *)node.sysctl_data;
454 		sc->sc_limit = newlimit;
455 		mcp980x_templimit_set(sc, sc->sc_limit);
456 		return 0;
457 	} else {
458 		sc->sc_limit = mcp980x_templimit_get(sc);
459 		node.sysctl_size = 4;
460 	}
461 
462 	return err;
463 }
464 
465