11.4Sthorpej/* $NetBSD: asms.c,v 1.4 2021/01/27 02:29:48 thorpej Exp $ */ 21.1Smacallan 31.1Smacallan/*- 41.1Smacallan * Copyright (c) 2020 Michael Lorenz 51.1Smacallan * All rights reserved. 61.1Smacallan * 71.1Smacallan * Redistribution and use in source and binary forms, with or without 81.1Smacallan * modification, are permitted provided that the following conditions 91.1Smacallan * are met: 101.1Smacallan * 1. Redistributions of source code must retain the above copyright 111.1Smacallan * notice, this list of conditions and the following disclaimer. 121.1Smacallan * 2. Redistributions in binary form must reproduce the above copyright 131.1Smacallan * notice, this list of conditions and the following disclaimer in the 141.1Smacallan * documentation and/or other materials provided with the distribution. 151.1Smacallan * 161.1Smacallan * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 171.1Smacallan * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 181.1Smacallan * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 191.1Smacallan * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 201.1Smacallan * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 211.1Smacallan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 221.1Smacallan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 231.1Smacallan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 241.1Smacallan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 251.1Smacallan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 261.1Smacallan * POSSIBILITY OF SUCH DAMAGE. 271.1Smacallan */ 281.1Smacallan 291.1Smacallan#include <sys/cdefs.h> 301.4Sthorpej__KERNEL_RCSID(0, "$NetBSD: asms.c,v 1.4 2021/01/27 02:29:48 thorpej Exp $"); 311.1Smacallan 321.1Smacallan#include <sys/param.h> 331.1Smacallan#include <sys/systm.h> 341.1Smacallan#include <sys/device.h> 351.1Smacallan#include <sys/conf.h> 361.1Smacallan#include <sys/bus.h> 371.1Smacallan 381.1Smacallan#include <dev/i2c/i2cvar.h> 391.1Smacallan 401.1Smacallan#include <dev/sysmon/sysmonvar.h> 411.1Smacallan 421.1Smacallanstruct asms_softc { 431.1Smacallan device_t sc_dev; 441.1Smacallan i2c_tag_t sc_i2c; 451.1Smacallan i2c_addr_t sc_addr; 461.1Smacallan 471.1Smacallan struct sysmon_envsys *sc_sme; 481.1Smacallan envsys_data_t sc_sensors[3]; 491.1Smacallan}; 501.1Smacallan 511.1Smacallanstatic int asms_match(device_t, cfdata_t, void *); 521.1Smacallanstatic void asms_attach(device_t, device_t, void *); 531.1Smacallan 541.1Smacallanstatic void asms_sensors_refresh(struct sysmon_envsys *, envsys_data_t *); 551.1Smacallanstatic void asms_init(struct asms_softc *); 561.1Smacallan 571.1SmacallanCFATTACH_DECL_NEW(asms, sizeof(struct asms_softc), 581.1Smacallan asms_match, asms_attach, NULL, NULL); 591.1Smacallan 601.1Smacallanstatic const struct device_compatible_entry compat_data[] = { 611.2Sthorpej { .compat = "accelerometer" }, 621.2Sthorpej { .compat = "AAPL,accelerometer_1" }, 631.4Sthorpej DEVICE_COMPAT_EOL 641.1Smacallan}; 651.1Smacallan 661.1Smacallan/* ASMS Registers, from OpenBSD */ 671.1Smacallan#define ASMS_REG_COMMAND 0x00 681.1Smacallan#define ASMS_REG_STATUS 0x01 691.1Smacallan#define ASMS_REG_RCONTROL1 0x02 701.1Smacallan#define ASMS_REG_RCONTROL2 0x03 711.1Smacallan#define ASMS_REG_RCONTROL3 0x04 721.1Smacallan#define ASMS_REG_RDATA1 0x05 731.1Smacallan#define ASMS_REG_RDATA2 0x06 741.1Smacallan#define ASMS_REG_DATA_X 0x20 751.1Smacallan#define ASMS_REG_DATA_Y 0x21 761.1Smacallan#define ASMS_REG_DATA_Z 0x22 771.1Smacallan#define ASMS_REG_SENS_LOW 0x26 /* init with 0x15 */ 781.1Smacallan#define ASMS_REG_SENS_HIGH 0x27 /* init with 0x60 */ 791.1Smacallan#define ASMS_REG_CONTROL_X 0x28 /* init with 0x08 */ 801.1Smacallan#define ASMS_REG_CONTROL_Y 0x29 /* init with 0x0f */ 811.1Smacallan#define ASMS_REG_CONTROL_Z 0x2a /* init with 0x4f */ 821.1Smacallan#define ASMS_REG_UNKNOWN1 0x2b /* init with 0x14 */ 831.1Smacallan#define ASMS_REG_VENDOR 0x2e 841.1Smacallan#define ASMS_CMD_READ_VER 0x01 851.1Smacallan#define ASMS_CMD_READ_MEM 0x02 861.1Smacallan#define ASMS_CMD_RESET 0x07 871.1Smacallan#define ASMS_CMD_START 0x08 881.1Smacallan 891.1Smacallanstatic int 901.1Smacallanasms_match(device_t parent, cfdata_t match, void *aux) 911.1Smacallan{ 921.1Smacallan struct i2c_attach_args *ia = aux; 931.1Smacallan int match_result; 941.1Smacallan 951.1Smacallan if (iic_use_direct_match(ia, match, compat_data, &match_result)) 961.1Smacallan return match_result; 971.1Smacallan 981.1Smacallan if ((ia->ia_addr & 0xf8) == 0xd8) 991.1Smacallan return I2C_MATCH_ADDRESS_ONLY; 1001.1Smacallan 1011.1Smacallan return 0; 1021.1Smacallan} 1031.1Smacallan 1041.1Smacallanstatic void 1051.1Smacallanasms_attach(device_t parent, device_t self, void *aux) 1061.1Smacallan{ 1071.1Smacallan struct asms_softc *sc = device_private(self); 1081.1Smacallan struct i2c_attach_args *ia = aux; 1091.1Smacallan envsys_data_t *s; 1101.1Smacallan 1111.1Smacallan sc->sc_dev = self; 1121.1Smacallan sc->sc_i2c = ia->ia_tag; 1131.1Smacallan sc->sc_addr = ia->ia_addr; 1141.1Smacallan 1151.1Smacallan aprint_naive("\n"); 1161.1Smacallan aprint_normal(": Sudden Motion Sensor\n"); 1171.1Smacallan 1181.1Smacallan asms_init(sc); 1191.1Smacallan 1201.1Smacallan sc->sc_sme = sysmon_envsys_create(); 1211.1Smacallan sc->sc_sme->sme_name = device_xname(self); 1221.1Smacallan sc->sc_sme->sme_cookie = sc; 1231.1Smacallan sc->sc_sme->sme_refresh = asms_sensors_refresh; 1241.1Smacallan 1251.1Smacallan s = &sc->sc_sensors[0]; 1261.1Smacallan s->units = ENVSYS_INTEGER; 1271.1Smacallan s->state = ENVSYS_SINVALID; 1281.1Smacallan s->private = ASMS_REG_DATA_X; 1291.1Smacallan strncpy(s->desc, "X", sizeof(s->desc)); 1301.1Smacallan sysmon_envsys_sensor_attach(sc->sc_sme, s); 1311.1Smacallan 1321.1Smacallan s = &sc->sc_sensors[1]; 1331.1Smacallan s->units = ENVSYS_INTEGER; 1341.1Smacallan s->state = ENVSYS_SINVALID; 1351.1Smacallan s->private = ASMS_REG_DATA_Y; 1361.1Smacallan strncpy(s->desc, "Y", sizeof(s->desc)); 1371.1Smacallan sysmon_envsys_sensor_attach(sc->sc_sme, s); 1381.1Smacallan 1391.1Smacallan s = &sc->sc_sensors[2]; 1401.1Smacallan s->units = ENVSYS_INTEGER; 1411.1Smacallan s->state = ENVSYS_SINVALID; 1421.1Smacallan s->private = ASMS_REG_DATA_Z; 1431.1Smacallan strncpy(s->desc, "Z", sizeof(s->desc)); 1441.1Smacallan sysmon_envsys_sensor_attach(sc->sc_sme, s); 1451.1Smacallan 1461.1Smacallan sysmon_envsys_register(sc->sc_sme); 1471.1Smacallan} 1481.1Smacallan 1491.1Smacallanstatic void 1501.1Smacallanasms_init(struct asms_softc *sc) 1511.1Smacallan{ 1521.1Smacallan int error, i, j; 1531.1Smacallan uint8_t cmd[2], data[48]; 1541.1Smacallan 1551.1Smacallan iic_acquire_bus(sc->sc_i2c, 0); 1561.1Smacallan 1571.1Smacallan cmd[0] = ASMS_REG_COMMAND; 1581.1Smacallan data[0] = ASMS_CMD_START; 1591.1Smacallan error = iic_exec(sc->sc_i2c, I2C_OP_WRITE_WITH_STOP, 1601.1Smacallan sc->sc_addr, cmd, 1, data, 1, 0); 1611.1Smacallan delay(10000); 1621.1Smacallan 1631.1Smacallan cmd[0] = 0; 1641.1Smacallan error = iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP, 1651.1Smacallan sc->sc_addr, cmd, 1, data, 48, 0); 1661.1Smacallan iic_release_bus(sc->sc_i2c, 0); 1671.1Smacallan if (error != 0) { 1681.1Smacallan aprint_error_dev(sc->sc_dev, "unable to read registers.\n"); 1691.1Smacallan return; 1701.1Smacallan } 1711.1Smacallan for (i = 0; i < 48; i += 8) { 1721.1Smacallan printf("%02x:", i); 1731.1Smacallan for (j =0; j < 8; j++) { 1741.1Smacallan printf(" %02x", data[i + j]); 1751.1Smacallan } 1761.1Smacallan printf("\n"); 1771.1Smacallan } 1781.1Smacallan} 1791.1Smacallan 1801.1Smacallanstatic void 1811.1Smacallanasms_sensors_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 1821.1Smacallan{ 1831.1Smacallan struct asms_softc *sc = sme->sme_cookie; 1841.1Smacallan uint8_t cmd = 0; 1851.1Smacallan int8_t data = 0; 1861.1Smacallan int error; 1871.1Smacallan 1881.1Smacallan cmd = edata->private; 1891.1Smacallan iic_acquire_bus(sc->sc_i2c, 0); 1901.1Smacallan error = iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP, 1911.1Smacallan sc->sc_addr, &cmd, 1, &data, 1, 0); 1921.1Smacallan iic_release_bus(sc->sc_i2c, 0); 1931.1Smacallan 1941.1Smacallan if (error) { 1951.1Smacallan edata->state = ENVSYS_SINVALID; 1961.1Smacallan } else { 1971.1Smacallan edata->value_cur = (int)data; 1981.1Smacallan edata->state = ENVSYS_SVALID; 1991.1Smacallan } 2001.1Smacallan} 201