1 /* $OpenBSD: bmc150.c,v 1.1 2017/11/30 14:53:21 kettenis 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 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 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 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 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