Module Name:    src
Committed By:   rkujawa
Date:           Mon May  6 22:04:12 UTC 2013

Modified Files:
        src/sys/dev/i2c: files.i2c
Added Files:
        src/sys/dev/i2c: mcp980x.c mcp980xreg.h

Log Message:
Add driver for Microchip MCP9800/1/2/3 temperature sensors.


To generate a diff of this commit:
cvs rdiff -u -r1.48 -r1.49 src/sys/dev/i2c/files.i2c
cvs rdiff -u -r0 -r1.1 src/sys/dev/i2c/mcp980x.c src/sys/dev/i2c/mcp980xreg.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/i2c/files.i2c
diff -u src/sys/dev/i2c/files.i2c:1.48 src/sys/dev/i2c/files.i2c:1.49
--- src/sys/dev/i2c/files.i2c:1.48	Thu Apr 25 20:55:34 2013
+++ src/sys/dev/i2c/files.i2c	Mon May  6 22:04:12 2013
@@ -1,4 +1,4 @@
-#	$NetBSD: files.i2c,v 1.48 2013/04/25 20:55:34 rkujawa Exp $
+#	$NetBSD: files.i2c,v 1.49 2013/05/06 22:04:12 rkujawa Exp $
 
 obsolete defflag	opt_i2cbus.h		I2C_SCAN
 define	i2cbus { }
@@ -182,3 +182,8 @@ device	tps65217pmic: sysmon_envsys
 attach	tps65217pmic at iic
 file	dev/i2c/tps65217pmic.c 		tps65217pmic
 
+# Microchip MCP980x
+device	mcp980x: sysmon_envsys
+attach	mcp980x at iic
+file	dev/i2c/mcp980x.c 		mcp980x
+

Added files:

Index: src/sys/dev/i2c/mcp980x.c
diff -u /dev/null src/sys/dev/i2c/mcp980x.c:1.1
--- /dev/null	Mon May  6 22:04:12 2013
+++ src/sys/dev/i2c/mcp980x.c	Mon May  6 22:04:12 2013
@@ -0,0 +1,228 @@
+/*	$NetBSD: mcp980x.c,v 1.1 2013/05/06 22:04:12 rkujawa Exp $ */
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Radoslaw Kujawa.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Microchip MCP9800/1/2/3 2-Wire High-Accuracy Temperature Sensor driver.
+ * TODO: everything besides simple temperature read with default configuration.
+ *
+ * Note: MCP9805 is different and is supported by the sdtemp(4) driver.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: mcp980x.c,v 1.1 2013/05/06 22:04:12 rkujawa Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/mutex.h>
+#include <sys/endian.h>
+
+#include <sys/bus.h>
+#include <dev/i2c/i2cvar.h>
+
+#include <dev/sysmon/sysmonvar.h>
+
+#include <dev/i2c/mcp980xreg.h>
+
+struct mcp980x_softc {
+	device_t		sc_dev;
+
+	i2c_tag_t		sc_tag;
+	i2c_addr_t		sc_addr;
+
+	/* envsys(4) stuff */
+	struct sysmon_envsys	*sc_sme;
+	envsys_data_t		sc_sensor;
+	kmutex_t		sc_lock; 
+};
+
+
+static int mcp980x_match(device_t, cfdata_t, void *);
+static void mcp980x_attach(device_t, device_t, void *);
+
+/*static uint8_t mcp980x_reg_read_1(struct mcp980x_softc *sc, uint8_t);*/
+static uint16_t mcp980x_reg_read_2(struct mcp980x_softc *sc, uint8_t reg);
+
+static uint32_t mcp980x_temperature(struct mcp980x_softc *sc);
+
+static void mcp980x_envsys_register(struct mcp980x_softc *);
+static void mcp980x_envsys_refresh(struct sysmon_envsys *, envsys_data_t *);
+
+CFATTACH_DECL_NEW(mcp980x, sizeof (struct mcp980x_softc),
+    mcp980x_match, mcp980x_attach, NULL, NULL);
+
+static int
+mcp980x_match(device_t parent, cfdata_t cf, void *aux)
+{
+	/*
+	 * No sane way to probe? Perhaps at least try to match constant part
+	 * of the I2Caddress.
+	 */
+
+	return 1;
+}
+
+static void
+mcp980x_attach(device_t parent, device_t self, void *aux)
+{
+	struct mcp980x_softc *sc = device_private(self);
+	struct i2c_attach_args *ia = aux;
+
+	sc->sc_dev = self;
+	sc->sc_addr = ia->ia_addr;
+	sc->sc_tag = ia->ia_tag;
+
+	aprint_normal(": Microchip MCP980x Temperature Sensor\n");
+
+	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+
+	mcp980x_envsys_register(sc);
+}
+
+static uint16_t
+mcp980x_reg_read_2(struct mcp980x_softc *sc, uint8_t reg)
+{
+	uint8_t wbuf[2];
+	uint16_t rv;
+
+	if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL) != 0) {
+		aprint_error_dev(sc->sc_dev, "cannot acquire bus for read\n");
+		return 0;
+	}
+
+	wbuf[0] = reg;
+
+	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, wbuf,
+	    1, &rv, 2, I2C_F_POLL)) {
+		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
+		iic_release_bus(sc->sc_tag, I2C_F_POLL);
+		return 0;
+	}
+	iic_release_bus(sc->sc_tag, I2C_F_POLL);
+
+	return be16toh(rv);
+}
+
+/* Will need that later for reading config register. */ 
+/*
+static uint8_t
+mcp980x_reg_read_1(struct mcp980x_softc *sc, uint8_t reg)
+{
+	uint8_t rv, wbuf[2];
+
+	if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL) != 0) {
+		aprint_error_dev(sc->sc_dev, "cannot acquire bus for read\n");
+		return 0;
+	}
+
+	wbuf[0] = reg;
+
+	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, wbuf,
+	    1, &rv, 1, I2C_F_POLL)) {
+		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
+		iic_release_bus(sc->sc_tag, I2C_F_POLL);
+		return 0;
+	}
+	iic_release_bus(sc->sc_tag, I2C_F_POLL);
+
+	return rv;
+}*/
+
+/* Get temperature in microKelvins. */
+static uint32_t
+mcp980x_temperature(struct mcp980x_softc *sc)
+{
+	uint16_t raw;
+	uint32_t rv, uk, basedegc;
+
+	raw = mcp980x_reg_read_2(sc, MCP980X_AMBIENT_TEMP);
+
+	basedegc = (raw & MCP980X_AMBIENT_TEMP_DEGREES) >> 
+	    MCP980X_AMBIENT_TEMP_DEGREES_SHIFT;
+
+	uk = 1000000 * basedegc;
+
+	if (raw & MCP980X_AMBIENT_TEMP_05DEGREE)
+		uk += 500000;
+	if (raw & MCP980X_AMBIENT_TEMP_025DEGREE)
+		uk += 250000;
+	if (raw & MCP980X_AMBIENT_TEMP_0125DEGREE)
+		uk += 125000;
+	if (raw & MCP980X_AMBIENT_TEMP_00625DEGREE)
+		uk += 62500;
+
+	if (raw & MCP980X_AMBIENT_TEMP_SIGN)
+		rv = 273150000U - uk;
+	else
+		rv = 273150000U + uk;
+
+	return rv;	
+}
+
+static void
+mcp980x_envsys_register(struct mcp980x_softc *sc)
+{
+	sc->sc_sme = sysmon_envsys_create();
+
+	strlcpy(sc->sc_sensor.desc, "Ambient temp",
+	    sizeof(sc->sc_sensor.desc));
+	sc->sc_sensor.units = ENVSYS_STEMP;
+	sc->sc_sensor.state = ENVSYS_SINVALID;
+
+	if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) {
+		aprint_error_dev(sc->sc_dev,
+		    "error attaching sensor\n");
+		return;
+	}
+
+	sc->sc_sme->sme_name = device_xname(sc->sc_dev);
+	sc->sc_sme->sme_cookie = sc;
+	sc->sc_sme->sme_refresh = mcp980x_envsys_refresh;
+
+	if (sysmon_envsys_register(sc->sc_sme)) {
+		aprint_error_dev(sc->sc_dev, "unable to register in sysmon\n");
+		sysmon_envsys_destroy(sc->sc_sme);
+	}
+}
+
+static void
+mcp980x_envsys_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
+{
+	struct mcp980x_softc *sc = sme->sme_cookie;
+
+	mutex_enter(&sc->sc_lock);
+
+	edata->value_cur = mcp980x_temperature(sc);
+	edata->state = ENVSYS_SVALID;
+
+	mutex_exit(&sc->sc_lock);
+}
Index: src/sys/dev/i2c/mcp980xreg.h
diff -u /dev/null src/sys/dev/i2c/mcp980xreg.h:1.1
--- /dev/null	Mon May  6 22:04:12 2013
+++ src/sys/dev/i2c/mcp980xreg.h	Mon May  6 22:04:12 2013
@@ -0,0 +1,57 @@
+/*	$NetBSD: mcp980xreg.h,v 1.1 2013/05/06 22:04:12 rkujawa Exp $ */
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Radoslaw Kujawa.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MCP980XREG_H_
+#define _MCP980XREG_H_
+
+#define MCP980X_ADDR_CONST		0x48 /* 1001___ */
+#define MCP980X_ADDR_VAR		0x7  /*     XXX */
+
+#define MCP980X_AMBIENT_TEMP		0x0
+
+#define MCP980X_AMBIENT_TEMP_00625DEGREE	__BIT(4)
+#define MCP980X_AMBIENT_TEMP_0125DEGREE		__BIT(5)
+#define MCP980X_AMBIENT_TEMP_025DEGREE		__BIT(6)
+#define MCP980X_AMBIENT_TEMP_05DEGREE		__BIT(7)
+#define MCP980X_AMBIENT_TEMP_DEGREES		__BITS(8,14)
+#define MCP980X_AMBIENT_TEMP_DEGREES_SHIFT	8
+#define MCP980X_AMBIENT_TEMP_SIGN		__BIT(15)
+
+#define MCP980X_CONFIG			0x1
+
+#define MCP980X_CONFIG_ADC_RES			__BITS(5,6)
+#define MCP980X_CONFIG_ADC_RES_SHIFT		5
+#define MCP980X_CONFIG_ADC_RES_9BIT		0	
+#define MCP980X_CONFIG_ADC_RES_10BIT		1	
+#define MCP980X_CONFIG_ADC_RES_11BIT		2	
+#define MCP980X_CONFIG_ADC_RES_12BIT		3
+
+#endif /* _MCP980XREG_H_ */

Reply via email to