xref: /openbsd-src/sys/arch/macppc/dev/asms.c (revision 98f1db2d6a6ef9f75ae8a63edcd242f476673a49)
1*98f1db2dSmiod /*	$OpenBSD: asms.c,v 1.9 2023/12/26 14:04:50 miod Exp $	*/
2bcec8f31Sxsa /*
3bcec8f31Sxsa  * Copyright (c) 2005 Xavier Santolaria <xsa@openbsd.org>
4bcec8f31Sxsa  *
5bcec8f31Sxsa  * Permission to use, copy, modify, and distribute this software for any
6bcec8f31Sxsa  * purpose with or without fee is hereby granted, provided that the above
7bcec8f31Sxsa  * copyright notice and this permission notice appear in all copies.
8bcec8f31Sxsa  *
9bcec8f31Sxsa  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10bcec8f31Sxsa  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11bcec8f31Sxsa  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12bcec8f31Sxsa  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13bcec8f31Sxsa  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14bcec8f31Sxsa  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15bcec8f31Sxsa  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16bcec8f31Sxsa  */
17bcec8f31Sxsa 
18bcec8f31Sxsa /*
19bcec8f31Sxsa  * A driver for the Apple Sudden Motion Sensor based on notes from
20*98f1db2dSmiod  * https://johannes.sipsolutions.net/PowerBook/apple-motion-sensor-specification
21bcec8f31Sxsa  */
22bcec8f31Sxsa 
23bcec8f31Sxsa #include <sys/param.h>
24bcec8f31Sxsa #include <sys/systm.h>
25bcec8f31Sxsa #include <sys/device.h>
26bcec8f31Sxsa #include <sys/sensors.h>
27bcec8f31Sxsa 
28bcec8f31Sxsa #include <dev/i2c/i2cvar.h>
29bcec8f31Sxsa 
30bcec8f31Sxsa /* ASMS Registers */
31bcec8f31Sxsa #define ASMS_REG_COMMAND	0x00
32bcec8f31Sxsa #define ASMS_REG_STATUS		0x01
33bcec8f31Sxsa #define ASMS_REG_RCONTROL1	0x02
34bcec8f31Sxsa #define ASMS_REG_RCONTROL2	0x03
35bcec8f31Sxsa #define ASMS_REG_RCONTROL3	0x04
36bcec8f31Sxsa #define ASMS_REG_RDATA1		0x05
37bcec8f31Sxsa #define ASMS_REG_RDATA2		0x06
38bcec8f31Sxsa #define ASMS_REG_DATA_X		0x20
39bcec8f31Sxsa #define ASMS_REG_DATA_Y		0x21
40bcec8f31Sxsa #define ASMS_REG_DATA_Z		0x22
41bcec8f31Sxsa #define ASMS_REG_SENS_LOW	0x26	/* init with 0x15 */
42bcec8f31Sxsa #define ASMS_REG_SENS_HIGH	0x27	/* init with 0x60 */
43bcec8f31Sxsa #define ASMS_REG_CONTROL_X	0x28	/* init with 0x08 */
44bcec8f31Sxsa #define ASMS_REG_CONTROL_Y	0x29	/* init with 0x0f */
45bcec8f31Sxsa #define ASMS_REG_CONTROL_Z	0x2a	/* init with 0x4f */
46bcec8f31Sxsa #define ASMS_REG_UNKNOWN1	0x2b	/* init with 0x14 */
47bcec8f31Sxsa #define ASMS_REG_VENDOR		0x2e
48bcec8f31Sxsa #define ASMS_CMD_READ_VER	0x01
49bcec8f31Sxsa #define ASMS_CMD_READ_MEM	0x02
50bcec8f31Sxsa #define ASMS_CMD_RESET		0x07
51bcec8f31Sxsa #define ASMS_CMD_START		0x08
52bcec8f31Sxsa 
53bcec8f31Sxsa /* Sensors */
54bcec8f31Sxsa #define ASMS_DATA_X		0
55bcec8f31Sxsa #define ASMS_DATA_Y		1
56bcec8f31Sxsa #define ASMS_DATA_Z		2
57bcec8f31Sxsa #define ASMS_NUM_SENSORS	3
58bcec8f31Sxsa 
59bcec8f31Sxsa struct asms_softc {
60bcec8f31Sxsa 	struct device	sc_dev;
61bcec8f31Sxsa 	i2c_tag_t	sc_tag;
62bcec8f31Sxsa 	i2c_addr_t	sc_addr;
63bcec8f31Sxsa 
64275cbf62Sderaadt 	struct ksensor	sc_sensor[ASMS_NUM_SENSORS];
65275cbf62Sderaadt 	struct ksensordev sc_sensordev;
66bcec8f31Sxsa };
67bcec8f31Sxsa 
68bcec8f31Sxsa int	asms_match(struct device *, void *, void *);
69bcec8f31Sxsa void	asms_attach(struct device *, struct device *, void *);
70bcec8f31Sxsa void	asms_refresh(void *);
71bcec8f31Sxsa 
7289ed722cSmpi const struct cfattach asms_ca = {
73bcec8f31Sxsa 	sizeof(struct asms_softc), asms_match, asms_attach
74bcec8f31Sxsa };
75bcec8f31Sxsa 
76bcec8f31Sxsa struct cfdriver asms_cd = {
77bcec8f31Sxsa 	NULL, "asms", DV_DULL
78bcec8f31Sxsa };
79bcec8f31Sxsa 
80bcec8f31Sxsa int
asms_match(struct device * parent,void * match,void * aux)81bcec8f31Sxsa asms_match(struct device *parent, void *match, void *aux)
82bcec8f31Sxsa {
83bcec8f31Sxsa 	struct i2c_attach_args *ia = aux;
84bcec8f31Sxsa 
85bcec8f31Sxsa 	if (strcmp(ia->ia_name, "AAPL,accelerometer_1") == 0)
86bcec8f31Sxsa 		return (1);
87bcec8f31Sxsa 	return (0);
88bcec8f31Sxsa }
89bcec8f31Sxsa 
90bcec8f31Sxsa void
asms_attach(struct device * parent,struct device * self,void * aux)91bcec8f31Sxsa asms_attach(struct device *parent, struct device *self, void *aux)
92bcec8f31Sxsa {
93bcec8f31Sxsa 	struct asms_softc *sc = (struct asms_softc *)self;
94bcec8f31Sxsa 	struct i2c_attach_args *ia = aux;
95aea9067dSxsa 	u_int8_t cmd, data, rev1, rev2, ver1, ver2;
96bcec8f31Sxsa 	int i, vflag = 0;
97bcec8f31Sxsa 
98bcec8f31Sxsa 	sc->sc_tag = ia->ia_tag;
99bcec8f31Sxsa 	sc->sc_addr = ia ->ia_addr;
100bcec8f31Sxsa 
101bcec8f31Sxsa 	iic_acquire_bus(sc->sc_tag, 0);
102bcec8f31Sxsa 
103bcec8f31Sxsa 	cmd = ASMS_REG_COMMAND; data = ASMS_CMD_START;
104bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
105bcec8f31Sxsa 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
106bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
107bcec8f31Sxsa 		printf(": cannot write command register\n");
108bcec8f31Sxsa 		return;
109bcec8f31Sxsa 	}
110bcec8f31Sxsa 	delay(10000);
111bcec8f31Sxsa 
112bcec8f31Sxsa 	cmd = ASMS_REG_RCONTROL1; data = 0x02;
113bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
114bcec8f31Sxsa 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
115bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
116bcec8f31Sxsa 		printf(": cannot write read control register\n");
117bcec8f31Sxsa 		return;
118bcec8f31Sxsa 	}
119bcec8f31Sxsa 
120bcec8f31Sxsa 	cmd = ASMS_REG_RCONTROL2; data = 0x85;
121bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
122bcec8f31Sxsa 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
123bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
124bcec8f31Sxsa 		printf(": cannot write read control register\n");
125bcec8f31Sxsa 		return;
126bcec8f31Sxsa 	}
127bcec8f31Sxsa 
128bcec8f31Sxsa 	cmd = ASMS_REG_RCONTROL3; data = 0x01;
129bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
130bcec8f31Sxsa 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
131bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
132bcec8f31Sxsa 		printf(": cannot write read control register\n");
133bcec8f31Sxsa 		return;
134bcec8f31Sxsa 	}
135bcec8f31Sxsa 
136bcec8f31Sxsa 	cmd = ASMS_REG_COMMAND; data = ASMS_CMD_READ_MEM;
137bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
138bcec8f31Sxsa 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
139bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
140bcec8f31Sxsa 		printf(": cannot write command register\n");
141bcec8f31Sxsa 		return;
142bcec8f31Sxsa 	}
143bcec8f31Sxsa 	delay(10000);
144bcec8f31Sxsa 
145bcec8f31Sxsa 	cmd = ASMS_REG_RDATA1;
146bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
147aea9067dSxsa 	    sc->sc_addr, &cmd, sizeof cmd, &rev1, sizeof rev1, 0)) {
148bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
149bcec8f31Sxsa 		printf(": cannot read data register\n");
150bcec8f31Sxsa 		return;
151bcec8f31Sxsa 	}
152bcec8f31Sxsa 
153bcec8f31Sxsa 	cmd = ASMS_REG_RDATA2;
154bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
155aea9067dSxsa 	    sc->sc_addr, &cmd, sizeof cmd, &rev2, sizeof rev2, 0)) {
156bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
157bcec8f31Sxsa 		printf(": cannot read data register\n");
158bcec8f31Sxsa 		return;
159bcec8f31Sxsa 	}
160bcec8f31Sxsa 
161bcec8f31Sxsa 	cmd = ASMS_REG_COMMAND; data = ASMS_CMD_READ_VER;
162bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
163bcec8f31Sxsa 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
164bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
165bcec8f31Sxsa 		printf(": cannot write command register\n");
166bcec8f31Sxsa 		return;
167bcec8f31Sxsa 	}
1688987106aSxsa 	delay(10000);
169bcec8f31Sxsa 
170bcec8f31Sxsa 	cmd = ASMS_REG_RDATA1;
171bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
172aea9067dSxsa 	    sc->sc_addr, &cmd, sizeof cmd, &ver1, sizeof ver1, 0)) {
173bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
174bcec8f31Sxsa 		printf(": cannot read data register\n");
175bcec8f31Sxsa 		return;
176bcec8f31Sxsa 	}
177bcec8f31Sxsa 
178bcec8f31Sxsa 	cmd = ASMS_REG_RDATA2;
179bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
180aea9067dSxsa 	    sc->sc_addr, &cmd, sizeof cmd, &ver2, sizeof ver2, 0)) {
181bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
182bcec8f31Sxsa 		printf(": cannot read data register\n");
183bcec8f31Sxsa 		return;
184bcec8f31Sxsa 	}
185bcec8f31Sxsa 
186bcec8f31Sxsa 	cmd = ASMS_REG_VENDOR;
187bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
188bcec8f31Sxsa 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
189bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
190bcec8f31Sxsa 		printf(": cannot read vendor register\n");
191bcec8f31Sxsa 		return;
192bcec8f31Sxsa 	}
193bcec8f31Sxsa 	if (data & 0x10)
194bcec8f31Sxsa 		vflag = 1;
195bcec8f31Sxsa 
196bcec8f31Sxsa 	cmd = ASMS_REG_SENS_LOW; data = 0x15;
197bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
198bcec8f31Sxsa 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
199bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
200bcec8f31Sxsa 		printf(": cannot write sensibility low register\n");
201bcec8f31Sxsa 		return;
202bcec8f31Sxsa 	}
203bcec8f31Sxsa 
204bcec8f31Sxsa 	cmd = ASMS_REG_SENS_HIGH; data = 0x60;
205bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
206bcec8f31Sxsa 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
207bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
208bcec8f31Sxsa 		printf(": cannot write sensibility high register\n");
209bcec8f31Sxsa 		return;
210bcec8f31Sxsa 	}
211bcec8f31Sxsa 
212bcec8f31Sxsa 	cmd = ASMS_REG_CONTROL_X; data = 0x08;
213bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
214bcec8f31Sxsa 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
215bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
216bcec8f31Sxsa 		printf(": cannot write control X register\n");
217bcec8f31Sxsa 		return;
218bcec8f31Sxsa 	}
219bcec8f31Sxsa 
220bcec8f31Sxsa 	cmd = ASMS_REG_CONTROL_Y; data= 0x0f;
221bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
222bcec8f31Sxsa 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
223bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
224bcec8f31Sxsa 		printf(": cannot write control Y register\n");
225bcec8f31Sxsa 		return;
226bcec8f31Sxsa 	}
227bcec8f31Sxsa 
228bcec8f31Sxsa 	cmd = ASMS_REG_CONTROL_Z; data = 0x4f;
229bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
230bcec8f31Sxsa 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
231bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
232bcec8f31Sxsa 		printf(": cannot write control Z register\n");
233bcec8f31Sxsa 		return;
234bcec8f31Sxsa 	}
235bcec8f31Sxsa 
236bcec8f31Sxsa 	cmd = ASMS_REG_UNKNOWN1; data = 0x14;
237bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
238bcec8f31Sxsa 	    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
239bcec8f31Sxsa 		iic_release_bus(sc->sc_tag, 0);
240bcec8f31Sxsa 		printf(": cannot write unknown 1 register\n");
241bcec8f31Sxsa 		return;
242bcec8f31Sxsa 	}
243bcec8f31Sxsa 
244bcec8f31Sxsa 	iic_release_bus(sc->sc_tag, 0);
245bcec8f31Sxsa 
246aea9067dSxsa 	printf(": rev %x.%x, version %x.%x", rev1, rev2, ver1, ver2);
247aea9067dSxsa 
248bcec8f31Sxsa 	/* Initialize sensor data. */
24927515a6bSderaadt 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
25027515a6bSderaadt 	    sizeof(sc->sc_sensordev.xname));
251bcec8f31Sxsa 
252bcec8f31Sxsa 	sc->sc_sensor[ASMS_DATA_X].type = SENSOR_INTEGER;
253bcec8f31Sxsa 	strlcpy(sc->sc_sensor[ASMS_DATA_X].desc, "X_ACCEL",
254bcec8f31Sxsa 	    sizeof(sc->sc_sensor[ASMS_DATA_X].desc));
255bcec8f31Sxsa 
256bcec8f31Sxsa 	sc->sc_sensor[ASMS_DATA_Y].type = SENSOR_INTEGER;
257bcec8f31Sxsa 	strlcpy(sc->sc_sensor[ASMS_DATA_Y].desc, "Y_ACCEL",
258bcec8f31Sxsa 	    sizeof(sc->sc_sensor[ASMS_DATA_Y].desc));
259bcec8f31Sxsa 
260bcec8f31Sxsa 	sc->sc_sensor[ASMS_DATA_Z].type = SENSOR_INTEGER;
261bcec8f31Sxsa 	strlcpy(sc->sc_sensor[ASMS_DATA_Z].desc, "Z_ACCEL",
262bcec8f31Sxsa 	    sizeof(sc->sc_sensor[ASMS_DATA_Z].desc));
263bcec8f31Sxsa 
264abd9fc28Sdlg 	if (sensor_task_register(sc, asms_refresh, 5) == NULL) {
265bcec8f31Sxsa 		printf(": unable to register update task\n");
266bcec8f31Sxsa 		return;
267bcec8f31Sxsa 	}
268bcec8f31Sxsa 
269bcec8f31Sxsa 	for (i = 0; i < ASMS_NUM_SENSORS; i++)
27027515a6bSderaadt 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
27127515a6bSderaadt 	sensordev_install(&sc->sc_sensordev);
272bcec8f31Sxsa 
273bcec8f31Sxsa 	printf("\n");
274bcec8f31Sxsa }
275bcec8f31Sxsa 
276bcec8f31Sxsa void
asms_refresh(void * arg)277bcec8f31Sxsa asms_refresh(void *arg)
278bcec8f31Sxsa {
279bcec8f31Sxsa 	struct asms_softc *sc = arg;
280bcec8f31Sxsa 	u_int8_t cmd;
281bcec8f31Sxsa 	int8_t sdata;
282bcec8f31Sxsa 
283bcec8f31Sxsa 	iic_acquire_bus(sc->sc_tag, 0);
284bcec8f31Sxsa 
285bcec8f31Sxsa 	cmd = ASMS_REG_DATA_X;
286bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
287bcec8f31Sxsa 	    sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0)
288bcec8f31Sxsa 		sc->sc_sensor[ASMS_DATA_X].value = sdata;
289bcec8f31Sxsa 
290bcec8f31Sxsa 	cmd = ASMS_REG_DATA_Y;
291bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
292bcec8f31Sxsa 	    sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0)
293bcec8f31Sxsa 		sc->sc_sensor[ASMS_DATA_Y].value = sdata;
294bcec8f31Sxsa 
295bcec8f31Sxsa 	cmd = ASMS_REG_DATA_Z;
296bcec8f31Sxsa 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
297bcec8f31Sxsa 	    sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0)
298bcec8f31Sxsa 		sc->sc_sensor[ASMS_DATA_Z].value = sdata;
299bcec8f31Sxsa 
300bcec8f31Sxsa 	iic_release_bus(sc->sc_tag, 0);
301bcec8f31Sxsa }
302