NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/52972: Support additional devices for dstemp(4)
>Number: 52972
>Category: kern
>Synopsis: enhancements for dstemp(4)
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Thu Feb 01 23:25:00 +0000 2018
>Originator: Paul Goyette
>Release: NetBSD 8.99.7
>Organization:
+------------------+--------------------------+----------------------------+
| Paul Goyette | PGP Key fingerprint: | E-mail addresses: |
| (Retired) | FA29 0E3B 35AF E8AE 6651 | paul at whooppee dot com |
| Kernel Developer | 0786 F758 55DE 53BA 7731 | pgoyette at netbsd dot org |
+------------------+--------------------------+----------------------------+
>Environment:
System: NetBSD speedy.whooppee.com 8.99.7 NetBSD 8.99.7 (SPEEDY 2017-11-29 22:03:05 UTC) #0: Wed Nov 29 23:14:50 UTC 2017 paul%speedy.whooppee.com@localhost:/build/netbsd-local/obj/amd64/sys/arch/amd64/compile/SPEEDY amd64
Architecture: x86_64
Machine: amd64
>Description:
I've had the following driver sitting in my INBOX for several years; it
was never imported because the submitter had disappeared and I didn't have
appropriate hardware.
Now that we have a basic driver for one sensor model, it shouldn't be too
difficult to merge this code into the recently-committed dstemp(4) driver!
--------------
/* $NetBSD: dstemp_reg.h,v 0.1 2009/05/11 09:49:48 xxx Exp $ */
/*-
* Copyright (c) 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jukka Ruohonen.
*
* 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 _DEV_I2C_DSTEMP_REG_H
#define _DEV_I2C_DSTEMP_REG_H
#include <sys/cdefs.h>
/*
* Derived from the following datasheets:
*
* DS1621 (replaced DS1625):
* http://datasheets.maxim-ic.com/en/ds/DS1621.pdf
*
* DS1624:
* http://datasheets.maxim-ic.com/en/ds/DS1624.pdf
*
* DS1631, DS1631A, DS1731:
* http://datasheets.maxim-ic.com/en/ds/DS1631-DS1731.pdf
*
* DS1721:
* http://datasheets.maxim-ic.com/en/ds/DS1721.pdf
*
* (Retrieved on Mon May 11 09:49:48 EEST 2009.)
*/
/*
* The accuracy of the listed chips vary from 9-bit
* resolution to 13-bit resolution. The MSB will always
* represent resolution of 1 C, whereas the LSB conveys
* additional resolution. The following modified example
* is taken from the datasheet of DS1624:
*
* degC MSB LSB uint16_t
* ----- -------- -------- --------
* MAX: +125.0 01111101 00000000 0x7D00
* +25.0625 00011001 00010000 0x1910
* +25.0 00011001 00000000 0x1900
* +0.5 00000000 10000000 0x0080
* 0.0 00000000 00000000 0x0000
* -0.5 11111111 10000000 0xFF80
* -25.0625 11100110 11110000 0xE6F0
* -25.0 11100111 00000000 0xE700
* MIN: -55.0 11001001 00000000 0xC900
* S
*
* Instead of this 13-bit (0.03125 C) resolution, other
* listed chips provide varying degrees of accuracy.
*
* Conversion times vary substantially between different
* resolutions. An example from the datasheet of DS1721:
*
* R1 R0 Resol. Time (ms)
* -- -- ------ ---------
* 0 0 9-bit 93.75
* 0 1 10-bit 187.50
* 1 0 11-bit 375.00
* 1 1 12-bit 750.00
*/
#define DSTEMP_ADDRMASK 0x78
#define DSTEMP_ADDR 0x48 /* 100 1xxx (same for all listed chips) */
#define DS1621_REG_READ_TEMP 0xAA
#define DS1621_REG_ACCESS_TH 0xA1
#define DS1621_REG_ACCESS_TL 0xA2
#define DS1621_REG_ACCESS_CTRL 0xAC
#define DS1621_REG_READ_COUNT 0xA8
#define DS1621_REG_READ_SLOPE 0xA9
#define DS1621_REG_CONV_START 0xEE /* Diverges. */
#define DS1621_REG_CONV_STOP 0x22
#define DS1624_REG_READ_TEMP 0xAA
#define DS1624_REG_ACCESS_CTRL 0xAC
#define DS1624_REG_ACCESS_MEM 0x17
#define DS1624_REG_CONV_START 0xEE
#define DS1624_REG_CONV_STOP 0x22
#define DS1625_REG_READ_TEMP 0xAA
#define DS1625_REG_ACCESS_TH 0xA1
#define DS1625_REG_ACCESS_TL 0xA2
#define DS1625_REG_ACCESS_CTRL 0xAC
#define DS1625_REG_CONV_START 0xEE
#define DS1625_REG_CONV_STOP 0x22
#define DS1631_REG_READ_TEMP 0xAA
#define DS1631_REG_ACCESS_TH 0xA1
#define DS1631_REG_ACCESS_TL 0xA2
#define DS1631_REG_ACCESS_CTRL 0xAC
#define DS1631_REG_SOFT_POR 0x54
#define DS1631_REG_CONV_START 0x51
#define DS1631_REG_CONV_STOP 0x22
#define DS1721_REG_READ_TEMP 0xAA
#define DS1721_REG_ACCESS_TH 0xA1
#define DS1721_REG_ACCESS_TL 0xA2
#define DS1721_REG_ACCESS_CTRL 0xAC
#define DS1721_REG_CONV_START 0x51
#define DS1721_REG_CONV_STOP 0x22
#define DSTEMP_REG_READ_TEMP DS1621_REG_READ_TEMP
#define DSTEMP_REG_ACCESS_CTRL DS1621_REG_ACCESS_CTRL
#define DSTEMP_REG_CONV_STOP DS1621_REG_CONV_STOP
#define DS1621_CTRL_1SHOT __BIT(0)
#define DS1621_CTRL_POL __BIT(1)
#define DS1621_CTRL_NVB __BIT(4)
#define DS1621_CTRL_TLF __BIT(5)
#define DS1621_CTRL_THF __BIT(6)
#define DS1621_CTRL_DONE __BIT(7)
#define DS1624_CTRL_1SHOT __BIT(0)
#define DS1624_CTRL_DONE __BIT(7)
#define DS1625_CTRL_1SHOT __BIT(0)
#define DS1625_CTRL_POL __BIT(1)
#define DS1625_CTRL_NVB __BIT(4)
#define DS1625_CTRL_TLF __BIT(5)
#define DS1625_CTRL_THF __BIT(6)
#define DS1625_CTRL_DONE __BIT(7)
#define DS1631_CTRL_1SHOT __BIT(0)
#define DS1631_CTRL_POL __BIT(1)
#define DS1631_CTRL_R0 __BIT(2)
#define DS1631_CTRL_R1 __BIT(3)
#define DS1631_CTRL_NVB __BIT(4)
#define DS1631_CTRL_TLF __BIT(5)
#define DS1631_CTRL_THF __BIT(6)
#define DS1631_CTRL_DONE __BIT(7)
#define DS1721_CTRL_1SHOT __BIT(0)
#define DS1721_CTRL_POL __BIT(1)
#define DS1721_CTRL_R0 __BIT(2)
#define DS1721_CTRL_R1 __BIT(3)
#define DS1721_CTRL_DONE __BIT(7)
#define DSTEMP_CTRL_1SHOT DS1621_CTRL_1SHOT
#define DSTEMP_CTRL_DONE DS1621_CTRL_DONE
#endif /* _DEV_I2C_DSTEMP_REG_H */
---------------
/* $NetBSD: dstemp.c,v 0.1 2009/05/11 09:49:48 xxx Exp $ */
/*-
* Copyright (c) 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jukka Ruohonen.
*
* 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.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: dstemp.c,v 0.1 2009/05/11 09:49:48 xxx Exp $");
#include <sys/param.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <dev/sysmon/sysmonvar.h>
#include <dev/i2c/i2cvar.h>
#include <dev/i2c/dstemp_reg.h>
struct dstemp_softc {
device_t sc_dev;
i2c_tag_t sc_tag;
i2c_addr_t sc_addr;
uint8_t sc_type;
uint8_t sc_start;
envsys_data_t sc_sensor;
struct sysmon_envsys *sc_sme;
};
enum {
DSTEMP_TYPE_DS1621 = 0,
DSTEMP_TYPE_DS1624,
DSTEMP_TYPE_DS1625,
DSTEMP_TYPE_DS1631,
DSTEMP_TYPE_DS1721
};
static const struct {
int type;
uint8_t start;
uint8_t resol; /* Factory default resolution (bits). */
const char *name;
} dstemp_table[] = {
{ DSTEMP_TYPE_DS1621,
DS1621_REG_CONV_START, 9, "DS1621" },
{ DSTEMP_TYPE_DS1624,
DS1624_REG_CONV_START, 13, "DS1624" },
{ DSTEMP_TYPE_DS1625,
DS1625_REG_CONV_START, 9, "DS1625" },
{ DSTEMP_TYPE_DS1631,
DS1631_REG_CONV_START, 12, "DS1631 or compatible" },
{ DSTEMP_TYPE_DS1721,
DS1721_REG_CONV_START, 12, "DS1721" },
{ -1, 0, 0, NULL }
};
/*
* From uK to degC and vice versa.
*/
#define DSTEMP_ENCODE(x) (((((x) - 273150000U) / 62500) << 4) & 0xFFFF);
#define DSTEMP_DECODE(x) ((((int16_t)(x) >> 4) & 0x0FFF) * 62500 + 273150000U)
/*
* Print uK as degC.
*/
#define DSTEMP_PRINT(x) (((x) - 273150000) / 1000000)
/*
* We can handle only PROP_WARNMAX and PROP_WARNMIN in hardware.
*/
#define NOPROP (PROP_CRITMAX | PROP_CRITMIN | PROP_BATTCAP | PROP_BATTWARN)
static int dstemp_lookup(const int);
static bool dstemp_ident(struct dstemp_softc *, const uint8_t);
static int dstemp_match(device_t, cfdata_t, void *);
static void dstemp_attach(device_t, device_t, void *);
static bool dstemp_init(device_t);
static bool dstemp_init_sysmon(device_t);
static void dstemp_get_limits(struct sysmon_envsys *, envsys_data_t *,
sysmon_envsys_lim_t *);
static void dstemp_set_limits(struct sysmon_envsys *, envsys_data_t *,
sysmon_envsys_lim_t *);
static bool dstemp_check_limits(struct dstemp_softc *);
static void dstemp_refresh(struct sysmon_envsys *, envsys_data_t *);
static bool dstemp_enable(struct dstemp_softc *, const bool);
static bool dstemp_read_ctrl(struct dstemp_softc *, uint8_t *);
static bool dstemp_write_ctrl(struct dstemp_softc *, const uint8_t);
static bool dstemp_read_16(struct dstemp_softc *, const uint8_t, uint16_t *);
static bool dstemp_write_16(struct dstemp_softc *,
const uint8_t, const uint16_t);
static bool dstemp_suspend(device_t PMF_FN_PROTO);
static bool dstemp_resume(device_t PMF_FN_PROTO);
CFATTACH_DECL_NEW(dstemp, sizeof(struct dstemp_softc),
dstemp_match, dstemp_attach, NULL, NULL);
static int
dstemp_lookup(const int cf_flags)
{
int i;
for (i = 0; dstemp_table[i].name != NULL; i++) {
if (dstemp_table[i].type == cf_flags)
return i;
}
return -1;
}
/*
* Since there is no identification register, we use the
* following simple heuristic as a validation test: either
*
* 7 (DS1621 and DS1625),
* 3 (DS1624) or
* 4 (DS1631-DS1731 and DS1721)
*
* least significant bits should always be zero.
*/
static bool
dstemp_ident(struct dstemp_softc *sc, const uint8_t resol)
{
uint16_t temp;
KDASSERT(resol <= 16);
iic_acquire_bus(sc->sc_tag, 0);
if (dstemp_read_16(sc, DSTEMP_REG_READ_TEMP, &temp) != true) {
iic_release_bus(sc->sc_tag, 0);
return false;
}
iic_release_bus(sc->sc_tag, 0);
if ((temp & (0xFFFF >> resol)) != 0)
return false;
return true;
}
static int
dstemp_match(device_t parent, cfdata_t cf, void *aux)
{
struct dstemp_softc sc;
struct i2c_attach_args *ia = aux;
int i;
sc.sc_tag = ia->ia_tag;
sc.sc_addr = ia->ia_addr;
if ((ia->ia_addr & DSTEMP_ADDRMASK) != DSTEMP_ADDR)
return 0;
if ((i = dstemp_lookup(cf->cf_flags)) < 0) {
aprint_debug("dstemp0: invalid configuration flag\n");
return 0;
}
if (dstemp_ident(&sc, dstemp_table[i].resol) != true) {
aprint_debug("dstemp0: failed to identify chip\n");
return 0;
}
return 1;
}
static void
dstemp_attach(device_t parent, device_t self, void *aux)
{
struct dstemp_softc *sc = device_private(self);
struct i2c_attach_args *ia = aux;
sysmon_envsys_lim_t limits;
uint16_t lim;
int i;
sc->sc_dev = self;
sc->sc_tag = ia->ia_tag;
sc->sc_addr = ia->ia_addr;
i = dstemp_lookup(device_cfdata(self)->cf_flags);
KDASSERT(i != -1);
aprint_naive(": temperature sensor\n");
aprint_normal(": %s temperature sensor\n", dstemp_table[i].name);
sc->sc_type = dstemp_table[i].type;
sc->sc_start = dstemp_table[i].start;
if (dstemp_init(self) != true) {
aprint_error_dev(self, "failed to initialize device\n");
return;
}
if (dstemp_init_sysmon(self) != true) {
aprint_error_dev(self, "failed to initialize sysmon\n");
return;
}
if (pmf_device_register(self, dstemp_suspend, dstemp_resume) != true)
aprint_error_dev(self, "failed to establish power handler\n");
if (sc->sc_type == DSTEMP_TYPE_DS1624 ||
sc->sc_type == DSTEMP_TYPE_DS1721)
return;
(void)memset(&limits, 0, sizeof(struct sysmon_envsys_lim));
dstemp_get_limits(sc->sc_sme, &sc->sc_sensor, &limits);
if ((limits.sel_flags & PROP_WARNMIN) != 0) {
lim = DSTEMP_PRINT(limits.sel_warnmin);
aprint_normal_dev(self, "low limit %u C\n", lim);
}
if ((limits.sel_flags & PROP_WARNMAX) != 0) {
lim = DSTEMP_PRINT(limits.sel_warnmax);
aprint_normal_dev(self, "high limit %u C\n", lim);
}
}
static bool
dstemp_init(device_t self)
{
struct dstemp_softc *sc = device_private(self);
uint8_t buf, val;
iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
if (dstemp_read_ctrl(sc, &buf) != true)
goto fail;
val = buf;
/*
* We want continuous mode.
*/
if ((buf & DSTEMP_CTRL_1SHOT) != 0)
val &= ~DSTEMP_CTRL_1SHOT;
/*
* We want full resolution for these chips.
*/
if (sc->sc_type == DSTEMP_TYPE_DS1631 ||
sc->sc_type == DSTEMP_TYPE_DS1721) {
val |= DS1631_CTRL_R0;
val |= DS1631_CTRL_R1;
}
if (buf != val) {
/*
* If we are already operating in continuous
* mode, conversions must be stopped before
* writing to the configuration register.
*/
if ((buf & DSTEMP_CTRL_1SHOT) != 0) {
if (dstemp_enable(sc, false) != true)
goto fail;
}
if (dstemp_write_ctrl(sc, val) != true)
goto fail;
DELAY(10000); /* 10 ms required for next write. */
}
if (dstemp_enable(sc, true) != true)
goto fail;
iic_release_bus(sc->sc_tag, I2C_F_POLL);
return true;
fail:
iic_release_bus(sc->sc_tag, I2C_F_POLL);
return false;
}
static bool
dstemp_init_sysmon(device_t self)
{
struct dstemp_softc *sc = device_private(self);
sc->sc_sme = sysmon_envsys_create();
sc->sc_sensor.monitor = true;
sc->sc_sensor.units = ENVSYS_STEMP;
sc->sc_sensor.state = ENVSYS_SINVALID;
sc->sc_sensor.flags |= ENVSYS_FMONLIMITS;
(void)strlcpy(sc->sc_sensor.desc,
device_xname(self), sizeof(sc->sc_sensor.desc));
/*
* Although all supported chips are capable of operating with
* temperatures below zero, we limit the valid values to [0, 125].
*/
sc->sc_sensor.value_min = 0;
sc->sc_sensor.value_max = DSTEMP_DECODE(0x7D00);
sc->sc_sensor.flags |= ENVSYS_FVALID_MAX | ENVSYS_FVALID_MIN;
if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor) != 0) {
sysmon_envsys_destroy(sc->sc_sme);
return false;
}
sc->sc_sme->sme_cookie = sc;
sc->sc_sme->sme_refresh = dstemp_refresh;
sc->sc_sme->sme_name = device_xname(self);
sc->sc_sme->sme_get_limits = NULL;
sc->sc_sme->sme_set_limits = NULL;
if (sc->sc_type != DSTEMP_TYPE_DS1624 &&
sc->sc_type != DSTEMP_TYPE_DS1721) {
sc->sc_sme->sme_get_limits = dstemp_get_limits;
sc->sc_sme->sme_set_limits = dstemp_set_limits;
}
if (sysmon_envsys_register(sc->sc_sme) != 0) {
sysmon_envsys_destroy(sc->sc_sme);
return false;
}
return true;
}
static void
dstemp_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
sysmon_envsys_lim_t *limits)
{
struct dstemp_softc *sc = sme->sme_cookie;
uint16_t hi, lo;
KDASSERT(sc->sc_type != DSTEMP_TYPE_DS1624);
KDASSERT(sc->sc_type != DSTEMP_TYPE_DS1721);
hi = lo = 0xFFFF;
iic_acquire_bus(sc->sc_tag, 0);
(void)dstemp_read_16(sc, DS1621_REG_ACCESS_TH, &hi);
(void)dstemp_read_16(sc, DS1621_REG_ACCESS_TL, &lo);
iic_release_bus(sc->sc_tag, 0);
if (hi != 0xFFFF && (hi & __BIT(15)) == 0) {
limits->sel_warnmax = DSTEMP_DECODE(hi);
limits->sel_flags |= PROP_WARNMAX;
}
if (lo != 0xFFFF && (lo & __BIT(15)) == 0) {
limits->sel_warnmin = DSTEMP_DECODE(lo);
limits->sel_flags |= PROP_WARNMIN;
}
if (hi == 0xFFFF || lo == 0xFFFF)
aprint_debug_dev(sc->sc_dev, "failed to get limits\n");
}
static void
dstemp_set_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
sysmon_envsys_lim_t *limits)
{
struct dstemp_softc *sc = sme->sme_cookie;
uint16_t lim;
KDASSERT(sc->sc_type != DSTEMP_TYPE_DS1624);
KDASSERT(sc->sc_type != DSTEMP_TYPE_DS1721);
iic_acquire_bus(sc->sc_tag, 0);
/*
* We must stop conversions when making
* changes to the trip-point registers.
*/
if (dstemp_enable(sc, false) != true) {
iic_release_bus(sc->sc_tag, 0);
return;
}
if ((limits->sel_flags & PROP_WARNMAX) != 0) {
lim = DSTEMP_ENCODE(limits->sel_warnmax);
if (dstemp_write_16(sc, DS1621_REG_ACCESS_TH, lim) != true)
aprint_debug_dev(sc->sc_dev, "failed to set limits\n");
}
if ((limits->sel_flags & PROP_WARNMIN) != 0) {
lim = DSTEMP_ENCODE(limits->sel_warnmin);
if (dstemp_write_16(sc, DS1621_REG_ACCESS_TL, lim) != true)
aprint_debug_dev(sc->sc_dev, "failed to set limits\n");
}
if (dstemp_enable(sc, true) != true) {
iic_release_bus(sc->sc_tag, 0);
return;
}
iic_release_bus(sc->sc_tag, 0);
/*
* If and only if PROP_LIMITS is set and
* we can handle all requested limits,
* take over the processing of limits.
*/
limits->sel_flags &= ~PROP_DRIVER_LIMITS;
if ((limits->sel_flags & NOPROP) != 0)
return;
if ((limits->sel_flags & PROP_LIMITS) == 0)
return;
limits->sel_flags |= PROP_DRIVER_LIMITS;
}
static bool
dstemp_check_limits(struct dstemp_softc *sc)
{
uint8_t buf, val;
KDASSERT(sc->sc_type != DSTEMP_TYPE_DS1624);
KDASSERT(sc->sc_type != DSTEMP_TYPE_DS1721);
iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
if (__predict_false(dstemp_read_ctrl(sc, &buf) != true))
goto fail;
val = buf;
if (__predict_false((buf & DS1621_CTRL_THF) != 0)) {
val &= ~DS1621_CTRL_THF;
sc->sc_sensor.state = ENVSYS_SWARNOVER;
}
if (__predict_false((buf & DS1621_CTRL_TLF) != 0)) {
val &= ~DS1621_CTRL_TLF;
sc->sc_sensor.state = ENVSYS_SWARNUNDER;
KASSERT(sc->sc_sensor.state != ENVSYS_SWARNOVER);
}
if (buf != val) {
if (__predict_false(dstemp_enable(sc, false) != true))
goto fail;
if (__predict_false(dstemp_write_ctrl(sc, val) != true))
goto fail;
if (__predict_false(dstemp_enable(sc, true) != true))
goto fail;
}
iic_release_bus(sc->sc_tag, 0);
return true;
fail:
iic_release_bus(sc->sc_tag, 0);
return false;
}
static void
dstemp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
{
struct dstemp_softc *sc = sme->sme_cookie;
uint16_t temp;
bool rv;
iic_acquire_bus(sc->sc_tag, 0);
rv = dstemp_read_16(sc, DSTEMP_REG_READ_TEMP, &temp);
iic_release_bus(sc->sc_tag, 0);
if (__predict_false(rv != true)) {
aprint_debug_dev(sc->sc_dev, "failed to read temperature\n");
sc->sc_sensor.state = ENVSYS_SINVALID;
return;
}
/*
* It is unlikely that NetBSD will ever run in a freezer.
*/
if (__predict_false((temp & __BIT(15)) != 0)) {
aprint_debug_dev(sc->sc_dev, "temperature below zero?\n");
sc->sc_sensor.state = ENVSYS_SINVALID;
return;
}
sc->sc_sensor.state = ENVSYS_SVALID;
sc->sc_sensor.value_cur = DSTEMP_DECODE(temp);
if (sc->sc_type == DSTEMP_TYPE_DS1624 ||
sc->sc_type == DSTEMP_TYPE_DS1721)
return;
if ((sc->sc_sensor.upropset & PROP_DRIVER_LIMITS) == 0)
return;
KDASSERT((sc->sc_sensor.upropset & NOPROP) == 0);
if (__predict_false(dstemp_check_limits(sc) != true))
aprint_debug_dev(sc->sc_dev, "failed to evaluate limits\n");
}
static bool
dstemp_enable(struct dstemp_softc *sc, const bool enable)
{
bool rv;
uint8_t cmd;
const char *str;
cmd = (enable != true) ? DSTEMP_REG_CONV_STOP : sc->sc_start;
rv = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
sc->sc_addr, &cmd, 1, NULL, 0, 0);
if (__predict_false(rv != 0)) {
str = (enable != true) ? "disable" : "enable";
aprint_debug_dev(sc->sc_dev, "failed to %s device\n", str);
return false;
}
return true;
}
static bool
dstemp_read_ctrl(struct dstemp_softc *sc, uint8_t *valp)
{
uint8_t buf, cmd = DSTEMP_REG_ACCESS_CTRL;
if (iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, cmd, &buf, 0) != 0)
return false;
*valp = buf;
return true;
}
static bool
dstemp_write_ctrl(struct dstemp_softc *sc, const uint8_t val)
{
uint8_t cmd = DSTEMP_REG_ACCESS_CTRL;
if (iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, cmd, val, 0) != 0)
return false;
return true;
}
static bool
dstemp_read_16(struct dstemp_softc *sc, const uint8_t cmd, uint16_t *valp)
{
uint16_t buf;
if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
sc->sc_addr, &cmd, 1, &buf, 2, 0) != 0) {
return false;
}
*valp = be16toh(buf);
return true;
}
static bool
dstemp_write_16(struct dstemp_softc *sc, const uint8_t cmd, const uint16_t val)
{
uint16_t buf;
buf = htobe16(val);
if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
sc->sc_addr, &cmd, 1, &buf, 2, 0) != 0)
return false;
return true;
}
static bool
dstemp_suspend(device_t dv PMF_FN_ARGS)
{
struct dstemp_softc *sc = device_private(dv);
bool rv;
iic_acquire_bus(sc->sc_tag, 0);
rv = dstemp_enable(sc, false);
iic_release_bus(sc->sc_tag, 0);
return rv;
}
static bool
dstemp_resume(device_t dv PMF_FN_ARGS)
{
struct dstemp_softc *sc = device_private(dv);
bool rv;
iic_acquire_bus(sc->sc_tag, 0);
rv = dstemp_enable(sc, true);
iic_release_bus(sc->sc_tag, 0);
return rv;
}
>How-To-Repeat:
>Fix:
>Unformatted:
Home |
Main Index |
Thread Index |
Old Index