1*18f3098cSthorpej /* $NetBSD: asms.c,v 1.4 2021/01/27 02:29:48 thorpej Exp $ */
2b8f219c7Smacallan
3b8f219c7Smacallan /*-
4b8f219c7Smacallan * Copyright (c) 2020 Michael Lorenz
5b8f219c7Smacallan * All rights reserved.
6b8f219c7Smacallan *
7b8f219c7Smacallan * Redistribution and use in source and binary forms, with or without
8b8f219c7Smacallan * modification, are permitted provided that the following conditions
9b8f219c7Smacallan * are met:
10b8f219c7Smacallan * 1. Redistributions of source code must retain the above copyright
11b8f219c7Smacallan * notice, this list of conditions and the following disclaimer.
12b8f219c7Smacallan * 2. Redistributions in binary form must reproduce the above copyright
13b8f219c7Smacallan * notice, this list of conditions and the following disclaimer in the
14b8f219c7Smacallan * documentation and/or other materials provided with the distribution.
15b8f219c7Smacallan *
16b8f219c7Smacallan * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17b8f219c7Smacallan * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18b8f219c7Smacallan * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19b8f219c7Smacallan * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20b8f219c7Smacallan * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21b8f219c7Smacallan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22b8f219c7Smacallan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23b8f219c7Smacallan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24b8f219c7Smacallan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25b8f219c7Smacallan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26b8f219c7Smacallan * POSSIBILITY OF SUCH DAMAGE.
27b8f219c7Smacallan */
28b8f219c7Smacallan
29b8f219c7Smacallan #include <sys/cdefs.h>
30*18f3098cSthorpej __KERNEL_RCSID(0, "$NetBSD: asms.c,v 1.4 2021/01/27 02:29:48 thorpej Exp $");
31b8f219c7Smacallan
32b8f219c7Smacallan #include <sys/param.h>
33b8f219c7Smacallan #include <sys/systm.h>
34b8f219c7Smacallan #include <sys/device.h>
35b8f219c7Smacallan #include <sys/conf.h>
36b8f219c7Smacallan #include <sys/bus.h>
37b8f219c7Smacallan
38b8f219c7Smacallan #include <dev/i2c/i2cvar.h>
39b8f219c7Smacallan
40b8f219c7Smacallan #include <dev/sysmon/sysmonvar.h>
41b8f219c7Smacallan
42b8f219c7Smacallan struct asms_softc {
43b8f219c7Smacallan device_t sc_dev;
44b8f219c7Smacallan i2c_tag_t sc_i2c;
45b8f219c7Smacallan i2c_addr_t sc_addr;
46b8f219c7Smacallan
47b8f219c7Smacallan struct sysmon_envsys *sc_sme;
48b8f219c7Smacallan envsys_data_t sc_sensors[3];
49b8f219c7Smacallan };
50b8f219c7Smacallan
51b8f219c7Smacallan static int asms_match(device_t, cfdata_t, void *);
52b8f219c7Smacallan static void asms_attach(device_t, device_t, void *);
53b8f219c7Smacallan
54b8f219c7Smacallan static void asms_sensors_refresh(struct sysmon_envsys *, envsys_data_t *);
55b8f219c7Smacallan static void asms_init(struct asms_softc *);
56b8f219c7Smacallan
57b8f219c7Smacallan CFATTACH_DECL_NEW(asms, sizeof(struct asms_softc),
58b8f219c7Smacallan asms_match, asms_attach, NULL, NULL);
59b8f219c7Smacallan
60b8f219c7Smacallan static const struct device_compatible_entry compat_data[] = {
617246a945Sthorpej { .compat = "accelerometer" },
627246a945Sthorpej { .compat = "AAPL,accelerometer_1" },
63*18f3098cSthorpej DEVICE_COMPAT_EOL
64b8f219c7Smacallan };
65b8f219c7Smacallan
66b8f219c7Smacallan /* ASMS Registers, from OpenBSD */
67b8f219c7Smacallan #define ASMS_REG_COMMAND 0x00
68b8f219c7Smacallan #define ASMS_REG_STATUS 0x01
69b8f219c7Smacallan #define ASMS_REG_RCONTROL1 0x02
70b8f219c7Smacallan #define ASMS_REG_RCONTROL2 0x03
71b8f219c7Smacallan #define ASMS_REG_RCONTROL3 0x04
72b8f219c7Smacallan #define ASMS_REG_RDATA1 0x05
73b8f219c7Smacallan #define ASMS_REG_RDATA2 0x06
74b8f219c7Smacallan #define ASMS_REG_DATA_X 0x20
75b8f219c7Smacallan #define ASMS_REG_DATA_Y 0x21
76b8f219c7Smacallan #define ASMS_REG_DATA_Z 0x22
77b8f219c7Smacallan #define ASMS_REG_SENS_LOW 0x26 /* init with 0x15 */
78b8f219c7Smacallan #define ASMS_REG_SENS_HIGH 0x27 /* init with 0x60 */
79b8f219c7Smacallan #define ASMS_REG_CONTROL_X 0x28 /* init with 0x08 */
80b8f219c7Smacallan #define ASMS_REG_CONTROL_Y 0x29 /* init with 0x0f */
81b8f219c7Smacallan #define ASMS_REG_CONTROL_Z 0x2a /* init with 0x4f */
82b8f219c7Smacallan #define ASMS_REG_UNKNOWN1 0x2b /* init with 0x14 */
83b8f219c7Smacallan #define ASMS_REG_VENDOR 0x2e
84b8f219c7Smacallan #define ASMS_CMD_READ_VER 0x01
85b8f219c7Smacallan #define ASMS_CMD_READ_MEM 0x02
86b8f219c7Smacallan #define ASMS_CMD_RESET 0x07
87b8f219c7Smacallan #define ASMS_CMD_START 0x08
88b8f219c7Smacallan
89b8f219c7Smacallan static int
asms_match(device_t parent,cfdata_t match,void * aux)90b8f219c7Smacallan asms_match(device_t parent, cfdata_t match, void *aux)
91b8f219c7Smacallan {
92b8f219c7Smacallan struct i2c_attach_args *ia = aux;
93b8f219c7Smacallan int match_result;
94b8f219c7Smacallan
95b8f219c7Smacallan if (iic_use_direct_match(ia, match, compat_data, &match_result))
96b8f219c7Smacallan return match_result;
97b8f219c7Smacallan
98b8f219c7Smacallan if ((ia->ia_addr & 0xf8) == 0xd8)
99b8f219c7Smacallan return I2C_MATCH_ADDRESS_ONLY;
100b8f219c7Smacallan
101b8f219c7Smacallan return 0;
102b8f219c7Smacallan }
103b8f219c7Smacallan
104b8f219c7Smacallan static void
asms_attach(device_t parent,device_t self,void * aux)105b8f219c7Smacallan asms_attach(device_t parent, device_t self, void *aux)
106b8f219c7Smacallan {
107b8f219c7Smacallan struct asms_softc *sc = device_private(self);
108b8f219c7Smacallan struct i2c_attach_args *ia = aux;
109b8f219c7Smacallan envsys_data_t *s;
110b8f219c7Smacallan
111b8f219c7Smacallan sc->sc_dev = self;
112b8f219c7Smacallan sc->sc_i2c = ia->ia_tag;
113b8f219c7Smacallan sc->sc_addr = ia->ia_addr;
114b8f219c7Smacallan
115b8f219c7Smacallan aprint_naive("\n");
116b8f219c7Smacallan aprint_normal(": Sudden Motion Sensor\n");
117b8f219c7Smacallan
118b8f219c7Smacallan asms_init(sc);
119b8f219c7Smacallan
120b8f219c7Smacallan sc->sc_sme = sysmon_envsys_create();
121b8f219c7Smacallan sc->sc_sme->sme_name = device_xname(self);
122b8f219c7Smacallan sc->sc_sme->sme_cookie = sc;
123b8f219c7Smacallan sc->sc_sme->sme_refresh = asms_sensors_refresh;
124b8f219c7Smacallan
125b8f219c7Smacallan s = &sc->sc_sensors[0];
126b8f219c7Smacallan s->units = ENVSYS_INTEGER;
127b8f219c7Smacallan s->state = ENVSYS_SINVALID;
128b8f219c7Smacallan s->private = ASMS_REG_DATA_X;
129b8f219c7Smacallan strncpy(s->desc, "X", sizeof(s->desc));
130b8f219c7Smacallan sysmon_envsys_sensor_attach(sc->sc_sme, s);
131b8f219c7Smacallan
132b8f219c7Smacallan s = &sc->sc_sensors[1];
133b8f219c7Smacallan s->units = ENVSYS_INTEGER;
134b8f219c7Smacallan s->state = ENVSYS_SINVALID;
135b8f219c7Smacallan s->private = ASMS_REG_DATA_Y;
136b8f219c7Smacallan strncpy(s->desc, "Y", sizeof(s->desc));
137b8f219c7Smacallan sysmon_envsys_sensor_attach(sc->sc_sme, s);
138b8f219c7Smacallan
139b8f219c7Smacallan s = &sc->sc_sensors[2];
140b8f219c7Smacallan s->units = ENVSYS_INTEGER;
141b8f219c7Smacallan s->state = ENVSYS_SINVALID;
142b8f219c7Smacallan s->private = ASMS_REG_DATA_Z;
143b8f219c7Smacallan strncpy(s->desc, "Z", sizeof(s->desc));
144b8f219c7Smacallan sysmon_envsys_sensor_attach(sc->sc_sme, s);
145b8f219c7Smacallan
146b8f219c7Smacallan sysmon_envsys_register(sc->sc_sme);
147b8f219c7Smacallan }
148b8f219c7Smacallan
149b8f219c7Smacallan static void
asms_init(struct asms_softc * sc)150b8f219c7Smacallan asms_init(struct asms_softc *sc)
151b8f219c7Smacallan {
152b8f219c7Smacallan int error, i, j;
153b8f219c7Smacallan uint8_t cmd[2], data[48];
154b8f219c7Smacallan
155b8f219c7Smacallan iic_acquire_bus(sc->sc_i2c, 0);
156b8f219c7Smacallan
157b8f219c7Smacallan cmd[0] = ASMS_REG_COMMAND;
158b8f219c7Smacallan data[0] = ASMS_CMD_START;
159b8f219c7Smacallan error = iic_exec(sc->sc_i2c, I2C_OP_WRITE_WITH_STOP,
160b8f219c7Smacallan sc->sc_addr, cmd, 1, data, 1, 0);
161b8f219c7Smacallan delay(10000);
162b8f219c7Smacallan
163b8f219c7Smacallan cmd[0] = 0;
164b8f219c7Smacallan error = iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP,
165b8f219c7Smacallan sc->sc_addr, cmd, 1, data, 48, 0);
166b8f219c7Smacallan iic_release_bus(sc->sc_i2c, 0);
167b8f219c7Smacallan if (error != 0) {
168b8f219c7Smacallan aprint_error_dev(sc->sc_dev, "unable to read registers.\n");
169b8f219c7Smacallan return;
170b8f219c7Smacallan }
171b8f219c7Smacallan for (i = 0; i < 48; i += 8) {
172b8f219c7Smacallan printf("%02x:", i);
173b8f219c7Smacallan for (j =0; j < 8; j++) {
174b8f219c7Smacallan printf(" %02x", data[i + j]);
175b8f219c7Smacallan }
176b8f219c7Smacallan printf("\n");
177b8f219c7Smacallan }
178b8f219c7Smacallan }
179b8f219c7Smacallan
180b8f219c7Smacallan static void
asms_sensors_refresh(struct sysmon_envsys * sme,envsys_data_t * edata)181b8f219c7Smacallan asms_sensors_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
182b8f219c7Smacallan {
183b8f219c7Smacallan struct asms_softc *sc = sme->sme_cookie;
184b8f219c7Smacallan uint8_t cmd = 0;
185b8f219c7Smacallan int8_t data = 0;
186b8f219c7Smacallan int error;
187b8f219c7Smacallan
188b8f219c7Smacallan cmd = edata->private;
189b8f219c7Smacallan iic_acquire_bus(sc->sc_i2c, 0);
190b8f219c7Smacallan error = iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP,
191b8f219c7Smacallan sc->sc_addr, &cmd, 1, &data, 1, 0);
192b8f219c7Smacallan iic_release_bus(sc->sc_i2c, 0);
193b8f219c7Smacallan
194b8f219c7Smacallan if (error) {
195b8f219c7Smacallan edata->state = ENVSYS_SINVALID;
196b8f219c7Smacallan } else {
197b8f219c7Smacallan edata->value_cur = (int)data;
198b8f219c7Smacallan edata->state = ENVSYS_SVALID;
199b8f219c7Smacallan }
200b8f219c7Smacallan }
201