1 /* $OpenBSD: bmc150.c,v 1.2 2022/04/06 18:59:28 naddy Exp $ */
2
3 /*
4 * Copyright (c) 2017 Mark Kettenis
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/param.h>
20 #include <sys/systm.h>
21 #include <sys/device.h>
22 #include <sys/sensors.h>
23
24 #include <dev/i2c/i2cvar.h>
25
26 #define BGW_CHIPID 0x00
27 #define BGW_CHIPID_BMA222E 0xf8
28 #define BGW_CHIPID_BMA250E 0xf9
29 #define BGW_CHIPID_BMC150 0xfa
30 #define BGW_CHIPID_BMI055 0xfa
31 #define BGW_CHIPID_BMA255 0xfa
32 #define BGW_CHIPID_BMA280 0xfb
33 #define ACCD_X_LSB 0x02
34 #define ACCD_X_MSB 0x03
35 #define ACCD_Y_LSB 0x04
36 #define ACCD_Y_MSB 0x05
37 #define ACCD_Z_LSB 0x06
38 #define ACCD_Z_MSB 0x07
39 #define ACCD_TEMP 0x08
40
41 #define BGW_NUM_SENSORS 4
42
43 #define BGW_SENSOR_XACCEL 0
44 #define BGW_SENSOR_YACCEL 1
45 #define BGW_SENSOR_ZACCEL 2
46 #define BGW_SENSOR_TEMP 3
47
48 struct bgw_softc {
49 struct device sc_dev;
50 i2c_tag_t sc_tag;
51 i2c_addr_t sc_addr;
52
53 uint8_t sc_temp0;
54
55 struct ksensor sc_sensor[BGW_NUM_SENSORS];
56 struct ksensordev sc_sensordev;
57 };
58
59 int bgw_match(struct device *, void *, void *);
60 void bgw_attach(struct device *, struct device *, void *);
61
62 const struct cfattach bgw_ca = {
63 sizeof(struct bgw_softc), bgw_match, bgw_attach
64 };
65
66 struct cfdriver bgw_cd = {
67 NULL, "bgw", DV_DULL
68 };
69
70 void bgw_refresh(void *);
71
72 int
bgw_match(struct device * parent,void * match,void * aux)73 bgw_match(struct device *parent, void *match, void *aux)
74 {
75 struct i2c_attach_args *ia = aux;
76
77 if (strcmp(ia->ia_name, "BSBA0150") == 0 ||
78 strcmp(ia->ia_name, "BMC150A") == 0 ||
79 strcmp(ia->ia_name, "BMI055A") == 0 ||
80 strcmp(ia->ia_name, "BMA0255") == 0 ||
81 strcmp(ia->ia_name, "BMA250E") == 0 ||
82 strcmp(ia->ia_name, "BMA222E") == 0 ||
83 strcmp(ia->ia_name, "BMA0280") == 0 ||
84 strcmp(ia->ia_name, "BOSC0200") == 0)
85 return 1;
86 return 0;
87 }
88
89 void
bgw_attach(struct device * parent,struct device * self,void * aux)90 bgw_attach(struct device *parent, struct device *self, void *aux)
91 {
92 struct bgw_softc *sc = (struct bgw_softc *)self;
93 struct i2c_attach_args *ia = aux;
94 uint8_t cmd, data;
95 int i;
96
97 sc->sc_tag = ia->ia_tag;
98 sc->sc_addr = ia->ia_addr;
99
100 iic_acquire_bus(sc->sc_tag, 0);
101 cmd = BGW_CHIPID;
102 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
103 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
104 iic_release_bus(sc->sc_tag, 0);
105 printf(": can't read chip ID\n");
106 return;
107 }
108 iic_release_bus(sc->sc_tag, 0);
109
110 switch (data) {
111 case BGW_CHIPID_BMA222E:
112 sc->sc_temp0 = 23;
113 printf(": BMA222E");
114 break;
115 case BGW_CHIPID_BMA250E:
116 sc->sc_temp0 = 23;
117 printf(": BMA250E");
118 break;
119 case BGW_CHIPID_BMC150:
120 sc->sc_temp0 = 24;
121 printf(": BMC150");
122 break;
123 case BGW_CHIPID_BMA280:
124 sc->sc_temp0 = 23;
125 printf(": BMA280");
126 break;
127 }
128
129 sc->sc_sensor[BGW_SENSOR_XACCEL].type = SENSOR_INTEGER;
130 strlcpy(sc->sc_sensor[BGW_SENSOR_XACCEL].desc, "X_ACCEL",
131 sizeof(sc->sc_sensor[BGW_SENSOR_XACCEL].desc));
132 sc->sc_sensor[BGW_SENSOR_YACCEL].type = SENSOR_INTEGER;
133 strlcpy(sc->sc_sensor[BGW_SENSOR_YACCEL].desc, "Y_ACCEL",
134 sizeof(sc->sc_sensor[BGW_SENSOR_YACCEL].desc));
135 sc->sc_sensor[BGW_SENSOR_ZACCEL].type = SENSOR_INTEGER;
136 strlcpy(sc->sc_sensor[BGW_SENSOR_ZACCEL].desc, "Z_ACCEL",
137 sizeof(sc->sc_sensor[BGW_SENSOR_ZACCEL].desc));
138 sc->sc_sensor[BGW_SENSOR_TEMP].type = SENSOR_TEMP;
139
140 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
141 sizeof(sc->sc_sensordev.xname));
142 for (i = 0; i < BGW_NUM_SENSORS; i++)
143 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
144 sensordev_install(&sc->sc_sensordev);
145
146 if (sensor_task_register(sc, bgw_refresh, 5) == NULL) {
147 printf(", unable to register update task\n");
148 return;
149 }
150
151 printf("\n");
152 }
153
154 void
bgw_refresh(void * arg)155 bgw_refresh(void *arg)
156 {
157 struct bgw_softc *sc = arg;
158 uint8_t cmd, data[7];
159 uint8_t lsb;
160 int8_t msb;
161 int8_t temp;
162 int i;
163
164 iic_acquire_bus(sc->sc_tag, 0);
165 cmd = ACCD_X_LSB;
166 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
167 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
168 iic_release_bus(sc->sc_tag, 0);
169 for (i = 0; i < BGW_NUM_SENSORS; i++)
170 sc->sc_sensor[i].flags |= SENSOR_FINVALID;
171 return;
172 }
173 iic_release_bus(sc->sc_tag, 0);
174
175 lsb = data[ACCD_X_LSB - ACCD_X_LSB];
176 msb = data[ACCD_X_MSB - ACCD_X_LSB];
177 sc->sc_sensor[BGW_SENSOR_XACCEL].value = (msb << 4) | (lsb >> 4);
178 sc->sc_sensor[BGW_SENSOR_XACCEL].flags &= ~SENSOR_FINVALID;
179
180 lsb = data[ACCD_Y_LSB - ACCD_X_LSB];
181 msb = data[ACCD_Y_MSB - ACCD_X_LSB];
182 sc->sc_sensor[BGW_SENSOR_YACCEL].value = (msb << 4) | (lsb >> 4);
183 sc->sc_sensor[BGW_SENSOR_YACCEL].flags &= ~SENSOR_FINVALID;
184
185 lsb = data[ACCD_Z_LSB - ACCD_X_LSB];
186 msb = data[ACCD_Z_MSB - ACCD_X_LSB];
187 sc->sc_sensor[BGW_SENSOR_ZACCEL].value = (msb << 4) | (lsb >> 4);
188 sc->sc_sensor[BGW_SENSOR_ZACCEL].flags &= ~SENSOR_FINVALID;
189
190 temp = data[ACCD_TEMP - ACCD_X_LSB];
191 sc->sc_sensor[BGW_SENSOR_TEMP].value =
192 273150000 + (sc->sc_temp0 + temp) * 1000000;
193 sc->sc_sensor[BGW_SENSOR_TEMP].flags &= ~SENSOR_FINVALID;
194 }
195