xref: /openbsd/sys/dev/i2c/lis331dl.c (revision 76d0caae)
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, &reg, 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, &reg, sizeof reg, &data, sizeof data, 0);
141 }
142