bmx280thpspi.c revision 1.6
1/* $NetBSD: bmx280thpspi.c,v 1.6 2025/09/13 15:55:45 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 2022 Brad Spencer <brad@anduin.eldar.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/cdefs.h> 20__KERNEL_RCSID(0, "$NetBSD: bmx280thpspi.c,v 1.6 2025/09/13 15:55:45 thorpej Exp $"); 21 22/* 23 * SPI driver for the Bosch BMP280 / BME280 sensor. 24 * Uses the common bmx280thp driver to do the real work. 25*/ 26 27#include <sys/param.h> 28#include <sys/systm.h> 29#include <sys/kernel.h> 30#include <sys/device.h> 31#include <sys/module.h> 32#include <sys/conf.h> 33#include <sys/sysctl.h> 34#include <sys/mutex.h> 35#include <sys/condvar.h> 36#include <sys/pool.h> 37#include <sys/kmem.h> 38 39#include <dev/sysmon/sysmonvar.h> 40#include <dev/i2c/i2cvar.h> 41#include <dev/spi/spivar.h> 42#include <dev/ic/bmx280reg.h> 43#include <dev/ic/bmx280var.h> 44 45struct bmx280_spi_softc { 46 struct bmx280_sc sc_bmx280; 47 spi_handle_t sc_sh; 48}; 49 50#define BMX280_TO_SPI(sc) \ 51 container_of((sc), struct bmx280_spi_softc, sc_bmx280) 52 53static const struct device_compatible_entry compat_data[] = { 54 { .compat = "bosch,bmp280" }, 55 { .compat = "bosch,bme280" }, 56#if 0 57 /* 58 * XXX Should also add support for: 59 * bosch,bmp085 60 * bosch,bmp180 61 * bosch,bmp380 62 * bosch,bmp580 63 */ 64#endif 65 DEVICE_COMPAT_EOL 66}; 67 68static int bmx280thpspi_match(device_t, cfdata_t, void *); 69static void bmx280thpspi_attach(device_t, device_t, void *); 70static int bmx280thpspi_detach(device_t, int); 71 72#define BMX280_DEBUG 73#ifdef BMX280_DEBUG 74#define DPRINTF(s, l, x) \ 75 do { \ 76 if (l <= s->sc_bmx280debug) \ 77 printf x; \ 78 } while (/*CONSTCOND*/0) 79#else 80#define DPRINTF(s, l, x) 81#endif 82 83CFATTACH_DECL_NEW(bmx280thpspi, sizeof(struct bmx280_spi_softc), 84 bmx280thpspi_match, bmx280thpspi_attach, bmx280thpspi_detach, NULL); 85 86/* The SPI interface of the chip, assuming that it has managed to get into that 87 * mode to start with, is pretty simple. Simply send the register MINUS the 7th 88 * bit which will be 1 and then do as many reads as you want. The chip will 89 * auto increment for you. 90 * 91 * The delays are only hinted at in the data sheet. 92 */ 93 94static int 95bmx280thpspi_read_reg_direct(spi_handle_t sh, uint8_t reg, uint8_t *buf, 96 size_t rlen) 97{ 98 int err = 0; 99 uint8_t rreg = reg | 0x80; 100 101 if (buf != NULL) { 102 err = spi_send_recv(sh, 1, &rreg, 103 rlen, buf); 104 } else { 105 err = spi_send(sh, 1, &rreg); 106 } 107 108 return err; 109} 110 111static int 112bmx280thpspi_read_reg(struct bmx280_sc *sc, uint8_t reg, uint8_t *buf, 113 size_t rlen) 114{ 115 struct bmx280_spi_softc *ssc = BMX280_TO_SPI(sc); 116 117 return bmx280thpspi_read_reg_direct(ssc->sc_sh, reg, buf, rlen); 118} 119 120/* SPI writes to this device are normal enough. You send the register 121 * you want making sure that the high bit, 0x80, is clear and then the 122 * data. These pairs can be repeated as many times as you like. 123 */ 124static int 125bmx280thpspi_write_reg_direct(spi_handle_t sh, uint8_t *buf, size_t slen) 126{ 127 int err = 0; 128 int i; 129 130 /* XXX - 131 this is probably BAD thing to do... but we must insure that the 132 registers have a cleared bit.. otherwise it is a read .... 133 */ 134 135 for(i = 0; i < slen;i+=2) { 136 buf[i] = buf[i] & 0x7F; 137 } 138 139 err = spi_send(sh, slen, buf); 140 141 return err; 142} 143 144static int 145bmx280thpspi_write_reg(struct bmx280_sc *sc, uint8_t *buf, size_t slen) 146{ 147 struct bmx280_spi_softc *ssc = BMX280_TO_SPI(sc); 148 149 return bmx280thpspi_write_reg_direct(ssc->sc_sh, buf, slen); 150} 151 152/* These are to satisfy the common code */ 153static int 154bmx280thpspi_acquire_bus(struct bmx280_sc *sc __unused) 155{ 156 return 0; 157} 158 159static void 160bmx280thpspi_release_bus(struct bmx280_sc *sc __unused) 161{ 162 return; 163} 164 165static const struct bmx280_accessfuncs bmx280_spi_accessfuncs = { 166 .acquire_bus = bmx280thpspi_acquire_bus, 167 .release_bus = bmx280thpspi_release_bus, 168 .read_reg = bmx280thpspi_read_reg, 169 .write_reg = bmx280thpspi_write_reg, 170}; 171 172/* Nothing more is done here. Assumptions on whether or not 173 * the SPI interface is set up may not be proper.... for better 174 * or worse... and there is setting that are needed such as the 175 * SPI mode and bus speed that really should not be done here, so 176 * any active match might not work anyway. 177 */ 178static int 179bmx280thpspi_match(device_t parent, cfdata_t match, void *aux) 180{ 181 struct spi_attach_args *sa = aux; 182 int match_result; 183 184 if (spi_use_direct_match(sa, compat_data, &match_result)) { 185 return match_result; 186 } 187 188 return SPI_MATCH_DEFAULT; 189} 190 191static void 192bmx280thpspi_attach(device_t parent, device_t self, void *aux) 193{ 194 struct bmx280_spi_softc *ssc = device_private(self); 195 struct bmx280_sc *sc = &ssc->sc_bmx280; 196 struct spi_attach_args *sa = aux; 197 int error; 198 199 sc->sc_dev = self; 200 sc->sc_funcs = &bmx280_spi_accessfuncs; 201 202 ssc->sc_sh = sa->sa_handle; 203 204 sc->sc_bmx280debug = 0; 205 206 /* Configure for 1MHz and SPI mode 0 according to the data sheet. 207 * The chip will actually handle a number of different modes and 208 * can go a lot faster, just use this for now... 209 */ 210 error = spi_configure(self, sa->sa_handle, SPI_MODE_0, SPI_FREQ_MHz(1)); 211 if (error) { 212 return; 213 } 214 215 /* 216 * XXX Need to get this data from the device tree: 217 * 218 * vddd-supply (a regulator) 219 * vdda-supply (a regulator) 220 * reset-gpios (a gpio, active-low reset) 221 */ 222 223 /* Please note that if the pins are not set up for SPI, the attachment 224 * will probably not work out. 225 */ 226 bmx280_attach(sc); 227} 228 229/* These really do not do a whole lot, as SPI devices do not seem to work 230 * as modules. 231 */ 232static int 233bmx280thpspi_detach(device_t self, int flags) 234{ 235 struct bmx280_sc *sc; 236 237 sc = device_private(self); 238 239 mutex_destroy(&sc->sc_mutex); 240 241 return 0; 242} 243