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