1 /* $OpenBSD: lis331dl.c,v 1.1 2009/08/12 14:51:20 cnst Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru> 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 /* 27 * STMicroelectronics LIS331DL 28 * MEMS motion sensor 29 * http://www.stm.com/stonline/products/literature/ds/13951.pdf 30 * April 2008 31 */ 32 33 /* 3-axis accelerometer */ 34 #define LISA_NUM_AXIS 3 35 static const struct { 36 const char *name; 37 const uint8_t reg; 38 } lisa_axis[LISA_NUM_AXIS] = { 39 { "OUT_X", 0x29 }, 40 { "OUT_Y", 0x2b }, 41 { "OUT_Z", 0x2d } 42 }; 43 44 struct lisa_softc { 45 struct device sc_dev; 46 i2c_tag_t sc_tag; 47 i2c_addr_t sc_addr; 48 49 struct ksensor sc_sensors[LISA_NUM_AXIS]; 50 struct ksensordev sc_sensordev; 51 }; 52 53 54 int lisa_match(struct device *, void *, void *); 55 void lisa_attach(struct device *, struct device *, void *); 56 void lisa_refresh(void *); 57 58 uint8_t lisa_readreg(struct lisa_softc *, uint8_t); 59 void lisa_writereg(struct lisa_softc *, uint8_t, uint8_t); 60 61 62 struct cfattach lisa_ca = { 63 sizeof(struct lisa_softc), lisa_match, lisa_attach 64 }; 65 66 struct cfdriver lisa_cd = { 67 NULL, "lisa", DV_DULL 68 }; 69 70 71 int 72 lisa_match(struct device *parent, void *match, void *aux) 73 { 74 struct i2c_attach_args *ia = aux; 75 76 if (strcmp(ia->ia_name, "lis331dl") == 0) 77 return 1; 78 return 0; 79 } 80 81 void 82 lisa_attach(struct device *parent, struct device *self, void *aux) 83 { 84 struct lisa_softc *sc = (struct lisa_softc *)self; 85 struct i2c_attach_args *ia = aux; 86 int i; 87 88 sc->sc_tag = ia->ia_tag; 89 sc->sc_addr = ia->ia_addr; 90 91 printf(": %s", ia->ia_name); 92 93 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 94 sizeof(sc->sc_sensordev.xname)); 95 96 for (i = 0; i < LISA_NUM_AXIS; i++) { 97 strlcpy(sc->sc_sensors[i].desc, lisa_axis[i].name, 98 sizeof(sc->sc_sensors[i].desc)); 99 sc->sc_sensors[i].type = SENSOR_INTEGER; 100 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]); 101 } 102 103 if (sensor_task_register(sc, lisa_refresh, 1) == NULL) { 104 printf(", unable to register update task\n"); 105 return; 106 } 107 108 sensordev_install(&sc->sc_sensordev); 109 printf("\n"); 110 } 111 112 void 113 lisa_refresh(void *arg) 114 { 115 struct lisa_softc *sc = arg; 116 struct ksensor *s = sc->sc_sensors; 117 int i; 118 119 iic_acquire_bus(sc->sc_tag, 0); 120 for (i = 0; i < LISA_NUM_AXIS; i++) 121 s[i].value = (int8_t)lisa_readreg(sc, lisa_axis[i].reg); 122 iic_release_bus(sc->sc_tag, 0); 123 } 124 125 uint8_t 126 lisa_readreg(struct lisa_softc *sc, uint8_t reg) 127 { 128 uint8_t data; 129 130 iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 131 sc->sc_addr, ®, sizeof reg, &data, sizeof data, 0); 132 133 return data; 134 } 135 136 void 137 lisa_writereg(struct lisa_softc *sc, uint8_t reg, uint8_t data) 138 { 139 iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 140 sc->sc_addr, ®, sizeof reg, &data, sizeof data, 0); 141 } 142