Module Name:    src
Committed By:   phx
Date:           Tue Aug 18 15:54:20 UTC 2015

Modified Files:
        src/distrib/sets/lists/man: mi
        src/doc: CHANGES
        src/share/man/man4: Makefile
        src/sys/arch/evbarm/conf: RPI
        src/sys/dev/spi: files.spi
Added Files:
        src/share/man/man4: mcp3kadc.4
        src/sys/dev/spi: mcp3k.c

Log Message:
MI driver for the Microchip 3x0x series of SAR analog to digital converters.


To generate a diff of this commit:
cvs rdiff -u -r1.1504 -r1.1505 src/distrib/sets/lists/man/mi
cvs rdiff -u -r1.2094 -r1.2095 src/doc/CHANGES
cvs rdiff -u -r1.620 -r1.621 src/share/man/man4/Makefile
cvs rdiff -u -r0 -r1.1 src/share/man/man4/mcp3kadc.4
cvs rdiff -u -r1.63 -r1.64 src/sys/arch/evbarm/conf/RPI
cvs rdiff -u -r1.4 -r1.5 src/sys/dev/spi/files.spi
cvs rdiff -u -r0 -r1.1 src/sys/dev/spi/mcp3k.c

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

Modified files:

Index: src/distrib/sets/lists/man/mi
diff -u src/distrib/sets/lists/man/mi:1.1504 src/distrib/sets/lists/man/mi:1.1505
--- src/distrib/sets/lists/man/mi:1.1504	Mon Aug 17 06:50:03 2015
+++ src/distrib/sets/lists/man/mi	Tue Aug 18 15:54:20 2015
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.1504 2015/08/17 06:50:03 knakahara Exp $
+# $NetBSD: mi,v 1.1505 2015/08/18 15:54:20 phx Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -1391,6 +1391,7 @@
 ./usr/share/man/cat4/mcclock.0			man-sys-catman		.cat
 ./usr/share/man/cat4/mcd.0			man-sys-catman		.cat
 ./usr/share/man/cat4/mcp23s17gpio.0		man-sys-catman		.cat
+./usr/share/man/cat4/mcp3kadc.0			man-sys-catman		.cat
 ./usr/share/man/cat4/mcp980x.0			man-sys-catman		.cat
 ./usr/share/man/cat4/md.0			man-sys-catman		.cat
 ./usr/share/man/cat4/mfb.0			man-sys-catman		.cat
@@ -4415,6 +4416,7 @@
 ./usr/share/man/html4/mcclock.html		man-sys-htmlman		html
 ./usr/share/man/html4/mcd.html			man-sys-htmlman		html
 ./usr/share/man/html4/mcp23s17gpio.html		man-sys-htmlman		html
+./usr/share/man/html4/mcp3kadc.html		man-sys-htmlman		html
 ./usr/share/man/html4/mcp980x.html		man-sys-htmlman		html
 ./usr/share/man/html4/md.html			man-sys-htmlman		html
 ./usr/share/man/html4/mfb.html			man-sys-htmlman		html
@@ -7289,6 +7291,7 @@
 ./usr/share/man/man4/mcclock.4			man-sys-man		.man
 ./usr/share/man/man4/mcd.4			man-sys-man		.man
 ./usr/share/man/man4/mcp23s17gpio.4		man-sys-man		.man
+./usr/share/man/man4/mcp3kadc.4			man-sys-man		.man
 ./usr/share/man/man4/mcp980x.4			man-sys-man		.man
 ./usr/share/man/man4/md.4			man-sys-man		.man
 ./usr/share/man/man4/mfb.4			man-sys-man		.man

Index: src/doc/CHANGES
diff -u src/doc/CHANGES:1.2094 src/doc/CHANGES:1.2095
--- src/doc/CHANGES:1.2094	Tue Aug 18 10:48:01 2015
+++ src/doc/CHANGES	Tue Aug 18 15:54:20 2015
@@ -1,4 +1,4 @@
-# LIST OF CHANGES FROM LAST RELEASE:			<$Revision: 1.2094 $>
+# LIST OF CHANGES FROM LAST RELEASE:			<$Revision: 1.2095 $>
 #
 #
 # [Note: This file does not mention every change made to the NetBSD source tree.
@@ -187,3 +187,4 @@ Changes from NetBSD 7.0 to NetBSD 8.0:
 	libc: Update to tzcode2015f. [christos 20150813]
 	gdb(1): Updated to 7.9.1.  [christos 20150818]
 	acpi(4): Updated ACPICA to 20150717. [christos 20150818]
+	mcp3kadc(4): Driver for Microchip 3x0x SAR ADC chips. [phx 20150818]

Index: src/share/man/man4/Makefile
diff -u src/share/man/man4/Makefile:1.620 src/share/man/man4/Makefile:1.621
--- src/share/man/man4/Makefile:1.620	Wed May 13 07:28:49 2015
+++ src/share/man/man4/Makefile	Tue Aug 18 15:54:20 2015
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.620 2015/05/13 07:28:49 mlelstv Exp $
+#	$NetBSD: Makefile,v 1.621 2015/08/18 15:54:20 phx Exp $
 #	@(#)Makefile	8.1 (Berkeley) 6/18/93
 
 MAN=	aac.4 ac97.4 acardide.4 aceride.4 acphy.4 \
@@ -127,7 +127,7 @@ MAN+=	dbcool.4 g760a.4 lmenv.4 lmtemp.4 
 	smscmon.4 spdmem.4 tps65217pmic.4
 
 # machine-independent SPI devices
-MAN +=	m25p.4 mcp23s17gpio.4 tm121temp.4
+MAN +=	m25p.4 mcp23s17gpio.4 mcp3kadc.4 tm121temp.4
 
 # machine-independent SD/MMC devices
 MAN +=	sbt.4 sdhc.4 sdmmc.4

Index: src/sys/arch/evbarm/conf/RPI
diff -u src/sys/arch/evbarm/conf/RPI:1.63 src/sys/arch/evbarm/conf/RPI:1.64
--- src/sys/arch/evbarm/conf/RPI:1.63	Sat Apr 18 13:43:45 2015
+++ src/sys/arch/evbarm/conf/RPI	Tue Aug 18 15:54:20 2015
@@ -1,5 +1,5 @@
 #
-#	$NetBSD: RPI,v 1.63 2015/04/18 13:43:45 skrll Exp $
+#	$NetBSD: RPI,v 1.64 2015/08/18 15:54:20 phx Exp $
 #
 #	RPi -- Raspberry Pi
 #
@@ -144,6 +144,10 @@ iic* at i2cbus?
 bcmspi* at obio?
 spi* at spibus?
 
+# MCP3x0x ADC
+# flags selects the actual chip, refer to mcp3kadc(4)
+#mcp3kadc0 at spi? slave 0 flags 0
+
 # PIFace or other boards using that chip (needs gpio)
 #mcp23s17gpio0 at spi? slave 0 flags 0
 #mcp23s17gpio1 at spi? slave 0 flags 1

Index: src/sys/dev/spi/files.spi
diff -u src/sys/dev/spi/files.spi:1.4 src/sys/dev/spi/files.spi:1.5
--- src/sys/dev/spi/files.spi:1.4	Sun Apr  6 17:59:39 2014
+++ src/sys/dev/spi/files.spi	Tue Aug 18 15:54:20 2015
@@ -1,4 +1,4 @@
-#	$NetBSD: files.spi,v 1.4 2014/04/06 17:59:39 kardel Exp $
+#	$NetBSD: files.spi,v 1.5 2015/08/18 15:54:20 phx Exp $
 
 define	spibus { }
 
@@ -35,3 +35,8 @@ file	dev/spi/mcp48x1.c		mcp48x1dac	
 device	mcp23s17gpio: gpiobus
 attach	mcp23s17gpio at spi
 file	dev/spi/mcp23s17.c		mcp23s17gpio
+
+# MCP3x0x ADC
+device	mcp3kadc: sysmon_envsys
+attach	mcp3kadc at spi
+file	dev/spi/mcp3k.c			mcp3kadc

Added files:

Index: src/share/man/man4/mcp3kadc.4
diff -u /dev/null src/share/man/man4/mcp3kadc.4:1.1
--- /dev/null	Tue Aug 18 15:54:20 2015
+++ src/share/man/man4/mcp3kadc.4	Tue Aug 18 15:54:20 2015
@@ -0,0 +1,94 @@
+.\" $NetBSD: mcp3kadc.4,v 1.1 2015/08/18 15:54:20 phx Exp $
+.\"
+.\" Copyright (c) 2015 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Frank Wille.
+.\"
+.\" 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.
+.\"
+.Dd August 18, 2015
+.Dt MCP3KADC 4
+.Os
+.Sh NAME
+.Nm mcp3kadc
+.Nd Microchip 3x0x SAR analog to digital converter
+.Sh SYNOPSIS
+.Cd "mcp3kadc* at spi? slave ? flags N"
+.Sh DESCRIPTION
+The
+.Nm
+driver reports the current voltage on the chip's ADC channels through the
+.Xr envsys 4
+API. The driver calculates these values according to the currently selected
+reference voltage (
+.Li Vref
+). It can be changed
+through the
+.Xr sysctl 8
+node
+.Li hw.mcp3kadc0.vref .
+.Pp
+The following table shows the supported chips. The type of the chip can
+be selected with the
+.Ar flags
+argument in the config file.
+.Bl -column "Designation" "Resolution" "Input Channels" "flags" -offset indent
+.It Sy "Designation" Ta Sy "Resolution" Ta Sy "Input Channels" Ta Sy "flags"
+.It Li "MCP3001" Ta "10 bits" Ta "1" Ta "0"
+.It Li "MCP3002" Ta "10 bits" Ta "2" Ta "1"
+.It Li "MCP3004" Ta "10 bits" Ta "4" Ta "2"
+.It Li "MCP3008" Ta "10 bits" Ta "8" Ta "3"
+.It Li "MCP3201" Ta "12 bits" Ta "1" Ta "4"
+.It Li "MCP3202" Ta "12 bits" Ta "2" Ta "5"
+.It Li "MCP3204" Ta "12 bits" Ta "4" Ta "6"
+.It Li "MCP3208" Ta "12 bits" Ta "8" Ta "7"
+.It Li "MCP3301" Ta "13 bits" Ta "1" Ta "8"
+.It Li "MCP3302" Ta "13 bits" Ta "4" Ta "9"
+.It Li "MCP3304" Ta "13 bits" Ta "8" Ta "10"
+.El
+.Sh SYSCTL VARIABLES
+The following
+.Xr sysctl 3
+variables are provided:
+.Bl -tag -width indent
+.It hw.mcp3kadc0.vref
+Defines the reference voltage on the chip's
+.Li Vref
+pin in millivolts (mV). It defaults to the ADC's maximum output value + 1
+in millivolts (e.g., 4096 for a 12-bit ADC).
+.El
+.Sh SEE ALSO
+.Xr spi 4 ,
+.Xr envsys 4 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Nx 8.0 .
+.Sh AUTHORS
+The
+.Nm
+driver was written by
+.An Frank Wille .

Index: src/sys/dev/spi/mcp3k.c
diff -u /dev/null src/sys/dev/spi/mcp3k.c:1.1
--- /dev/null	Tue Aug 18 15:54:20 2015
+++ src/sys/dev/spi/mcp3k.c	Tue Aug 18 15:54:20 2015
@@ -0,0 +1,368 @@
+/*	$NetBSD: mcp3k.c,v 1.1 2015/08/18 15:54:20 phx Exp $ */
+
+/*-
+ * Copyright (c) 2015 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Frank Wille.
+ *
+ * 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 MCP3x0x SAR analog to digital converters.
+ * The driver supports various ADCs with different resolutions, operation
+ * modes and number of input channels.
+ * The reference voltage Vref defaults to the maximum output value in mV,
+ * but can be changed via sysctl(3).
+ *
+ * MCP3001: http://ww1.microchip.com/downloads/en/DeviceDoc/21293C.pdf
+ * MCP3002: http://ww1.microchip.com/downloads/en/DeviceDoc/21294E.pdf
+ * MCP3004/3008: http://ww1.microchip.com/downloads/en/DeviceDoc/21295C.pdf
+ * MCP3201: http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf
+ * MCP3204/3208: http://ww1.microchip.com/downloads/en/DeviceDoc/21298c.pdf
+ * MCP3301: http://ww1.microchip.com/downloads/en/DeviceDoc/21700E.pdf
+ * MPC3302/3304: http://ww1.microchip.com/downloads/en/DeviceDoc/21697F.pdf
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/types.h> 
+#include <sys/sysctl.h>
+
+#include <dev/sysmon/sysmonvar.h>
+#include <dev/spi/spivar.h>
+
+#define M3K_MAX_SENSORS		16		/* 8 single-ended & 8 diff. */
+
+/* mcp3x0x model description */
+struct mcp3kadc_model {
+	uint32_t		name;
+	uint8_t			bits;
+	uint8_t			channels;
+	uint8_t			lead;		/* leading bits to ignore */
+	uint8_t			flags;
+#define M3K_SGLDIFF		0x01		/* single-ended/differential */
+#define M3K_D2D1D0		0x02		/* 3 channel select bits */
+#define M3K_MSBF		0x04		/* MSBF select bit */
+#define M3K_SIGNED		0x80		/* result is signed */
+#define M3K_CTRL_NEEDED		(M3K_SGLDIFF | M3K_D2D1D0 | M3K_MSBF)
+};
+
+struct mcp3kadc_softc {
+	device_t		sc_dev;
+	struct spi_handle 	*sc_sh;
+	int			sc_model;
+	uint32_t		sc_adc_max;
+	int32_t			sc_vref_mv;
+
+	struct sysmon_envsys 	*sc_sme;
+	envsys_data_t 		sc_sensors[M3K_MAX_SENSORS];
+};
+
+static int	mcp3kadc_match(device_t, cfdata_t, void *);
+static void	mcp3kadc_attach(device_t, device_t, void *);
+static void	mcp3kadc_envsys_refresh(struct sysmon_envsys *,
+		    envsys_data_t *);
+static int	sysctl_mcp3kadc_vref(SYSCTLFN_ARGS);
+
+CFATTACH_DECL_NEW(mcp3kadc, sizeof(struct mcp3kadc_softc),
+    mcp3kadc_match,  mcp3kadc_attach, NULL, NULL);
+
+static struct mcp3kadc_model mcp3k_models[] = {
+	{
+		.name = 3001,
+		.bits = 10,
+		.channels = 1,
+		.lead = 3,
+		.flags = 0
+	},
+	{
+		.name = 3002,
+		.bits = 10,
+		.channels = 2,
+		.lead = 2,
+		.flags = M3K_SGLDIFF | M3K_MSBF
+	},
+	{
+		.name = 3004,
+		.bits = 10,
+		.channels = 4,
+		.lead = 2,
+		.flags = M3K_SGLDIFF | M3K_D2D1D0
+	},
+	{
+		.name = 3008,
+		.bits = 10,
+		.channels = 8,
+		.lead = 2,
+		.flags = M3K_SGLDIFF | M3K_D2D1D0
+	},
+	{
+		.name = 3201,
+		.bits = 12,
+		.channels = 1,
+		.lead = 3,
+		.flags = 0
+	},
+	{
+		.name = 3202,
+		.bits = 12,
+		.channels = 2,
+		.lead = 2,
+		.flags = M3K_SGLDIFF | M3K_MSBF
+	},
+	{
+		.name = 3204,
+		.bits = 12,
+		.channels = 4,
+		.lead = 2,
+		.flags = M3K_SGLDIFF | M3K_D2D1D0
+	},
+	{
+		.name = 3208,
+		.bits = 12,
+		.channels = 8,
+		.lead = 2,
+		.flags = M3K_SGLDIFF | M3K_D2D1D0
+	},
+	{
+		.name = 3301,
+		.bits = 13,
+		.channels = 1,
+		.lead = 3,
+		.flags = M3K_SIGNED
+	},
+	{
+		.name = 3302,
+		.bits = 13,
+		.channels = 4,
+		.lead = 2,
+		.flags = M3K_SIGNED | M3K_SGLDIFF | M3K_D2D1D0
+	},
+	{
+		.name = 3204,
+		.bits = 13,
+		.channels = 8,
+		.lead = 2,
+		.flags = M3K_SIGNED | M3K_SGLDIFF | M3K_D2D1D0
+	},
+};
+
+static int
+mcp3kadc_match(device_t parent, cfdata_t cf, void *aux)
+{
+	struct spi_attach_args *sa = aux;
+
+	if (strcmp(cf->cf_name, "mcp3kadc") != 0)
+		return 0;
+
+	/* configure for 1MHz */
+	if (spi_configure(sa->sa_handle, SPI_MODE_0, 1000000))
+		return 0;
+
+	return 1;
+}
+
+static void
+mcp3kadc_attach(device_t parent, device_t self, void *aux)
+{
+	const struct sysctlnode *rnode, *node;
+	struct spi_attach_args *sa;
+	struct mcp3kadc_softc *sc;
+	struct mcp3kadc_model *model;
+	int ch, i;
+
+	sa = aux;
+	sc = device_private(self);
+	sc->sc_dev = self;
+	sc->sc_sh = sa->sa_handle;
+
+	/* device flags define the model */
+	sc->sc_model = device_cfdata(sc->sc_dev)->cf_flags;
+	model = &mcp3k_models[sc->sc_model];
+
+	aprint_naive(": Analog to Digital converter\n");
+	aprint_normal(": MCP%u %u-channel %u-bit ADC\n",
+	    (unsigned)model->name, (unsigned)model->channels,
+	    (unsigned)model->bits);
+
+	/* set a default Vref in mV according to the chip's ADC resolution */
+	sc->sc_vref_mv = 1 << ((model->flags & M3K_SIGNED) ?
+	    model->bits - 1 : model->bits);
+
+	/* remember maximum value for this ADC - also used for masking */
+	sc->sc_adc_max = (1 << model->bits) - 1;
+
+	/* attach voltage sensors to envsys */
+	sc->sc_sme = sysmon_envsys_create();
+
+	/* adc difference from two neighbouring channels */
+	for (ch = 0; ch < model->channels; ch++) {
+		KASSERT(ch < M3K_MAX_SENSORS);
+		sc->sc_sensors[ch].units = ENVSYS_SVOLTS_DC;
+		sc->sc_sensors[ch].state = ENVSYS_SINVALID;
+		if (model->channels == 1)
+			strlcpy(sc->sc_sensors[ch].desc, "adc diff ch0",
+			    sizeof(sc->sc_sensors[ch].desc));
+		else
+			snprintf(sc->sc_sensors[ch].desc,
+			    sizeof(sc->sc_sensors[ch].desc),
+			    "adc diff ch%d-ch%d", ch, ch ^ 1);
+		sc->sc_sensors[ch].private = ch;
+		sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensors[ch]);
+	}
+
+	if (model->flags & M3K_SGLDIFF) {
+		/* adc from single ended channels */
+		for (i = 0; i < model->channels; i++, ch++) {
+			KASSERT(ch < M3K_MAX_SENSORS);
+			sc->sc_sensors[ch].units = ENVSYS_SVOLTS_DC;
+			sc->sc_sensors[ch].state = ENVSYS_SINVALID;
+			snprintf(sc->sc_sensors[ch].desc,
+			    sizeof(sc->sc_sensors[ch].desc),
+			    "adc single ch%d", i);
+			sc->sc_sensors[ch].private = ch;
+			sysmon_envsys_sensor_attach(sc->sc_sme,
+			    &sc->sc_sensors[ch]);
+		}
+	}
+
+	sc->sc_sme->sme_name = device_xname(self);
+	sc->sc_sme->sme_refresh = mcp3kadc_envsys_refresh;
+	sc->sc_sme->sme_cookie = sc;
+	if (sysmon_envsys_register(sc->sc_sme)) {
+		aprint_error_dev(self, "unable to register with sysmon\n");
+		sysmon_envsys_destroy(sc->sc_sme);
+	}
+
+	/* create a sysctl node for adjusting the ADC's reference voltage */
+	rnode = node = NULL;
+	sysctl_createv(NULL, 0, NULL, &rnode,
+	    CTLFLAG_READWRITE,
+	    CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
+	    NULL, 0, NULL, 0,
+	    CTL_HW, CTL_CREATE, CTL_EOL);
+
+	if (rnode != NULL)
+		sysctl_createv(NULL, 0, NULL, &node,
+		    CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
+		    CTLTYPE_INT, "vref",
+		    SYSCTL_DESCR("ADC reference voltage"),
+		    sysctl_mcp3kadc_vref, 0, (void *)sc, 0,
+		    CTL_HW, rnode->sysctl_num, CTL_CREATE, CTL_EOL);
+}
+
+static void
+mcp3kadc_envsys_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
+{
+	struct mcp3kadc_softc *sc;
+	struct mcp3kadc_model *model;
+	uint8_t buf[2], ctrl;
+	int32_t val, scale;
+
+	sc = sme->sme_cookie;
+	model = &mcp3k_models[sc->sc_model];
+	scale = sc->sc_adc_max + 1;
+
+	if (model->flags & M3K_CTRL_NEEDED) {
+		/* we need to send some control bits first */
+		ctrl = 1;	/* start bit */
+
+		if (model->flags & M3K_SGLDIFF) {
+			/* bit set to select single-ended mode */
+			ctrl <<= 1;
+			ctrl |= edata->private >= model->channels;
+		}
+
+		if (model->flags & M3K_D2D1D0) {
+			/* 3 bits select the channel */
+			ctrl <<= 3;
+			ctrl |= edata->private & (model->channels - 1);
+		} else {
+			/* 1 bit selects between two channels */
+			ctrl <<= 1;
+			ctrl |= edata->private & 1;
+		}
+
+		if (model->flags & M3K_MSBF) {
+			/* bit select MSB first format */
+			ctrl <<= 1;
+			ctrl |= 1;
+		}
+
+		/* send control bits, receive ADC data */
+		if (spi_send_recv(sc->sc_sh, 1, &ctrl, 2, buf) != 0) {
+			edata->state = ENVSYS_SINVALID;
+			return;
+		}
+	} else {
+
+		/* just read data from the ADC */
+		if (spi_recv(sc->sc_sh, 2, buf) != 0) {
+			edata->state = ENVSYS_SINVALID;
+			return;
+		}
+	}
+
+	/* extract big-endian ADC data from buffer */
+	val = (buf[0] << 8) | buf[1];
+	val = (val >> (16 - (model->bits + model->lead))) & sc->sc_adc_max;
+
+	/* sign-extend the result, when needed */
+	if (model->flags & M3K_SIGNED) {
+		if (val & (1 << (model->bits - 1)))
+			val -= sc->sc_adc_max + 1;
+		scale >>= 1;	/* MSB is the sign */
+	}
+
+	/* scale the value for Vref and convert to mV */
+	edata->value_cur = (sc->sc_vref_mv * val / scale) * 1000;
+	edata->state = ENVSYS_SVALID;
+}
+
+static int
+sysctl_mcp3kadc_vref(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	struct mcp3kadc_softc *sc;
+	int32_t t;
+	int error;
+
+	node = *rnode;
+	sc = node.sysctl_data;
+
+	t = sc->sc_vref_mv;
+	node.sysctl_data = &t;
+
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+	if (t <= 0)
+		return EINVAL;
+
+	sc->sc_vref_mv = t;
+	return 0;
+}

Reply via email to