mcp980x.c revision 1.3
11.3Srkujawa/*	$NetBSD: mcp980x.c,v 1.3 2013/10/15 10:27:55 rkujawa 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.1Srkujawa * Note: MCP9805 is different and is supported by the sdtemp(4) driver.
361.1Srkujawa */
371.1Srkujawa
381.1Srkujawa#include <sys/cdefs.h>
391.3Srkujawa__KERNEL_RCSID(0, "$NetBSD: mcp980x.c,v 1.3 2013/10/15 10:27:55 rkujawa Exp $");
401.1Srkujawa
411.1Srkujawa#include <sys/param.h>
421.1Srkujawa#include <sys/systm.h>
431.1Srkujawa#include <sys/device.h>
441.1Srkujawa#include <sys/kernel.h>
451.1Srkujawa#include <sys/mutex.h>
461.1Srkujawa#include <sys/endian.h>
471.2Srkujawa#include <sys/sysctl.h>
481.1Srkujawa
491.1Srkujawa#include <sys/bus.h>
501.1Srkujawa#include <dev/i2c/i2cvar.h>
511.1Srkujawa
521.1Srkujawa#include <dev/sysmon/sysmonvar.h>
531.1Srkujawa
541.1Srkujawa#include <dev/i2c/mcp980xreg.h>
551.1Srkujawa
561.1Srkujawastruct mcp980x_softc {
571.1Srkujawa	device_t		sc_dev;
581.1Srkujawa
591.1Srkujawa	i2c_tag_t		sc_tag;
601.1Srkujawa	i2c_addr_t		sc_addr;
611.1Srkujawa
621.2Srkujawa	int			sc_res;
631.2Srkujawa
641.1Srkujawa	/* envsys(4) stuff */
651.1Srkujawa	struct sysmon_envsys	*sc_sme;
661.1Srkujawa	envsys_data_t		sc_sensor;
671.1Srkujawa	kmutex_t		sc_lock;
681.1Srkujawa};
691.1Srkujawa
701.1Srkujawa
711.1Srkujawastatic int mcp980x_match(device_t, cfdata_t, void *);
721.1Srkujawastatic void mcp980x_attach(device_t, device_t, void *);
731.1Srkujawa
741.2Srkujawastatic uint8_t mcp980x_reg_read_1(struct mcp980x_softc *, uint8_t);
751.2Srkujawastatic uint16_t mcp980x_reg_read_2(struct mcp980x_softc *, uint8_t);
761.2Srkujawastatic void mcp980x_reg_write_1(struct mcp980x_softc *, uint8_t, uint8_t);
771.2Srkujawa
781.2Srkujawastatic uint8_t mcp980x_resolution_get(struct mcp980x_softc *);
791.2Srkujawastatic void mcp980x_resolution_set(struct mcp980x_softc *, uint8_t);
801.1Srkujawa
811.2Srkujawastatic uint32_t mcp980x_temperature(struct mcp980x_softc *);
821.1Srkujawa
831.1Srkujawastatic void mcp980x_envsys_register(struct mcp980x_softc *);
841.1Srkujawastatic void mcp980x_envsys_refresh(struct sysmon_envsys *, envsys_data_t *);
851.1Srkujawa
861.2Srkujawastatic void mcp980x_setup_sysctl(struct mcp980x_softc *);
871.2Srkujawastatic int sysctl_mcp980x_res(SYSCTLFN_ARGS);
881.2Srkujawa
891.1SrkujawaCFATTACH_DECL_NEW(mcp980x, sizeof (struct mcp980x_softc),
901.1Srkujawa    mcp980x_match, mcp980x_attach, NULL, NULL);
911.1Srkujawa
921.1Srkujawastatic int
931.1Srkujawamcp980x_match(device_t parent, cfdata_t cf, void *aux)
941.1Srkujawa{
951.1Srkujawa	/*
961.1Srkujawa	 * No sane way to probe? Perhaps at least try to match constant part
971.1Srkujawa	 * of the I2Caddress.
981.1Srkujawa	 */
991.1Srkujawa
1001.1Srkujawa	return 1;
1011.1Srkujawa}
1021.1Srkujawa
1031.1Srkujawastatic void
1041.1Srkujawamcp980x_attach(device_t parent, device_t self, void *aux)
1051.1Srkujawa{
1061.1Srkujawa	struct mcp980x_softc *sc = device_private(self);
1071.1Srkujawa	struct i2c_attach_args *ia = aux;
1081.1Srkujawa
1091.1Srkujawa	sc->sc_dev = self;
1101.1Srkujawa	sc->sc_addr = ia->ia_addr;
1111.1Srkujawa	sc->sc_tag = ia->ia_tag;
1121.1Srkujawa
1131.1Srkujawa	aprint_normal(": Microchip MCP980x Temperature Sensor\n");
1141.1Srkujawa
1151.2Srkujawa	sc->sc_res = MCP980X_CONFIG_ADC_RES_12BIT;
1161.2Srkujawa	mcp980x_resolution_set(sc, sc->sc_res);
1171.2Srkujawa
1181.1Srkujawa	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
1191.1Srkujawa
1201.2Srkujawa	mcp980x_setup_sysctl(sc);
1211.1Srkujawa	mcp980x_envsys_register(sc);
1221.1Srkujawa}
1231.1Srkujawa
1241.1Srkujawastatic uint16_t
1251.1Srkujawamcp980x_reg_read_2(struct mcp980x_softc *sc, uint8_t reg)
1261.1Srkujawa{
1271.1Srkujawa	uint16_t rv;
1281.1Srkujawa
1291.1Srkujawa	if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL) != 0) {
1301.1Srkujawa		aprint_error_dev(sc->sc_dev, "cannot acquire bus for read\n");
1311.1Srkujawa		return 0;
1321.1Srkujawa	}
1331.1Srkujawa
1341.2Srkujawa	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &reg,
1351.1Srkujawa	    1, &rv, 2, I2C_F_POLL)) {
1361.1Srkujawa		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
1371.1Srkujawa		iic_release_bus(sc->sc_tag, I2C_F_POLL);
1381.1Srkujawa		return 0;
1391.1Srkujawa	}
1401.1Srkujawa	iic_release_bus(sc->sc_tag, I2C_F_POLL);
1411.1Srkujawa
1421.1Srkujawa	return be16toh(rv);
1431.1Srkujawa}
1441.1Srkujawa
1451.1Srkujawastatic uint8_t
1461.1Srkujawamcp980x_reg_read_1(struct mcp980x_softc *sc, uint8_t reg)
1471.1Srkujawa{
1481.2Srkujawa	uint8_t rv;
1491.1Srkujawa
1501.1Srkujawa	if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL) != 0) {
1511.1Srkujawa		aprint_error_dev(sc->sc_dev, "cannot acquire bus for read\n");
1521.1Srkujawa		return 0;
1531.1Srkujawa	}
1541.1Srkujawa
1551.2Srkujawa	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &reg,
1561.1Srkujawa	    1, &rv, 1, I2C_F_POLL)) {
1571.1Srkujawa		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
1581.1Srkujawa		iic_release_bus(sc->sc_tag, I2C_F_POLL);
1591.1Srkujawa		return 0;
1601.1Srkujawa	}
1611.1Srkujawa	iic_release_bus(sc->sc_tag, I2C_F_POLL);
1621.1Srkujawa
1631.1Srkujawa	return rv;
1641.2Srkujawa}
1651.2Srkujawa
1661.2Srkujawastatic void
1671.2Srkujawamcp980x_reg_write_1(struct mcp980x_softc *sc, uint8_t reg, uint8_t val)
1681.2Srkujawa{
1691.2Srkujawa        if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL) != 0) {
1701.2Srkujawa		aprint_error_dev(sc->sc_dev, "cannot acquire bus for write\n");
1711.2Srkujawa		return;
1721.2Srkujawa	}
1731.2Srkujawa
1741.2Srkujawa        if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, &reg,
1751.2Srkujawa	    1, &val, 1, I2C_F_POLL)) {
1761.2Srkujawa		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
1771.2Srkujawa        }
1781.2Srkujawa
1791.2Srkujawa	iic_release_bus(sc->sc_tag, I2C_F_POLL);
1801.2Srkujawa
1811.2Srkujawa}
1821.2Srkujawa
1831.2Srkujawastatic uint8_t
1841.2Srkujawamcp980x_resolution_get(struct mcp980x_softc *sc)
1851.2Srkujawa{
1861.2Srkujawa	uint8_t cfg, res;
1871.2Srkujawa
1881.2Srkujawa	cfg = mcp980x_reg_read_1(sc, MCP980X_CONFIG);
1891.2Srkujawa	res = (cfg & MCP980X_CONFIG_ADC_RES) >>
1901.2Srkujawa	    MCP980X_CONFIG_ADC_RES_SHIFT;
1911.2Srkujawa
1921.2Srkujawa	return res;
1931.2Srkujawa}
1941.2Srkujawa
1951.2Srkujawastatic void
1961.2Srkujawamcp980x_resolution_set(struct mcp980x_softc *sc, uint8_t res)
1971.2Srkujawa{
1981.2Srkujawa	uint8_t cfg;
1991.2Srkujawa
2001.2Srkujawa	/* read config register but discard resolution bits */
2011.2Srkujawa	cfg = mcp980x_reg_read_1(sc, MCP980X_CONFIG) & ~MCP980X_CONFIG_ADC_RES;
2021.2Srkujawa	/* set resolution bits to new value */
2031.2Srkujawa	cfg |= res << MCP980X_CONFIG_ADC_RES_SHIFT;
2041.2Srkujawa
2051.2Srkujawa	mcp980x_reg_write_1(sc, MCP980X_CONFIG, cfg);
2061.2Srkujawa}
2071.1Srkujawa
2081.1Srkujawa/* Get temperature in microKelvins. */
2091.1Srkujawastatic uint32_t
2101.1Srkujawamcp980x_temperature(struct mcp980x_softc *sc)
2111.1Srkujawa{
2121.1Srkujawa	uint16_t raw;
2131.1Srkujawa	uint32_t rv, uk, basedegc;
2141.1Srkujawa
2151.1Srkujawa	raw = mcp980x_reg_read_2(sc, MCP980X_AMBIENT_TEMP);
2161.1Srkujawa
2171.1Srkujawa	basedegc = (raw & MCP980X_AMBIENT_TEMP_DEGREES) >>
2181.1Srkujawa	    MCP980X_AMBIENT_TEMP_DEGREES_SHIFT;
2191.1Srkujawa
2201.1Srkujawa	uk = 1000000 * basedegc;
2211.1Srkujawa
2221.1Srkujawa	if (raw & MCP980X_AMBIENT_TEMP_05DEGREE)
2231.1Srkujawa		uk += 500000;
2241.1Srkujawa	if (raw & MCP980X_AMBIENT_TEMP_025DEGREE)
2251.1Srkujawa		uk += 250000;
2261.1Srkujawa	if (raw & MCP980X_AMBIENT_TEMP_0125DEGREE)
2271.1Srkujawa		uk += 125000;
2281.1Srkujawa	if (raw & MCP980X_AMBIENT_TEMP_00625DEGREE)
2291.1Srkujawa		uk += 62500;
2301.1Srkujawa
2311.1Srkujawa	if (raw & MCP980X_AMBIENT_TEMP_SIGN)
2321.1Srkujawa		rv = 273150000U - uk;
2331.1Srkujawa	else
2341.1Srkujawa		rv = 273150000U + uk;
2351.1Srkujawa
2361.1Srkujawa	return rv;
2371.1Srkujawa}
2381.1Srkujawa
2391.1Srkujawastatic void
2401.1Srkujawamcp980x_envsys_register(struct mcp980x_softc *sc)
2411.1Srkujawa{
2421.1Srkujawa	sc->sc_sme = sysmon_envsys_create();
2431.1Srkujawa
2441.1Srkujawa	strlcpy(sc->sc_sensor.desc, "Ambient temp",
2451.1Srkujawa	    sizeof(sc->sc_sensor.desc));
2461.1Srkujawa	sc->sc_sensor.units = ENVSYS_STEMP;
2471.1Srkujawa	sc->sc_sensor.state = ENVSYS_SINVALID;
2481.1Srkujawa
2491.1Srkujawa	if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) {
2501.1Srkujawa		aprint_error_dev(sc->sc_dev,
2511.1Srkujawa		    "error attaching sensor\n");
2521.1Srkujawa		return;
2531.1Srkujawa	}
2541.1Srkujawa
2551.1Srkujawa	sc->sc_sme->sme_name = device_xname(sc->sc_dev);
2561.1Srkujawa	sc->sc_sme->sme_cookie = sc;
2571.1Srkujawa	sc->sc_sme->sme_refresh = mcp980x_envsys_refresh;
2581.1Srkujawa
2591.1Srkujawa	if (sysmon_envsys_register(sc->sc_sme)) {
2601.1Srkujawa		aprint_error_dev(sc->sc_dev, "unable to register in sysmon\n");
2611.1Srkujawa		sysmon_envsys_destroy(sc->sc_sme);
2621.1Srkujawa	}
2631.1Srkujawa}
2641.1Srkujawa
2651.1Srkujawastatic void
2661.1Srkujawamcp980x_envsys_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
2671.1Srkujawa{
2681.1Srkujawa	struct mcp980x_softc *sc = sme->sme_cookie;
2691.1Srkujawa
2701.1Srkujawa	mutex_enter(&sc->sc_lock);
2711.1Srkujawa
2721.1Srkujawa	edata->value_cur = mcp980x_temperature(sc);
2731.1Srkujawa	edata->state = ENVSYS_SVALID;
2741.1Srkujawa
2751.1Srkujawa	mutex_exit(&sc->sc_lock);
2761.1Srkujawa}
2771.2Srkujawa
2781.2Srkujawastatic void
2791.2Srkujawamcp980x_setup_sysctl(struct mcp980x_softc *sc)
2801.2Srkujawa{
2811.2Srkujawa	const struct sysctlnode *me = NULL, *node = NULL;
2821.2Srkujawa
2831.2Srkujawa	sysctl_createv(NULL, 0, NULL, &me,
2841.2Srkujawa	    CTLFLAG_READWRITE,
2851.2Srkujawa	    CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
2861.2Srkujawa	    NULL, 0, NULL, 0,
2871.2Srkujawa	    CTL_MACHDEP, CTL_CREATE, CTL_EOL);
2881.2Srkujawa
2891.2Srkujawa	sysctl_createv(NULL, 0, NULL, &node,
2901.2Srkujawa	    CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
2911.2Srkujawa	    CTLTYPE_INT, "res", "Resolution",
2921.2Srkujawa	    sysctl_mcp980x_res, 1, (void *)sc, 0,
2931.2Srkujawa	    CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
2941.2Srkujawa
2951.2Srkujawa}
2961.2Srkujawa
2971.2Srkujawa
2981.2SrkujawaSYSCTL_SETUP(sysctl_lmtemp_setup, "sysctl mcp980x subtree setup")
2991.2Srkujawa{
3001.2Srkujawa	sysctl_createv(NULL, 0, NULL, NULL, CTLFLAG_PERMANENT,
3011.2Srkujawa	    CTLTYPE_NODE, "machdep", NULL, NULL, 0, NULL, 0,
3021.2Srkujawa	    CTL_MACHDEP, CTL_EOL);
3031.2Srkujawa}
3041.2Srkujawa
3051.2Srkujawa
3061.2Srkujawastatic int
3071.2Srkujawasysctl_mcp980x_res(SYSCTLFN_ARGS)
3081.2Srkujawa{
3091.2Srkujawa	struct sysctlnode node = *rnode;
3101.2Srkujawa	struct mcp980x_softc *sc = node.sysctl_data;
3111.3Srkujawa	int newres, err;
3121.3Srkujawa
3131.3Srkujawa	node.sysctl_data = &sc->sc_res;
3141.3Srkujawa	if ((err = (sysctl_lookup(SYSCTLFN_CALL(&node)))) != 0)
3151.3Srkujawa		return err;
3161.2Srkujawa
3171.2Srkujawa	if (newp) {
3181.3Srkujawa		newres = *(int *)node.sysctl_data;
3191.3Srkujawa		if (newres > MCP980X_CONFIG_ADC_RES_12BIT)
3201.3Srkujawa			return EINVAL;
3211.3Srkujawa		sc->sc_res = (uint8_t) newres;
3221.3Srkujawa		mcp980x_resolution_set(sc, sc->sc_res);
3231.3Srkujawa		return 0;
3241.2Srkujawa	} else {
3251.2Srkujawa		sc->sc_res = mcp980x_resolution_get(sc);
3261.2Srkujawa		node.sysctl_size = 4;
3271.2Srkujawa	}
3281.2Srkujawa
3291.3Srkujawa	return err;
3301.2Srkujawa}
3311.2Srkujawa
332