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