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, ®, 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, ®, 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, ®, 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, ®, 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