xref: /netbsd-src/sys/dev/spi/bmx280thpspi.c (revision 50bb9ed19fb685948d30ad3c7186b250d750fe26)
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
bmx280thpspi_read_reg_direct(struct spi_handle * sh,uint8_t reg,uint8_t * buf,size_t rlen)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
bmx280thpspi_read_reg(struct bmx280_sc * sc,uint8_t reg,uint8_t * buf,size_t rlen)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
bmx280thpspi_write_reg_direct(struct spi_handle * sh,uint8_t * buf,size_t slen)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
bmx280thpspi_write_reg(struct bmx280_sc * sc,uint8_t * buf,size_t slen)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
bmx280thpspi_acquire_bus(struct bmx280_sc * sc)128 bmx280thpspi_acquire_bus(struct bmx280_sc *sc)
129 {
130 	return 0;
131 }
132 
133 static void
bmx280thpspi_release_bus(struct bmx280_sc * sc)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
bmx280thpspi_match(device_t parent,cfdata_t match,void * aux)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
bmx280thpspi_attach(device_t parent,device_t self,void * aux)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
bmx280thpspi_detach(device_t self,int flags)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