Home | History | Annotate | Line # | Download | only in i2c
      1 /*	$NetBSD: mcp980x.c,v 1.9 2026/10/13 08:16:44 rkujawa Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2013 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Radoslaw Kujawa.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Microchip MCP9800/1/2/3 2-Wire High-Accuracy Temperature Sensor driver.
     34  *
     35  * TODO: better error checking, particularly in user settable limits.
     36  *
     37  * Note: MCP9805 is different and is supported by the sdtemp(4) driver.
     38  */
     39 
     40 #include <sys/cdefs.h>
     41 __KERNEL_RCSID(0, "$NetBSD: mcp980x.c,v 1.9 2026/10/13 08:16:44 rkujawa Exp $");
     42 
     43 #include <sys/param.h>
     44 #include <sys/systm.h>
     45 #include <sys/device.h>
     46 #include <sys/kernel.h>
     47 #include <sys/mutex.h>
     48 #include <sys/endian.h>
     49 #include <sys/sysctl.h>
     50 
     51 #include <sys/bus.h>
     52 #include <dev/i2c/i2cvar.h>
     53 
     54 #include <dev/sysmon/sysmonvar.h>
     55 
     56 #include <dev/i2c/mcp980xreg.h>
     57 
     58 struct mcp980x_softc {
     59 	device_t		sc_dev;
     60 
     61 	i2c_tag_t		sc_tag;
     62 	i2c_addr_t		sc_addr;
     63 
     64 	int			sc_res;
     65 	int			sc_hyst;
     66 	int			sc_limit;
     67 
     68 	/* envsys(4) stuff */
     69 	struct sysmon_envsys	*sc_sme;
     70 	envsys_data_t		sc_sensor;
     71 	kmutex_t		sc_lock;
     72 };
     73 
     74 
     75 static int mcp980x_match(device_t, cfdata_t, void *);
     76 static void mcp980x_attach(device_t, device_t, void *);
     77 
     78 static uint8_t mcp980x_reg_read_1(struct mcp980x_softc *, uint8_t);
     79 static uint16_t mcp980x_reg_read_2(struct mcp980x_softc *, uint8_t);
     80 static void mcp980x_reg_write_1(struct mcp980x_softc *, uint8_t, uint8_t);
     81 
     82 static uint8_t mcp980x_resolution_get(struct mcp980x_softc *);
     83 static void mcp980x_resolution_set(struct mcp980x_softc *, uint8_t);
     84 
     85 static int8_t mcp980x_hysteresis_get(struct mcp980x_softc *);
     86 static void mcp980x_hysteresis_set(struct mcp980x_softc *, int8_t);
     87 static int8_t mcp980x_templimit_get(struct mcp980x_softc *);
     88 static void mcp980x_templimit_set(struct mcp980x_softc *, int8_t);
     89 
     90 static int8_t mcp980x_s8b_get(struct mcp980x_softc *, uint8_t);
     91 static void mcp980x_s8b_set(struct mcp980x_softc *, uint8_t, int8_t);
     92 
     93 static uint32_t mcp980x_temperature(struct mcp980x_softc *);
     94 
     95 static void mcp980x_envsys_register(struct mcp980x_softc *);
     96 static void mcp980x_envsys_refresh(struct sysmon_envsys *, envsys_data_t *);
     97 
     98 static void mcp980x_setup_sysctl(struct mcp980x_softc *);
     99 static int sysctl_mcp980x_res(SYSCTLFN_ARGS);
    100 static int sysctl_mcp980x_hysteresis(SYSCTLFN_ARGS);
    101 static int sysctl_mcp980x_templimit(SYSCTLFN_ARGS);
    102 
    103 CFATTACH_DECL_NEW(mcp980x, sizeof (struct mcp980x_softc),
    104     mcp980x_match, mcp980x_attach, NULL, NULL);
    105 
    106 static int
    107 mcp980x_match(device_t parent, cfdata_t cf, void *aux)
    108 {
    109 	struct i2c_attach_args *ia = aux;
    110 
    111 	if (ia->ia_addr >= MCP980X_ADDR_CONST &&
    112 	    ia->ia_addr <= (MCP980X_ADDR_CONST + MCP980X_ADDR_VAR))
    113 		return I2C_MATCH_ADDRESS_ONLY;
    114 
    115 	return 0;
    116 }
    117 
    118 static void
    119 mcp980x_attach(device_t parent, device_t self, void *aux)
    120 {
    121 	struct mcp980x_softc *sc = device_private(self);
    122 	struct i2c_attach_args *ia = aux;
    123 
    124 	sc->sc_dev = self;
    125 	sc->sc_addr = ia->ia_addr;
    126 	sc->sc_tag = ia->ia_tag;
    127 
    128 	aprint_normal(": Microchip MCP980x Temperature Sensor\n");
    129 
    130 	sc->sc_res = MCP980X_CONFIG_ADC_RES_12BIT;
    131 	mcp980x_resolution_set(sc, sc->sc_res);
    132 
    133 	sc->sc_hyst = mcp980x_hysteresis_get(sc);
    134 	sc->sc_limit = mcp980x_templimit_get(sc);
    135 
    136 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
    137 
    138 	mcp980x_setup_sysctl(sc);
    139 	mcp980x_envsys_register(sc);
    140 }
    141 
    142 static uint16_t
    143 mcp980x_reg_read_2(struct mcp980x_softc *sc, uint8_t reg)
    144 {
    145 	uint16_t rv;
    146 
    147 	if (iic_acquire_bus(sc->sc_tag, 0) != 0) {
    148 		aprint_error_dev(sc->sc_dev, "cannot acquire bus for read\n");
    149 		return 0;
    150 	}
    151 
    152 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &reg,
    153 	    1, &rv, 2, 0)) {
    154 		iic_release_bus(sc->sc_tag, 0);
    155 		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
    156 		return 0;
    157 	}
    158 	iic_release_bus(sc->sc_tag, 0);
    159 
    160 	return be16toh(rv);
    161 }
    162 
    163 static uint8_t
    164 mcp980x_reg_read_1(struct mcp980x_softc *sc, uint8_t reg)
    165 {
    166 	uint8_t rv;
    167 
    168 	if (iic_acquire_bus(sc->sc_tag, 0) != 0) {
    169 		aprint_error_dev(sc->sc_dev, "cannot acquire bus for read\n");
    170 		return 0;
    171 	}
    172 
    173 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &reg,
    174 	    1, &rv, 1, 0)) {
    175 		iic_release_bus(sc->sc_tag, 0);
    176 		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
    177 		return 0;
    178 	}
    179 	iic_release_bus(sc->sc_tag, 0);
    180 
    181 	return rv;
    182 }
    183 
    184 static void
    185 mcp980x_reg_write_2(struct mcp980x_softc *sc, uint8_t reg, uint16_t val)
    186 {
    187 	uint16_t beval;
    188 
    189 	beval = htobe16(val);
    190 
    191         if (iic_acquire_bus(sc->sc_tag, 0) != 0) {
    192 		aprint_error_dev(sc->sc_dev, "cannot acquire bus for write\n");
    193 		return;
    194 	}
    195 
    196         if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, &reg,
    197 	    1, &beval, 2, 0)) {
    198 		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
    199         }
    200 
    201 	iic_release_bus(sc->sc_tag, 0);
    202 
    203 }
    204 
    205 static void
    206 mcp980x_reg_write_1(struct mcp980x_softc *sc, uint8_t reg, uint8_t val)
    207 {
    208         if (iic_acquire_bus(sc->sc_tag, 0) != 0) {
    209 		aprint_error_dev(sc->sc_dev, "cannot acquire bus for write\n");
    210 		return;
    211 	}
    212 
    213         if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, &reg,
    214 	    1, &val, 1, 0)) {
    215 		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
    216         }
    217 
    218 	iic_release_bus(sc->sc_tag, 0);
    219 
    220 }
    221 
    222 static int8_t
    223 mcp980x_templimit_get(struct mcp980x_softc *sc)
    224 {
    225 	return mcp980x_s8b_get(sc, MCP980X_TEMP_LIMIT);
    226 }
    227 
    228 static void
    229 mcp980x_templimit_set(struct mcp980x_softc *sc, int8_t val)
    230 {
    231 	mcp980x_s8b_set(sc, MCP980X_TEMP_LIMIT, val);
    232 }
    233 
    234 static int8_t
    235 mcp980x_hysteresis_get(struct mcp980x_softc *sc)
    236 {
    237 	return mcp980x_s8b_get(sc, MCP980X_TEMP_HYSTERESIS);
    238 }
    239 
    240 static void
    241 mcp980x_hysteresis_set(struct mcp980x_softc *sc, int8_t val)
    242 {
    243 	mcp980x_s8b_set(sc, MCP980X_TEMP_HYSTERESIS, val);
    244 }
    245 
    246 static int8_t
    247 mcp980x_s8b_get(struct mcp980x_softc *sc, uint8_t reg)
    248 {
    249 	return mcp980x_reg_read_2(sc, reg) >> MCP980X_TEMP_HYSTLIMIT_INT_SHIFT;
    250 }
    251 
    252 static void
    253 mcp980x_s8b_set(struct mcp980x_softc *sc, uint8_t reg, int8_t val)
    254 {
    255 	mcp980x_reg_write_2(sc, reg, val << MCP980X_TEMP_HYSTLIMIT_INT_SHIFT);
    256 }
    257 
    258 static uint8_t
    259 mcp980x_resolution_get(struct mcp980x_softc *sc)
    260 {
    261 	uint8_t cfg, res;
    262 
    263 	cfg = mcp980x_reg_read_1(sc, MCP980X_CONFIG);
    264 	res = (cfg & MCP980X_CONFIG_ADC_RES) >>
    265 	    MCP980X_CONFIG_ADC_RES_SHIFT;
    266 
    267 	return res;
    268 }
    269 
    270 static void
    271 mcp980x_resolution_set(struct mcp980x_softc *sc, uint8_t res)
    272 {
    273 	uint8_t cfg;
    274 
    275 	/* read config register but discard resolution bits */
    276 	cfg = mcp980x_reg_read_1(sc, MCP980X_CONFIG) & ~MCP980X_CONFIG_ADC_RES;
    277 	/* set resolution bits to new value */
    278 	cfg |= res << MCP980X_CONFIG_ADC_RES_SHIFT;
    279 
    280 	mcp980x_reg_write_1(sc, MCP980X_CONFIG, cfg);
    281 }
    282 
    283 /* Get temperature in microKelvins. */
    284 static uint32_t
    285 mcp980x_temperature(struct mcp980x_softc *sc)
    286 {
    287 	uint16_t raw;
    288 	uint32_t rv, uk, basedegc;
    289 
    290 	raw = mcp980x_reg_read_2(sc, MCP980X_AMBIENT_TEMP);
    291 
    292 	basedegc = (raw & MCP980X_AMBIENT_TEMP_DEGREES) >>
    293 	    MCP980X_AMBIENT_TEMP_DEGREES_SHIFT;
    294 
    295 	uk = 1000000 * basedegc;
    296 
    297 	if (raw & MCP980X_AMBIENT_TEMP_05DEGREE)
    298 		uk += 500000;
    299 	if (raw & MCP980X_AMBIENT_TEMP_025DEGREE)
    300 		uk += 250000;
    301 	if (raw & MCP980X_AMBIENT_TEMP_0125DEGREE)
    302 		uk += 125000;
    303 	if (raw & MCP980X_AMBIENT_TEMP_00625DEGREE)
    304 		uk += 62500;
    305 
    306 	if (raw & MCP980X_AMBIENT_TEMP_SIGN)
    307 		rv = 273150000U - uk;
    308 	else
    309 		rv = 273150000U + uk;
    310 
    311 	return rv;
    312 }
    313 
    314 static void
    315 mcp980x_envsys_register(struct mcp980x_softc *sc)
    316 {
    317 	sc->sc_sme = sysmon_envsys_create();
    318 
    319 	strlcpy(sc->sc_sensor.desc, "Ambient temp",
    320 	    sizeof(sc->sc_sensor.desc));
    321 	sc->sc_sensor.units = ENVSYS_STEMP;
    322 	sc->sc_sensor.state = ENVSYS_SINVALID;
    323 
    324 	if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) {
    325 		aprint_error_dev(sc->sc_dev,
    326 		    "error attaching sensor\n");
    327 		return;
    328 	}
    329 
    330 	sc->sc_sme->sme_name = device_xname(sc->sc_dev);
    331 	sc->sc_sme->sme_cookie = sc;
    332 	sc->sc_sme->sme_refresh = mcp980x_envsys_refresh;
    333 
    334 	if (sysmon_envsys_register(sc->sc_sme)) {
    335 		aprint_error_dev(sc->sc_dev, "unable to register in sysmon\n");
    336 		sysmon_envsys_destroy(sc->sc_sme);
    337 	}
    338 }
    339 
    340 static void
    341 mcp980x_envsys_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
    342 {
    343 	struct mcp980x_softc *sc = sme->sme_cookie;
    344 
    345 	mutex_enter(&sc->sc_lock);
    346 
    347 	edata->value_cur = mcp980x_temperature(sc);
    348 	edata->state = ENVSYS_SVALID;
    349 
    350 	mutex_exit(&sc->sc_lock);
    351 }
    352 
    353 static void
    354 mcp980x_setup_sysctl(struct mcp980x_softc *sc)
    355 {
    356 	const struct sysctlnode *me = NULL, *node = NULL;
    357 
    358 	sysctl_createv(NULL, 0, NULL, &me,
    359 	    CTLFLAG_READWRITE,
    360 	    CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
    361 	    NULL, 0, NULL, 0,
    362 	    CTL_MACHDEP, CTL_CREATE, CTL_EOL);
    363 
    364 	sysctl_createv(NULL, 0, NULL, &node,
    365 	    CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
    366 	    CTLTYPE_INT, "res", "Resolution",
    367 	    sysctl_mcp980x_res, 1, (void *)sc, 0,
    368 	    CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
    369 
    370 	sysctl_createv(NULL, 0, NULL, &node,
    371 	    CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
    372 	    CTLTYPE_INT, "hysteresis", "Temperature hysteresis",
    373 	    sysctl_mcp980x_hysteresis, 1, (void *)sc, 0,
    374 	    CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
    375 
    376 	sysctl_createv(NULL, 0, NULL, &node,
    377 	    CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
    378 	    CTLTYPE_INT, "templimit", "Temperature limit",
    379 	    sysctl_mcp980x_templimit, 1, (void *)sc, 0,
    380 	    CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
    381 }
    382 
    383 
    384 SYSCTL_SETUP(sysctl_mcp980x_setup, "sysctl mcp980x subtree setup")
    385 {
    386 	sysctl_createv(NULL, 0, NULL, NULL, CTLFLAG_PERMANENT,
    387 	    CTLTYPE_NODE, "machdep", NULL, NULL, 0, NULL, 0,
    388 	    CTL_MACHDEP, CTL_EOL);
    389 }
    390 
    391 
    392 static int
    393 sysctl_mcp980x_res(SYSCTLFN_ARGS)
    394 {
    395 	struct sysctlnode node = *rnode;
    396 	struct mcp980x_softc *sc = node.sysctl_data;
    397 	int newres, err;
    398 
    399 	node.sysctl_data = &sc->sc_res;
    400 	if ((err = (sysctl_lookup(SYSCTLFN_CALL(&node)))) != 0)
    401 		return err;
    402 
    403 	if (newp) {
    404 		newres = *(int *)node.sysctl_data;
    405 		if (newres > MCP980X_CONFIG_ADC_RES_12BIT)
    406 			return EINVAL;
    407 		sc->sc_res = (uint8_t) newres;
    408 		mcp980x_resolution_set(sc, sc->sc_res);
    409 		return 0;
    410 	} else {
    411 		sc->sc_res = mcp980x_resolution_get(sc);
    412 		node.sysctl_size = 4;
    413 	}
    414 
    415 	return err;
    416 }
    417 
    418 static int
    419 sysctl_mcp980x_hysteresis(SYSCTLFN_ARGS)
    420 {
    421 	struct sysctlnode node = *rnode;
    422 	struct mcp980x_softc *sc = node.sysctl_data;
    423 	int newhyst, err;
    424 
    425 	node.sysctl_data = &sc->sc_hyst;
    426 	if ((err = (sysctl_lookup(SYSCTLFN_CALL(&node)))) != 0)
    427 		return err;
    428 
    429 	if (newp) {
    430 		newhyst = *(int *)node.sysctl_data;
    431 		sc->sc_hyst = newhyst;
    432 		mcp980x_hysteresis_set(sc, sc->sc_hyst);
    433 		return 0;
    434 	} else {
    435 		sc->sc_hyst = mcp980x_hysteresis_get(sc);
    436 		node.sysctl_size = 4;
    437 	}
    438 
    439 	return err;
    440 }
    441 
    442 static int
    443 sysctl_mcp980x_templimit(SYSCTLFN_ARGS)
    444 {
    445 	struct sysctlnode node = *rnode;
    446 	struct mcp980x_softc *sc = node.sysctl_data;
    447 	int newlimit, err;
    448 
    449 	node.sysctl_data = &sc->sc_limit;
    450 	if ((err = (sysctl_lookup(SYSCTLFN_CALL(&node)))) != 0)
    451 		return err;
    452 
    453 	if (newp) {
    454 		newlimit = *(int *)node.sysctl_data;
    455 		sc->sc_limit = newlimit;
    456 		mcp980x_templimit_set(sc, sc->sc_limit);
    457 		return 0;
    458 	} else {
    459 		sc->sc_limit = mcp980x_templimit_get(sc);
    460 		node.sysctl_size = 4;
    461 	}
    462 
    463 	return err;
    464 }
    465 
    466