bmx280thpspi.c revision 1.5
1/* $NetBSD: bmx280thpspi.c,v 1.5 2025/09/13 14:10:44 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.5 2025/09/13 14:10:44 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 45/* 46 * XXX Should add configuration information for variants ... 47 * XXX E devices have humidity sensors, P devices do not. 48 */ 49static const struct device_compatible_entry compat_data[] = { 50 { .compat = "bosch,bmp280" }, 51 { .compat = "bosch,bme280" }, 52#if 0 53 /* 54 * XXX Should also add support for: 55 * bosch,bmp085 56 * bosch,bmp180 57 * bosch,bmp380 58 * bosch,bmp580 59 */ 60#endif 61 DEVICE_COMPAT_EOL 62}; 63 64extern void bmx280_attach(struct bmx280_sc *); 65 66static int bmx280thpspi_match(device_t, cfdata_t, void *); 67static void bmx280thpspi_attach(device_t, device_t, void *); 68static int bmx280thpspi_detach(device_t, int); 69 70#define BMX280_DEBUG 71#ifdef BMX280_DEBUG 72#define DPRINTF(s, l, x) \ 73 do { \ 74 if (l <= s->sc_bmx280debug) \ 75 printf x; \ 76 } while (/*CONSTCOND*/0) 77#else 78#define DPRINTF(s, l, x) 79#endif 80 81CFATTACH_DECL_NEW(bmx280thpspi, sizeof(struct bmx280_sc), 82 bmx280thpspi_match, bmx280thpspi_attach, bmx280thpspi_detach, NULL); 83 84/* The SPI interface of the chip, assuming that it has managed to get into that 85 * mode to start with, is pretty simple. Simply send the register MINUS the 7th 86 * bit which will be 1 and then do as many reads as you want. The chip will 87 * auto increment for you. 88 * 89 * The delays are only hinted at in the data sheet. 90 */ 91 92static int 93bmx280thpspi_read_reg_direct(spi_handle_t sh, uint8_t reg, 94 uint8_t *buf, size_t rlen) 95{ 96 int err = 0; 97 uint8_t rreg = reg | 0x80; 98 99 if (buf != NULL) { 100 err = spi_send_recv(sh, 1, &rreg, 101 rlen, buf); 102 } else { 103 err = spi_send(sh, 1, &rreg); 104 } 105 106 return err; 107} 108 109static int 110bmx280thpspi_read_reg(struct bmx280_sc *sc, uint8_t reg, uint8_t *buf, size_t rlen) 111{ 112 return bmx280thpspi_read_reg_direct(sc->sc_sh, reg, buf, rlen); 113} 114 115/* SPI writes to this device are normal enough. You send the register 116 * you want making sure that the high bit, 0x80, is clear and then the 117 * data. These pairs can be repeated as many times as you like. 118 */ 119static int 120bmx280thpspi_write_reg_direct(spi_handle_t sh, uint8_t *buf, size_t slen) 121{ 122 int err = 0; 123 int i; 124 125 /* XXX - 126 this is probably BAD thing to do... but we must insure that the 127 registers have a cleared bit.. otherwise it is a read .... 128 */ 129 130 for(i = 0; i < slen;i+=2) { 131 buf[i] = buf[i] & 0x7F; 132 } 133 134 err = spi_send(sh, slen, buf); 135 136 return err; 137} 138 139static int 140bmx280thpspi_write_reg(struct bmx280_sc *sc, uint8_t *buf, size_t slen) 141{ 142 return bmx280thpspi_write_reg_direct(sc->sc_sh, buf, slen); 143} 144 145/* These are to satisfy the common code */ 146static int 147bmx280thpspi_acquire_bus(struct bmx280_sc *sc) 148{ 149 return 0; 150} 151 152static void 153bmx280thpspi_release_bus(struct bmx280_sc *sc) 154{ 155 return; 156} 157 158/* Nothing more is done here. Assumptions on whether or not 159 * the SPI interface is set up may not be proper.... for better 160 * or worse... and there is setting that are needed such as the 161 * SPI mode and bus speed that really should not be done here, so 162 * any active match might not work anyway. 163 */ 164static int 165bmx280thpspi_match(device_t parent, cfdata_t match, void *aux) 166{ 167 struct spi_attach_args *sa = aux; 168 int match_result; 169 170 if (spi_use_direct_match(sa, compat_data, &match_result)) { 171 return match_result; 172 } 173 174 return SPI_MATCH_DEFAULT; 175} 176 177static void 178bmx280thpspi_attach(device_t parent, device_t self, void *aux) 179{ 180 struct bmx280_sc *sc; 181 struct spi_attach_args *sa; 182 int error; 183 184 sa = aux; 185 sc = device_private(self); 186 187 sc->sc_dev = self; 188 sc->sc_sh = sa->sa_handle; 189 sc->sc_bmx280debug = 0; 190 sc->sc_func_acquire_bus = &bmx280thpspi_acquire_bus; 191 sc->sc_func_release_bus = &bmx280thpspi_release_bus; 192 sc->sc_func_read_register = &bmx280thpspi_read_reg; 193 sc->sc_func_write_register = &bmx280thpspi_write_reg; 194 195 /* Configure for 1MHz and SPI mode 0 according to the data sheet. 196 * The chip will actually handle a number of different modes and 197 * can go a lot faster, just use this for now... 198 */ 199 error = spi_configure(self, sa->sa_handle, SPI_MODE_0, SPI_FREQ_MHz(1)); 200 if (error) { 201 return; 202 } 203 204 /* 205 * XXX Need to get this data from the device tree: 206 * 207 * vddd-supply (a regulator) 208 * vdda-supply (a regulator) 209 * reset-gpios (a gpio, active-low reset) 210 */ 211 212 /* Please note that if the pins are not set up for SPI, the attachment 213 * will probably not work out. 214 */ 215 bmx280_attach(sc); 216 217 return; 218} 219 220/* These really do not do a whole lot, as SPI devices do not seem to work 221 * as modules. 222 */ 223static int 224bmx280thpspi_detach(device_t self, int flags) 225{ 226 struct bmx280_sc *sc; 227 228 sc = device_private(self); 229 230 mutex_destroy(&sc->sc_mutex); 231 232 return 0; 233} 234