11.8Sandvar/*	$NetBSD: mcp980x.c,v 1.8 2024/01/16 21:08:52 andvar Exp $ */
21.1Srkujawa
31.1Srkujawa/*-
41.1Srkujawa * Copyright (c) 2013 The NetBSD Foundation, Inc.
51.1Srkujawa * All rights reserved.
61.1Srkujawa *
71.1Srkujawa * This code is derived from software contributed to The NetBSD Foundation
81.1Srkujawa * by Radoslaw Kujawa.
91.1Srkujawa *
101.1Srkujawa * Redistribution and use in source and binary forms, with or without
111.1Srkujawa * modification, are permitted provided that the following conditions
121.1Srkujawa * are met:
131.1Srkujawa * 1. Redistributions of source code must retain the above copyright
141.1Srkujawa *    notice, this list of conditions and the following disclaimer.
151.1Srkujawa * 2. Redistributions in binary form must reproduce the above copyright
161.1Srkujawa *    notice, this list of conditions and the following disclaimer in the
171.1Srkujawa *    documentation and/or other materials provided with the distribution.
181.1Srkujawa *
191.1Srkujawa * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
201.1Srkujawa * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
211.1Srkujawa * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
221.1Srkujawa * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
231.1Srkujawa * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
241.1Srkujawa * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
251.1Srkujawa * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
261.1Srkujawa * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
271.1Srkujawa * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
281.1Srkujawa * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
291.1Srkujawa * POSSIBILITY OF SUCH DAMAGE.
301.1Srkujawa */
311.1Srkujawa
321.1Srkujawa/*
331.1Srkujawa * Microchip MCP9800/1/2/3 2-Wire High-Accuracy Temperature Sensor driver.
341.1Srkujawa *
351.8Sandvar * TODO: better error checking, particularly in user settable limits.
361.4Srkujawa *
371.1Srkujawa * Note: MCP9805 is different and is supported by the sdtemp(4) driver.
381.1Srkujawa */
391.1Srkujawa
401.1Srkujawa#include <sys/cdefs.h>
411.8Sandvar__KERNEL_RCSID(0, "$NetBSD: mcp980x.c,v 1.8 2024/01/16 21:08:52 andvar Exp $");
421.1Srkujawa
431.1Srkujawa#include <sys/param.h>
441.1Srkujawa#include <sys/systm.h>
451.1Srkujawa#include <sys/device.h>
461.1Srkujawa#include <sys/kernel.h>
471.1Srkujawa#include <sys/mutex.h>
481.1Srkujawa#include <sys/endian.h>
491.2Srkujawa#include <sys/sysctl.h>
501.1Srkujawa
511.1Srkujawa#include <sys/bus.h>
521.1Srkujawa#include <dev/i2c/i2cvar.h>
531.1Srkujawa
541.1Srkujawa#include <dev/sysmon/sysmonvar.h>
551.1Srkujawa
561.1Srkujawa#include <dev/i2c/mcp980xreg.h>
571.1Srkujawa
581.1Srkujawastruct mcp980x_softc {
591.1Srkujawa	device_t		sc_dev;
601.1Srkujawa
611.1Srkujawa	i2c_tag_t		sc_tag;
621.1Srkujawa	i2c_addr_t		sc_addr;
631.1Srkujawa
641.2Srkujawa	int			sc_res;
651.4Srkujawa	int			sc_hyst;
661.4Srkujawa	int			sc_limit;
671.2Srkujawa
681.1Srkujawa	/* envsys(4) stuff */
691.1Srkujawa	struct sysmon_envsys	*sc_sme;
701.1Srkujawa	envsys_data_t		sc_sensor;
711.1Srkujawa	kmutex_t		sc_lock;
721.1Srkujawa};
731.1Srkujawa
741.1Srkujawa
751.1Srkujawastatic int mcp980x_match(device_t, cfdata_t, void *);
761.1Srkujawastatic void mcp980x_attach(device_t, device_t, void *);
771.1Srkujawa
781.2Srkujawastatic uint8_t mcp980x_reg_read_1(struct mcp980x_softc *, uint8_t);
791.2Srkujawastatic uint16_t mcp980x_reg_read_2(struct mcp980x_softc *, uint8_t);
801.2Srkujawastatic void mcp980x_reg_write_1(struct mcp980x_softc *, uint8_t, uint8_t);
811.2Srkujawa
821.2Srkujawastatic uint8_t mcp980x_resolution_get(struct mcp980x_softc *);
831.2Srkujawastatic void mcp980x_resolution_set(struct mcp980x_softc *, uint8_t);
841.1Srkujawa
851.4Srkujawastatic int8_t mcp980x_hysteresis_get(struct mcp980x_softc *);
861.4Srkujawastatic void mcp980x_hysteresis_set(struct mcp980x_softc *, int8_t);
871.4Srkujawastatic int8_t mcp980x_templimit_get(struct mcp980x_softc *);
881.4Srkujawastatic void mcp980x_templimit_set(struct mcp980x_softc *, int8_t);
891.4Srkujawa
901.4Srkujawastatic int8_t mcp980x_s8b_get(struct mcp980x_softc *, uint8_t);
911.4Srkujawastatic void mcp980x_s8b_set(struct mcp980x_softc *, uint8_t, int8_t);
921.4Srkujawa
931.2Srkujawastatic uint32_t mcp980x_temperature(struct mcp980x_softc *);
941.1Srkujawa
951.1Srkujawastatic void mcp980x_envsys_register(struct mcp980x_softc *);
961.1Srkujawastatic void mcp980x_envsys_refresh(struct sysmon_envsys *, envsys_data_t *);
971.1Srkujawa
981.2Srkujawastatic void mcp980x_setup_sysctl(struct mcp980x_softc *);
991.2Srkujawastatic int sysctl_mcp980x_res(SYSCTLFN_ARGS);
1001.4Srkujawastatic int sysctl_mcp980x_hysteresis(SYSCTLFN_ARGS);
1011.4Srkujawastatic int sysctl_mcp980x_templimit(SYSCTLFN_ARGS);
1021.2Srkujawa
1031.1SrkujawaCFATTACH_DECL_NEW(mcp980x, sizeof (struct mcp980x_softc),
1041.1Srkujawa    mcp980x_match, mcp980x_attach, NULL, NULL);
1051.1Srkujawa
1061.1Srkujawastatic int
1071.1Srkujawamcp980x_match(device_t parent, cfdata_t cf, void *aux)
1081.1Srkujawa{
1091.1Srkujawa
1101.6Sthorpej	if (ia->ia_addr >= MCP980X_ADDR_CONST &&
1111.6Sthorpej	    ia->ia_addr <= (MCP980X_ADDR_CONST + MCP980X_ADDR_VAR))
1121.6Sthorpej		return I2C_MATCH_ADDRESS_ONLY;
1131.6Sthorpej
1141.6Sthorpej	return 0;
1151.1Srkujawa}
1161.1Srkujawa
1171.1Srkujawastatic void
1181.1Srkujawamcp980x_attach(device_t parent, device_t self, void *aux)
1191.1Srkujawa{
1201.1Srkujawa	struct mcp980x_softc *sc = device_private(self);
1211.1Srkujawa	struct i2c_attach_args *ia = aux;
1221.1Srkujawa
1231.1Srkujawa	sc->sc_dev = self;
1241.1Srkujawa	sc->sc_addr = ia->ia_addr;
1251.1Srkujawa	sc->sc_tag = ia->ia_tag;
1261.1Srkujawa
1271.1Srkujawa	aprint_normal(": Microchip MCP980x Temperature Sensor\n");
1281.1Srkujawa
1291.2Srkujawa	sc->sc_res = MCP980X_CONFIG_ADC_RES_12BIT;
1301.2Srkujawa	mcp980x_resolution_set(sc, sc->sc_res);
1311.2Srkujawa
1321.4Srkujawa	sc->sc_hyst = mcp980x_hysteresis_get(sc);
1331.4Srkujawa	sc->sc_limit = mcp980x_templimit_get(sc);
1341.4Srkujawa
1351.1Srkujawa	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
1361.1Srkujawa
1371.2Srkujawa	mcp980x_setup_sysctl(sc);
1381.1Srkujawa	mcp980x_envsys_register(sc);
1391.1Srkujawa}
1401.1Srkujawa
1411.1Srkujawastatic uint16_t
1421.1Srkujawamcp980x_reg_read_2(struct mcp980x_softc *sc, uint8_t reg)
1431.1Srkujawa{
1441.1Srkujawa	uint16_t rv;
1451.1Srkujawa
1461.7Sthorpej	if (iic_acquire_bus(sc->sc_tag, 0) != 0) {
1471.1Srkujawa		aprint_error_dev(sc->sc_dev, "cannot acquire bus for read\n");
1481.1Srkujawa		return 0;
1491.1Srkujawa	}
1501.1Srkujawa
1511.2Srkujawa	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &reg,
1521.7Sthorpej	    1, &rv, 2, 0)) {
1531.7Sthorpej		iic_release_bus(sc->sc_tag, 0);
1541.1Srkujawa		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
1551.1Srkujawa		return 0;
1561.1Srkujawa	}
1571.7Sthorpej	iic_release_bus(sc->sc_tag, 0);
1581.1Srkujawa
1591.1Srkujawa	return be16toh(rv);
1601.1Srkujawa}
1611.1Srkujawa
1621.1Srkujawastatic uint8_t
1631.1Srkujawamcp980x_reg_read_1(struct mcp980x_softc *sc, uint8_t reg)
1641.1Srkujawa{
1651.2Srkujawa	uint8_t rv;
1661.1Srkujawa
1671.7Sthorpej	if (iic_acquire_bus(sc->sc_tag, 0) != 0) {
1681.1Srkujawa		aprint_error_dev(sc->sc_dev, "cannot acquire bus for read\n");
1691.1Srkujawa		return 0;
1701.1Srkujawa	}
1711.1Srkujawa
1721.2Srkujawa	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &reg,
1731.7Sthorpej	    1, &rv, 1, 0)) {
1741.7Sthorpej		iic_release_bus(sc->sc_tag, 0);
1751.1Srkujawa		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
1761.1Srkujawa		return 0;
1771.1Srkujawa	}
1781.7Sthorpej	iic_release_bus(sc->sc_tag, 0);
1791.1Srkujawa
1801.1Srkujawa	return rv;
1811.2Srkujawa}
1821.2Srkujawa
1831.2Srkujawastatic void
1841.4Srkujawamcp980x_reg_write_2(struct mcp980x_softc *sc, uint8_t reg, uint16_t val)
1851.4Srkujawa{
1861.4Srkujawa	uint16_t beval;
1871.4Srkujawa
1881.4Srkujawa	beval = htobe16(val);
1891.4Srkujawa
1901.7Sthorpej        if (iic_acquire_bus(sc->sc_tag, 0) != 0) {
1911.4Srkujawa		aprint_error_dev(sc->sc_dev, "cannot acquire bus for write\n");
1921.4Srkujawa		return;
1931.4Srkujawa	}
1941.4Srkujawa
1951.4Srkujawa        if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, &reg,
1961.7Sthorpej	    1, &beval, 2, 0)) {
1971.4Srkujawa		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
1981.4Srkujawa        }
1991.4Srkujawa
2001.7Sthorpej	iic_release_bus(sc->sc_tag, 0);
2011.4Srkujawa
2021.4Srkujawa}
2031.4Srkujawa
2041.4Srkujawastatic void
2051.2Srkujawamcp980x_reg_write_1(struct mcp980x_softc *sc, uint8_t reg, uint8_t val)
2061.2Srkujawa{
2071.7Sthorpej        if (iic_acquire_bus(sc->sc_tag, 0) != 0) {
2081.2Srkujawa		aprint_error_dev(sc->sc_dev, "cannot acquire bus for write\n");
2091.2Srkujawa		return;
2101.2Srkujawa	}
2111.2Srkujawa
2121.2Srkujawa        if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, &reg,
2131.7Sthorpej	    1, &val, 1, 0)) {
2141.2Srkujawa		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
2151.2Srkujawa        }
2161.2Srkujawa
2171.7Sthorpej	iic_release_bus(sc->sc_tag, 0);
2181.2Srkujawa
2191.2Srkujawa}
2201.2Srkujawa
2211.4Srkujawastatic int8_t
2221.4Srkujawamcp980x_templimit_get(struct mcp980x_softc *sc)
2231.4Srkujawa{
2241.4Srkujawa	return mcp980x_s8b_get(sc, MCP980X_TEMP_LIMIT);
2251.4Srkujawa}
2261.4Srkujawa
2271.4Srkujawastatic void
2281.4Srkujawamcp980x_templimit_set(struct mcp980x_softc *sc, int8_t val)
2291.4Srkujawa{
2301.4Srkujawa	mcp980x_s8b_set(sc, MCP980X_TEMP_LIMIT, val);
2311.4Srkujawa}
2321.4Srkujawa
2331.4Srkujawastatic int8_t
2341.4Srkujawamcp980x_hysteresis_get(struct mcp980x_softc *sc)
2351.4Srkujawa{
2361.4Srkujawa	return mcp980x_s8b_get(sc, MCP980X_TEMP_HYSTERESIS);
2371.4Srkujawa}
2381.4Srkujawa
2391.4Srkujawastatic void
2401.4Srkujawamcp980x_hysteresis_set(struct mcp980x_softc *sc, int8_t val)
2411.4Srkujawa{
2421.4Srkujawa	mcp980x_s8b_set(sc, MCP980X_TEMP_HYSTERESIS, val);
2431.4Srkujawa}
2441.4Srkujawa
2451.4Srkujawastatic int8_t
2461.4Srkujawamcp980x_s8b_get(struct mcp980x_softc *sc, uint8_t reg)
2471.4Srkujawa{
2481.4Srkujawa	return mcp980x_reg_read_2(sc, reg) >> MCP980X_TEMP_HYSTLIMIT_INT_SHIFT;
2491.4Srkujawa}
2501.4Srkujawa
2511.4Srkujawastatic void
2521.4Srkujawamcp980x_s8b_set(struct mcp980x_softc *sc, uint8_t reg, int8_t val)
2531.4Srkujawa{
2541.4Srkujawa	mcp980x_reg_write_2(sc, reg, val << MCP980X_TEMP_HYSTLIMIT_INT_SHIFT);
2551.4Srkujawa}
2561.4Srkujawa
2571.2Srkujawastatic uint8_t
2581.2Srkujawamcp980x_resolution_get(struct mcp980x_softc *sc)
2591.2Srkujawa{
2601.2Srkujawa	uint8_t cfg, res;
2611.2Srkujawa
2621.2Srkujawa	cfg = mcp980x_reg_read_1(sc, MCP980X_CONFIG);
2631.2Srkujawa	res = (cfg & MCP980X_CONFIG_ADC_RES) >>
2641.2Srkujawa	    MCP980X_CONFIG_ADC_RES_SHIFT;
2651.2Srkujawa
2661.2Srkujawa	return res;
2671.2Srkujawa}
2681.2Srkujawa
2691.2Srkujawastatic void
2701.2Srkujawamcp980x_resolution_set(struct mcp980x_softc *sc, uint8_t res)
2711.2Srkujawa{
2721.2Srkujawa	uint8_t cfg;
2731.2Srkujawa
2741.2Srkujawa	/* read config register but discard resolution bits */
2751.2Srkujawa	cfg = mcp980x_reg_read_1(sc, MCP980X_CONFIG) & ~MCP980X_CONFIG_ADC_RES;
2761.2Srkujawa	/* set resolution bits to new value */
2771.2Srkujawa	cfg |= res << MCP980X_CONFIG_ADC_RES_SHIFT;
2781.2Srkujawa
2791.2Srkujawa	mcp980x_reg_write_1(sc, MCP980X_CONFIG, cfg);
2801.2Srkujawa}
2811.1Srkujawa
2821.1Srkujawa/* Get temperature in microKelvins. */
2831.1Srkujawastatic uint32_t
2841.1Srkujawamcp980x_temperature(struct mcp980x_softc *sc)
2851.1Srkujawa{
2861.1Srkujawa	uint16_t raw;
2871.1Srkujawa	uint32_t rv, uk, basedegc;
2881.1Srkujawa
2891.1Srkujawa	raw = mcp980x_reg_read_2(sc, MCP980X_AMBIENT_TEMP);
2901.1Srkujawa
2911.1Srkujawa	basedegc = (raw & MCP980X_AMBIENT_TEMP_DEGREES) >>
2921.1Srkujawa	    MCP980X_AMBIENT_TEMP_DEGREES_SHIFT;
2931.1Srkujawa
2941.1Srkujawa	uk = 1000000 * basedegc;
2951.1Srkujawa
2961.1Srkujawa	if (raw & MCP980X_AMBIENT_TEMP_05DEGREE)
2971.1Srkujawa		uk += 500000;
2981.1Srkujawa	if (raw & MCP980X_AMBIENT_TEMP_025DEGREE)
2991.1Srkujawa		uk += 250000;
3001.1Srkujawa	if (raw & MCP980X_AMBIENT_TEMP_0125DEGREE)
3011.1Srkujawa		uk += 125000;
3021.1Srkujawa	if (raw & MCP980X_AMBIENT_TEMP_00625DEGREE)
3031.1Srkujawa		uk += 62500;
3041.1Srkujawa
3051.1Srkujawa	if (raw & MCP980X_AMBIENT_TEMP_SIGN)
3061.1Srkujawa		rv = 273150000U - uk;
3071.1Srkujawa	else
3081.1Srkujawa		rv = 273150000U + uk;
3091.1Srkujawa
3101.1Srkujawa	return rv;
3111.1Srkujawa}
3121.1Srkujawa
3131.1Srkujawastatic void
3141.1Srkujawamcp980x_envsys_register(struct mcp980x_softc *sc)
3151.1Srkujawa{
3161.1Srkujawa	sc->sc_sme = sysmon_envsys_create();
3171.1Srkujawa
3181.1Srkujawa	strlcpy(sc->sc_sensor.desc, "Ambient temp",
3191.1Srkujawa	    sizeof(sc->sc_sensor.desc));
3201.1Srkujawa	sc->sc_sensor.units = ENVSYS_STEMP;
3211.1Srkujawa	sc->sc_sensor.state = ENVSYS_SINVALID;
3221.1Srkujawa
3231.1Srkujawa	if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) {
3241.1Srkujawa		aprint_error_dev(sc->sc_dev,
3251.1Srkujawa		    "error attaching sensor\n");
3261.1Srkujawa		return;
3271.1Srkujawa	}
3281.1Srkujawa
3291.1Srkujawa	sc->sc_sme->sme_name = device_xname(sc->sc_dev);
3301.1Srkujawa	sc->sc_sme->sme_cookie = sc;
3311.1Srkujawa	sc->sc_sme->sme_refresh = mcp980x_envsys_refresh;
3321.1Srkujawa
3331.1Srkujawa	if (sysmon_envsys_register(sc->sc_sme)) {
3341.1Srkujawa		aprint_error_dev(sc->sc_dev, "unable to register in sysmon\n");
3351.1Srkujawa		sysmon_envsys_destroy(sc->sc_sme);
3361.1Srkujawa	}
3371.1Srkujawa}
3381.1Srkujawa
3391.1Srkujawastatic void
3401.1Srkujawamcp980x_envsys_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
3411.1Srkujawa{
3421.1Srkujawa	struct mcp980x_softc *sc = sme->sme_cookie;
3431.1Srkujawa
3441.1Srkujawa	mutex_enter(&sc->sc_lock);
3451.1Srkujawa
3461.1Srkujawa	edata->value_cur = mcp980x_temperature(sc);
3471.1Srkujawa	edata->state = ENVSYS_SVALID;
3481.1Srkujawa
3491.1Srkujawa	mutex_exit(&sc->sc_lock);
3501.1Srkujawa}
3511.2Srkujawa
3521.2Srkujawastatic void
3531.2Srkujawamcp980x_setup_sysctl(struct mcp980x_softc *sc)
3541.2Srkujawa{
3551.2Srkujawa	const struct sysctlnode *me = NULL, *node = NULL;
3561.2Srkujawa
3571.2Srkujawa	sysctl_createv(NULL, 0, NULL, &me,
3581.2Srkujawa	    CTLFLAG_READWRITE,
3591.2Srkujawa	    CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
3601.2Srkujawa	    NULL, 0, NULL, 0,
3611.2Srkujawa	    CTL_MACHDEP, CTL_CREATE, CTL_EOL);
3621.2Srkujawa
3631.2Srkujawa	sysctl_createv(NULL, 0, NULL, &node,
3641.2Srkujawa	    CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
3651.2Srkujawa	    CTLTYPE_INT, "res", "Resolution",
3661.2Srkujawa	    sysctl_mcp980x_res, 1, (void *)sc, 0,
3671.2Srkujawa	    CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
3681.2Srkujawa
3691.4Srkujawa	sysctl_createv(NULL, 0, NULL, &node,
3701.4Srkujawa	    CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
3711.4Srkujawa	    CTLTYPE_INT, "hysteresis", "Temperature hysteresis",
3721.4Srkujawa	    sysctl_mcp980x_hysteresis, 1, (void *)sc, 0,
3731.4Srkujawa	    CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
3741.4Srkujawa
3751.4Srkujawa	sysctl_createv(NULL, 0, NULL, &node,
3761.4Srkujawa	    CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
3771.4Srkujawa	    CTLTYPE_INT, "templimit", "Temperature limit",
3781.4Srkujawa	    sysctl_mcp980x_templimit, 1, (void *)sc, 0,
3791.4Srkujawa	    CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
3801.2Srkujawa}
3811.2Srkujawa
3821.2Srkujawa
3831.5SrkujawaSYSCTL_SETUP(sysctl_mcp980x_setup, "sysctl mcp980x subtree setup")
3841.2Srkujawa{
3851.2Srkujawa	sysctl_createv(NULL, 0, NULL, NULL, CTLFLAG_PERMANENT,
3861.2Srkujawa	    CTLTYPE_NODE, "machdep", NULL, NULL, 0, NULL, 0,
3871.2Srkujawa	    CTL_MACHDEP, CTL_EOL);
3881.2Srkujawa}
3891.2Srkujawa
3901.2Srkujawa
3911.2Srkujawastatic int
3921.2Srkujawasysctl_mcp980x_res(SYSCTLFN_ARGS)
3931.2Srkujawa{
3941.2Srkujawa	struct sysctlnode node = *rnode;
3951.2Srkujawa	struct mcp980x_softc *sc = node.sysctl_data;
3961.3Srkujawa	int newres, err;
3971.3Srkujawa
3981.3Srkujawa	node.sysctl_data = &sc->sc_res;
3991.3Srkujawa	if ((err = (sysctl_lookup(SYSCTLFN_CALL(&node)))) != 0)
4001.3Srkujawa		return err;
4011.2Srkujawa
4021.2Srkujawa	if (newp) {
4031.3Srkujawa		newres = *(int *)node.sysctl_data;
4041.3Srkujawa		if (newres > MCP980X_CONFIG_ADC_RES_12BIT)
4051.3Srkujawa			return EINVAL;
4061.3Srkujawa		sc->sc_res = (uint8_t) newres;
4071.3Srkujawa		mcp980x_resolution_set(sc, sc->sc_res);
4081.3Srkujawa		return 0;
4091.2Srkujawa	} else {
4101.2Srkujawa		sc->sc_res = mcp980x_resolution_get(sc);
4111.2Srkujawa		node.sysctl_size = 4;
4121.2Srkujawa	}
4131.2Srkujawa
4141.3Srkujawa	return err;
4151.2Srkujawa}
4161.2Srkujawa
4171.4Srkujawastatic int
4181.4Srkujawasysctl_mcp980x_hysteresis(SYSCTLFN_ARGS)
4191.4Srkujawa{
4201.4Srkujawa	struct sysctlnode node = *rnode;
4211.4Srkujawa	struct mcp980x_softc *sc = node.sysctl_data;
4221.4Srkujawa	int newhyst, err;
4231.4Srkujawa
4241.4Srkujawa	node.sysctl_data = &sc->sc_hyst;
4251.4Srkujawa	if ((err = (sysctl_lookup(SYSCTLFN_CALL(&node)))) != 0)
4261.4Srkujawa		return err;
4271.4Srkujawa
4281.4Srkujawa	if (newp) {
4291.4Srkujawa		newhyst = *(int *)node.sysctl_data;
4301.4Srkujawa		sc->sc_hyst = newhyst;
4311.4Srkujawa		mcp980x_hysteresis_set(sc, sc->sc_hyst);
4321.4Srkujawa		return 0;
4331.4Srkujawa	} else {
4341.4Srkujawa		sc->sc_hyst = mcp980x_hysteresis_get(sc);
4351.4Srkujawa		node.sysctl_size = 4;
4361.4Srkujawa	}
4371.4Srkujawa
4381.4Srkujawa	return err;
4391.4Srkujawa}
4401.4Srkujawa
4411.4Srkujawastatic int
4421.4Srkujawasysctl_mcp980x_templimit(SYSCTLFN_ARGS)
4431.4Srkujawa{
4441.4Srkujawa	struct sysctlnode node = *rnode;
4451.4Srkujawa	struct mcp980x_softc *sc = node.sysctl_data;
4461.4Srkujawa	int newlimit, err;
4471.4Srkujawa
4481.4Srkujawa	node.sysctl_data = &sc->sc_limit;
4491.4Srkujawa	if ((err = (sysctl_lookup(SYSCTLFN_CALL(&node)))) != 0)
4501.4Srkujawa		return err;
4511.4Srkujawa
4521.4Srkujawa	if (newp) {
4531.4Srkujawa		newlimit = *(int *)node.sysctl_data;
4541.4Srkujawa		sc->sc_limit = newlimit;
4551.4Srkujawa		mcp980x_templimit_set(sc, sc->sc_limit);
4561.4Srkujawa		return 0;
4571.4Srkujawa	} else {
4581.4Srkujawa		sc->sc_limit = mcp980x_templimit_get(sc);
4591.4Srkujawa		node.sysctl_size = 4;
4601.4Srkujawa	}
4611.4Srkujawa
4621.4Srkujawa	return err;
4631.4Srkujawa}
4641.4Srkujawa
465