bmx280thpspi.c revision 1.6
11.6Sthorpej/* $NetBSD: bmx280thpspi.c,v 1.6 2025/09/13 15:55:45 thorpej Exp $ */ 21.1Sbrad 31.1Sbrad/* 41.1Sbrad * Copyright (c) 2022 Brad Spencer <brad@anduin.eldar.org> 51.1Sbrad * 61.1Sbrad * Permission to use, copy, modify, and distribute this software for any 71.1Sbrad * purpose with or without fee is hereby granted, provided that the above 81.1Sbrad * copyright notice and this permission notice appear in all copies. 91.1Sbrad * 101.1Sbrad * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 111.1Sbrad * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 121.1Sbrad * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 131.1Sbrad * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 141.1Sbrad * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 151.1Sbrad * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 161.1Sbrad * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 171.1Sbrad */ 181.1Sbrad 191.1Sbrad#include <sys/cdefs.h> 201.6Sthorpej__KERNEL_RCSID(0, "$NetBSD: bmx280thpspi.c,v 1.6 2025/09/13 15:55:45 thorpej Exp $"); 211.1Sbrad 221.1Sbrad/* 231.1Sbrad * SPI driver for the Bosch BMP280 / BME280 sensor. 241.1Sbrad * Uses the common bmx280thp driver to do the real work. 251.1Sbrad*/ 261.1Sbrad 271.1Sbrad#include <sys/param.h> 281.1Sbrad#include <sys/systm.h> 291.1Sbrad#include <sys/kernel.h> 301.1Sbrad#include <sys/device.h> 311.1Sbrad#include <sys/module.h> 321.1Sbrad#include <sys/conf.h> 331.1Sbrad#include <sys/sysctl.h> 341.1Sbrad#include <sys/mutex.h> 351.1Sbrad#include <sys/condvar.h> 361.1Sbrad#include <sys/pool.h> 371.1Sbrad#include <sys/kmem.h> 381.1Sbrad 391.1Sbrad#include <dev/sysmon/sysmonvar.h> 401.1Sbrad#include <dev/i2c/i2cvar.h> 411.1Sbrad#include <dev/spi/spivar.h> 421.1Sbrad#include <dev/ic/bmx280reg.h> 431.1Sbrad#include <dev/ic/bmx280var.h> 441.1Sbrad 451.6Sthorpejstruct bmx280_spi_softc { 461.6Sthorpej struct bmx280_sc sc_bmx280; 471.6Sthorpej spi_handle_t sc_sh; 481.6Sthorpej}; 491.6Sthorpej 501.6Sthorpej#define BMX280_TO_SPI(sc) \ 511.6Sthorpej container_of((sc), struct bmx280_spi_softc, sc_bmx280) 521.6Sthorpej 531.4Sthorpejstatic const struct device_compatible_entry compat_data[] = { 541.4Sthorpej { .compat = "bosch,bmp280" }, 551.4Sthorpej { .compat = "bosch,bme280" }, 561.4Sthorpej#if 0 571.4Sthorpej /* 581.4Sthorpej * XXX Should also add support for: 591.4Sthorpej * bosch,bmp085 601.4Sthorpej * bosch,bmp180 611.4Sthorpej * bosch,bmp380 621.4Sthorpej * bosch,bmp580 631.4Sthorpej */ 641.4Sthorpej#endif 651.4Sthorpej DEVICE_COMPAT_EOL 661.4Sthorpej}; 671.4Sthorpej 681.1Sbradstatic int bmx280thpspi_match(device_t, cfdata_t, void *); 691.1Sbradstatic void bmx280thpspi_attach(device_t, device_t, void *); 701.1Sbradstatic int bmx280thpspi_detach(device_t, int); 711.1Sbrad 721.1Sbrad#define BMX280_DEBUG 731.1Sbrad#ifdef BMX280_DEBUG 741.1Sbrad#define DPRINTF(s, l, x) \ 751.1Sbrad do { \ 761.1Sbrad if (l <= s->sc_bmx280debug) \ 771.1Sbrad printf x; \ 781.1Sbrad } while (/*CONSTCOND*/0) 791.1Sbrad#else 801.1Sbrad#define DPRINTF(s, l, x) 811.1Sbrad#endif 821.1Sbrad 831.6SthorpejCFATTACH_DECL_NEW(bmx280thpspi, sizeof(struct bmx280_spi_softc), 841.1Sbrad bmx280thpspi_match, bmx280thpspi_attach, bmx280thpspi_detach, NULL); 851.1Sbrad 861.1Sbrad/* The SPI interface of the chip, assuming that it has managed to get into that 871.1Sbrad * mode to start with, is pretty simple. Simply send the register MINUS the 7th 881.1Sbrad * bit which will be 1 and then do as many reads as you want. The chip will 891.1Sbrad * auto increment for you. 901.1Sbrad * 911.1Sbrad * The delays are only hinted at in the data sheet. 921.1Sbrad */ 931.1Sbrad 941.1Sbradstatic int 951.6Sthorpejbmx280thpspi_read_reg_direct(spi_handle_t sh, uint8_t reg, uint8_t *buf, 961.6Sthorpej size_t rlen) 971.1Sbrad{ 981.1Sbrad int err = 0; 991.1Sbrad uint8_t rreg = reg | 0x80; 1001.1Sbrad 1011.1Sbrad if (buf != NULL) { 1021.1Sbrad err = spi_send_recv(sh, 1, &rreg, 1031.1Sbrad rlen, buf); 1041.1Sbrad } else { 1051.1Sbrad err = spi_send(sh, 1, &rreg); 1061.1Sbrad } 1071.1Sbrad 1081.1Sbrad return err; 1091.1Sbrad} 1101.1Sbrad 1111.1Sbradstatic int 1121.6Sthorpejbmx280thpspi_read_reg(struct bmx280_sc *sc, uint8_t reg, uint8_t *buf, 1131.6Sthorpej size_t rlen) 1141.1Sbrad{ 1151.6Sthorpej struct bmx280_spi_softc *ssc = BMX280_TO_SPI(sc); 1161.6Sthorpej 1171.6Sthorpej return bmx280thpspi_read_reg_direct(ssc->sc_sh, reg, buf, rlen); 1181.1Sbrad} 1191.1Sbrad 1201.1Sbrad/* SPI writes to this device are normal enough. You send the register 1211.1Sbrad * you want making sure that the high bit, 0x80, is clear and then the 1221.1Sbrad * data. These pairs can be repeated as many times as you like. 1231.1Sbrad */ 1241.1Sbradstatic int 1251.5Sthorpejbmx280thpspi_write_reg_direct(spi_handle_t sh, uint8_t *buf, size_t slen) 1261.1Sbrad{ 1271.1Sbrad int err = 0; 1281.1Sbrad int i; 1291.1Sbrad 1301.1Sbrad /* XXX - 1311.1Sbrad this is probably BAD thing to do... but we must insure that the 1321.1Sbrad registers have a cleared bit.. otherwise it is a read .... 1331.1Sbrad */ 1341.1Sbrad 1351.1Sbrad for(i = 0; i < slen;i+=2) { 1361.1Sbrad buf[i] = buf[i] & 0x7F; 1371.1Sbrad } 1381.1Sbrad 1391.1Sbrad err = spi_send(sh, slen, buf); 1401.1Sbrad 1411.1Sbrad return err; 1421.1Sbrad} 1431.1Sbrad 1441.1Sbradstatic int 1451.1Sbradbmx280thpspi_write_reg(struct bmx280_sc *sc, uint8_t *buf, size_t slen) 1461.1Sbrad{ 1471.6Sthorpej struct bmx280_spi_softc *ssc = BMX280_TO_SPI(sc); 1481.6Sthorpej 1491.6Sthorpej return bmx280thpspi_write_reg_direct(ssc->sc_sh, buf, slen); 1501.1Sbrad} 1511.1Sbrad 1521.1Sbrad/* These are to satisfy the common code */ 1531.1Sbradstatic int 1541.6Sthorpejbmx280thpspi_acquire_bus(struct bmx280_sc *sc __unused) 1551.1Sbrad{ 1561.1Sbrad return 0; 1571.1Sbrad} 1581.1Sbrad 1591.1Sbradstatic void 1601.6Sthorpejbmx280thpspi_release_bus(struct bmx280_sc *sc __unused) 1611.1Sbrad{ 1621.1Sbrad return; 1631.1Sbrad} 1641.1Sbrad 1651.6Sthorpejstatic const struct bmx280_accessfuncs bmx280_spi_accessfuncs = { 1661.6Sthorpej .acquire_bus = bmx280thpspi_acquire_bus, 1671.6Sthorpej .release_bus = bmx280thpspi_release_bus, 1681.6Sthorpej .read_reg = bmx280thpspi_read_reg, 1691.6Sthorpej .write_reg = bmx280thpspi_write_reg, 1701.6Sthorpej}; 1711.6Sthorpej 1721.1Sbrad/* Nothing more is done here. Assumptions on whether or not 1731.1Sbrad * the SPI interface is set up may not be proper.... for better 1741.1Sbrad * or worse... and there is setting that are needed such as the 1751.1Sbrad * SPI mode and bus speed that really should not be done here, so 1761.1Sbrad * any active match might not work anyway. 1771.1Sbrad */ 1781.1Sbradstatic int 1791.1Sbradbmx280thpspi_match(device_t parent, cfdata_t match, void *aux) 1801.1Sbrad{ 1811.4Sthorpej struct spi_attach_args *sa = aux; 1821.4Sthorpej int match_result; 1831.1Sbrad 1841.4Sthorpej if (spi_use_direct_match(sa, compat_data, &match_result)) { 1851.4Sthorpej return match_result; 1861.1Sbrad } 1871.1Sbrad 1881.3Sthorpej return SPI_MATCH_DEFAULT; 1891.1Sbrad} 1901.1Sbrad 1911.1Sbradstatic void 1921.1Sbradbmx280thpspi_attach(device_t parent, device_t self, void *aux) 1931.1Sbrad{ 1941.6Sthorpej struct bmx280_spi_softc *ssc = device_private(self); 1951.6Sthorpej struct bmx280_sc *sc = &ssc->sc_bmx280; 1961.6Sthorpej struct spi_attach_args *sa = aux; 1971.1Sbrad int error; 1981.1Sbrad 1991.6Sthorpej sc->sc_dev = self; 2001.6Sthorpej sc->sc_funcs = &bmx280_spi_accessfuncs; 2011.6Sthorpej 2021.6Sthorpej ssc->sc_sh = sa->sa_handle; 2031.1Sbrad 2041.1Sbrad sc->sc_bmx280debug = 0; 2051.1Sbrad 2061.1Sbrad /* Configure for 1MHz and SPI mode 0 according to the data sheet. 2071.1Sbrad * The chip will actually handle a number of different modes and 2081.1Sbrad * can go a lot faster, just use this for now... 2091.1Sbrad */ 2101.2Sthorpej error = spi_configure(self, sa->sa_handle, SPI_MODE_0, SPI_FREQ_MHz(1)); 2111.1Sbrad if (error) { 2121.1Sbrad return; 2131.1Sbrad } 2141.1Sbrad 2151.4Sthorpej /* 2161.4Sthorpej * XXX Need to get this data from the device tree: 2171.4Sthorpej * 2181.4Sthorpej * vddd-supply (a regulator) 2191.4Sthorpej * vdda-supply (a regulator) 2201.4Sthorpej * reset-gpios (a gpio, active-low reset) 2211.4Sthorpej */ 2221.4Sthorpej 2231.1Sbrad /* Please note that if the pins are not set up for SPI, the attachment 2241.1Sbrad * will probably not work out. 2251.1Sbrad */ 2261.1Sbrad bmx280_attach(sc); 2271.1Sbrad} 2281.1Sbrad 2291.1Sbrad/* These really do not do a whole lot, as SPI devices do not seem to work 2301.1Sbrad * as modules. 2311.1Sbrad */ 2321.1Sbradstatic int 2331.1Sbradbmx280thpspi_detach(device_t self, int flags) 2341.1Sbrad{ 2351.1Sbrad struct bmx280_sc *sc; 2361.1Sbrad 2371.1Sbrad sc = device_private(self); 2381.1Sbrad 2391.1Sbrad mutex_destroy(&sc->sc_mutex); 2401.1Sbrad 2411.1Sbrad return 0; 2421.1Sbrad} 243