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; +}