| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * resarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include <assert.h> |
| #include <stdio.h> |
| #include <errno.h> |
| #include <string.h> |
| |
| #include "os/mynewt.h" |
| #include "hal/hal_spi.h" |
| #include "hal/hal_i2c.h" |
| #include "i2cn/i2cn.h" |
| #include "sensor/sensor.h" |
| #include "sensor/accel.h" |
| #include "lis2dh12/lis2dh12.h" |
| #include "lis2dh12_priv.h" |
| #include "hal/hal_gpio.h" |
| #include "modlog/modlog.h" |
| #include "stats/stats.h" |
| #include <syscfg/syscfg.h> |
| |
| static struct hal_spi_settings spi_lis2dh12_settings = { |
| .data_order = HAL_SPI_MSB_FIRST, |
| .data_mode = HAL_SPI_MODE3, |
| .baudrate = 4000, |
| .word_size = HAL_SPI_WORD_SIZE_8BIT, |
| }; |
| |
| /* Define the stats section and records */ |
| STATS_SECT_START(lis2dh12_stat_section) |
| STATS_SECT_ENTRY(write_errors) |
| STATS_SECT_ENTRY(read_errors) |
| STATS_SECT_END |
| |
| /* Define stat names for querying */ |
| STATS_NAME_START(lis2dh12_stat_section) |
| STATS_NAME(lis2dh12_stat_section, write_errors) |
| STATS_NAME(lis2dh12_stat_section, read_errors) |
| STATS_NAME_END(lis2dh12_stat_section) |
| |
| /* Global variable used to hold stats data */ |
| STATS_SECT_DECL(lis2dh12_stat_section) g_lis2dh12stats; |
| |
| #define LIS2DH12_LOG(lvl_, ...) \ |
| MODLOG_ ## lvl_(MYNEWT_VAL(LIS2DH12_LOG_MODULE), __VA_ARGS__) |
| |
| /* Exports for the sensor API */ |
| static int lis2dh12_sensor_read(struct sensor *, sensor_type_t, |
| sensor_data_func_t, void *, uint32_t); |
| static int lis2dh12_sensor_get_config(struct sensor *, sensor_type_t, |
| struct sensor_cfg *); |
| static int |
| lis2dh12_sensor_set_trigger_thresh(struct sensor *, sensor_type_t, |
| struct sensor_type_traits *); |
| static int |
| lis2dh12_sensor_clear_low_thresh(struct sensor *, sensor_type_t); |
| |
| static int |
| lis2dh12_sensor_clear_high_thresh(struct sensor *, sensor_type_t); |
| |
| static const struct sensor_driver g_lis2dh12_sensor_driver = { |
| .sd_read = lis2dh12_sensor_read, |
| .sd_get_config = lis2dh12_sensor_get_config, |
| /* Setting trigger threshold is optional */ |
| .sd_set_trigger_thresh = lis2dh12_sensor_set_trigger_thresh, |
| .sd_clear_low_trigger_thresh = lis2dh12_sensor_clear_low_thresh, |
| .sd_clear_high_trigger_thresh = lis2dh12_sensor_clear_high_thresh |
| }; |
| |
| /** |
| * Read multiple length data from LIS2DH12 sensor over I2C |
| * |
| * @param The sensor interface |
| * @param register address |
| * @param variable length buffer |
| * @param length of the payload to read |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| lis2dh12_i2c_readlen(struct sensor_itf *itf, uint8_t addr, uint8_t *buffer, |
| uint8_t len) |
| { |
| int rc; |
| uint8_t payload[20] = { addr, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0}; |
| |
| struct hal_i2c_master_data data_struct = { |
| .address = itf->si_addr, |
| .len = 1, |
| .buffer = payload |
| }; |
| |
| /* Clear the supplied buffer */ |
| memset(buffer, 0, len); |
| |
| /* Register write */ |
| rc = i2cn_master_write(itf->si_num, &data_struct, MYNEWT_VAL(LIS2DH12_I2C_TIMEOUT_TICKS), 1, |
| MYNEWT_VAL(LIS2DH12_I2C_RETRIES)); |
| if (rc) { |
| LIS2DH12_LOG(ERROR, "I2C access failed at address 0x%02X\n", |
| data_struct.address); |
| STATS_INC(g_lis2dh12stats, read_errors); |
| goto err; |
| } |
| |
| /* Read len bytes back */ |
| memset(payload, 0, sizeof(payload)); |
| data_struct.len = len; |
| rc = i2cn_master_read(itf->si_num, &data_struct, MYNEWT_VAL(LIS2DH12_I2C_TIMEOUT_TICKS), 1, |
| MYNEWT_VAL(LIS2DH12_I2C_RETRIES)); |
| if (rc) { |
| LIS2DH12_LOG(ERROR, "Failed to read from 0x%02X:0x%02X\n", |
| data_struct.address, addr); |
| STATS_INC(g_lis2dh12stats, read_errors); |
| goto err; |
| } |
| |
| /* Copy the I2C results into the supplied buffer */ |
| memcpy(buffer, payload, len); |
| |
| return 0; |
| err: |
| |
| return rc; |
| } |
| |
| /** |
| * Read multiple length data from LIS2DH12 sensor over SPI |
| * |
| * @param The sensor interface |
| * @param register address |
| * @param variable length payload |
| * @param length of the payload to read |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| lis2dh12_spi_readlen(struct sensor_itf *itf, uint8_t addr, uint8_t *payload, |
| uint8_t len) |
| { |
| int i; |
| uint16_t retval; |
| int rc; |
| |
| rc = 0; |
| |
| addr |= LIS2DH12_SPI_READ_CMD_BIT; |
| |
| /* |
| * Auto register address increment is needed if the length |
| * requested is more than 1 |
| */ |
| if (len > 1) { |
| addr |= LIS2DH12_SPI_ADR_INC; |
| } |
| |
| /* Select the device */ |
| hal_gpio_write(itf->si_cs_pin, 0); |
| |
| /* Send the address */ |
| retval = hal_spi_tx_val(itf->si_num, addr); |
| if (retval == 0xFFFF) { |
| rc = SYS_EINVAL; |
| LIS2DH12_LOG(ERROR, "SPI_%u register write failed addr:0x%02X\n", |
| itf->si_num, addr); |
| STATS_INC(g_lis2dh12stats, read_errors); |
| goto err; |
| } |
| |
| for (i = 0; i < len; i++) { |
| /* Read data */ |
| retval = hal_spi_tx_val(itf->si_num, 0x55); |
| if (retval == 0xFFFF) { |
| rc = SYS_EINVAL; |
| LIS2DH12_LOG(ERROR, "SPI_%u read failed addr:0x%02X\n", |
| itf->si_num, addr); |
| STATS_INC(g_lis2dh12stats, read_errors); |
| goto err; |
| } |
| payload[i] = retval; |
| } |
| |
| rc = 0; |
| |
| err: |
| /* De-select the device */ |
| hal_gpio_write(itf->si_cs_pin, 1); |
| |
| return rc; |
| } |
| |
| |
| /** |
| * Write multiple length data to LIS2DH12 sensor over I2C (MAX: 19 bytes) |
| * |
| * @param The sensor interface |
| * @param register address |
| * @param variable length payload |
| * @param length of the payload to write |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| lis2dh12_i2c_writelen(struct sensor_itf *itf, uint8_t addr, uint8_t *buffer, |
| uint8_t len) |
| { |
| int rc; |
| uint8_t payload[20] = { addr, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0}; |
| |
| struct hal_i2c_master_data data_struct = { |
| .address = itf->si_addr, |
| .len = len + 1, |
| .buffer = payload |
| }; |
| |
| if (len > (sizeof(payload) - 1)) { |
| rc = OS_EINVAL; |
| goto err; |
| } |
| |
| memcpy(&payload[1], buffer, len); |
| |
| /* Register write */ |
| rc = i2cn_master_write(itf->si_num, &data_struct, MYNEWT_VAL(LIS2DH12_I2C_TIMEOUT_TICKS), 1, |
| MYNEWT_VAL(LIS2DH12_I2C_RETRIES)); |
| if (rc) { |
| LIS2DH12_LOG(ERROR, "I2C access failed at address 0x%02X\n", |
| data_struct.address); |
| STATS_INC(g_lis2dh12stats, write_errors); |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Write multiple length data to LIS2DH12 sensor over SPI |
| * |
| * @param The sensor interface |
| * @param register address |
| * @param variable length payload |
| * @param length of the payload to write |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| lis2dh12_spi_writelen(struct sensor_itf *itf, uint8_t addr, uint8_t *payload, |
| uint8_t len) |
| { |
| int i; |
| int rc; |
| |
| /* |
| * Auto register address increment is needed if the length |
| * requested is moret than 1 |
| */ |
| if (len > 1) { |
| addr |= LIS2DH12_SPI_ADR_INC; |
| } |
| |
| /* Select the device */ |
| hal_gpio_write(itf->si_cs_pin, 0); |
| |
| |
| /* Send the address */ |
| rc = hal_spi_tx_val(itf->si_num, addr); |
| if (rc == 0xFFFF) { |
| rc = SYS_EINVAL; |
| LIS2DH12_LOG(ERROR, "SPI_%u register write failed addr:0x%02X\n", |
| itf->si_num, addr); |
| STATS_INC(g_lis2dh12stats, write_errors); |
| goto err; |
| } |
| |
| for (i = 0; i < len; i++) { |
| /* Read data */ |
| rc = hal_spi_tx_val(itf->si_num, payload[i]); |
| if (rc == 0xFFFF) { |
| rc = SYS_EINVAL; |
| LIS2DH12_LOG(ERROR, "SPI_%u write failed addr:0x%02X\n", |
| itf->si_num, addr); |
| STATS_INC(g_lis2dh12stats, write_errors); |
| goto err; |
| } |
| } |
| |
| |
| rc = 0; |
| |
| err: |
| /* De-select the device */ |
| hal_gpio_write(itf->si_cs_pin, 1); |
| |
| return rc; |
| } |
| |
| /** |
| * Write multiple length data to LIS2DH12 sensor over different interfaces |
| * |
| * @param The sensor interface |
| * @param register address |
| * @param variable length payload |
| * @param length of the payload to write |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_writelen(struct sensor_itf *itf, uint8_t addr, uint8_t *payload, |
| uint8_t len) |
| { |
| int rc; |
| |
| rc = sensor_itf_lock(itf, MYNEWT_VAL(LIS2DH12_ITF_LOCK_TMO)); |
| if (rc) { |
| return rc; |
| } |
| |
| if (itf->si_type == SENSOR_ITF_I2C) { |
| rc = lis2dh12_i2c_writelen(itf, addr, payload, len); |
| } else { |
| rc = lis2dh12_spi_writelen(itf, addr, payload, len); |
| } |
| |
| sensor_itf_unlock(itf); |
| |
| return rc; |
| } |
| |
| /** |
| * Read multiple length data from LIS2DH12 sensor over different interfaces |
| * |
| * @param register address |
| * @param variable length payload |
| * @param length of the payload to read |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_readlen(struct sensor_itf *itf, uint8_t addr, uint8_t *payload, |
| uint8_t len) |
| { |
| int rc; |
| |
| rc = sensor_itf_lock(itf, MYNEWT_VAL(LIS2DH12_ITF_LOCK_TMO)); |
| if (rc) { |
| return rc; |
| } |
| |
| if (itf->si_type == SENSOR_ITF_I2C) { |
| rc = lis2dh12_i2c_readlen(itf, addr, payload, len); |
| } else { |
| rc = lis2dh12_spi_readlen(itf, addr, payload, len); |
| } |
| |
| sensor_itf_unlock(itf); |
| |
| return rc; |
| } |
| |
| /** |
| * Reset lis2dh12 |
| * |
| * @param The sensor interface |
| */ |
| int |
| lis2dh12_reset(struct sensor_itf *itf) |
| { |
| int rc; |
| uint8_t reg; |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG5, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| reg |= LIS2DH12_CTRL_REG5_BOOT; |
| |
| rc = lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG5, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| os_time_delay((OS_TICKS_PER_SEC * 6/1000) + 1); |
| |
| err: |
| return rc; |
| } |
| |
| /** |
| * Pull up disconnect |
| * |
| * @param The sensor interface |
| * @param disconnect pull up |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_pull_up_disc(struct sensor_itf *itf, uint8_t disconnect) |
| { |
| uint8_t reg; |
| |
| reg = 0; |
| |
| reg |= ((disconnect ? LIS2DH12_CTRL_REG0_SPD : 0) | |
| LIS2DH12_CTRL_REG0_CORR_OP); |
| |
| return lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG0, ®, 1); |
| } |
| |
| /** |
| * Enable channels |
| * |
| * @param sensor interface |
| * @param chan |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_chan_enable(struct sensor_itf *itf, uint8_t chan) |
| { |
| uint8_t reg; |
| int rc; |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG1, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| reg &= 0xF0; |
| reg |= chan; |
| |
| rc = lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG1, ®, 1); |
| |
| err: |
| return rc; |
| } |
| |
| /** |
| * Get chip ID |
| * |
| * @param sensor interface |
| * @param ptr to chip id to be filled up |
| */ |
| int |
| lis2dh12_get_chip_id(struct sensor_itf *itf, uint8_t *chip_id) |
| { |
| uint8_t reg; |
| int rc; |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_WHO_AM_I, ®, 1); |
| |
| if (rc) { |
| goto err; |
| } |
| |
| *chip_id = reg; |
| |
| err: |
| return rc; |
| } |
| |
| /** |
| * Sets the full scale selection |
| * |
| * @param The sensor interface |
| * @param The fs setting |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_set_full_scale(struct sensor_itf *itf, uint8_t fs) |
| { |
| int rc; |
| uint8_t reg; |
| |
| if (fs > LIS2DH12_FS_16G) { |
| LIS2DH12_LOG(ERROR, "Invalid full scale value\n"); |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG4, |
| ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| reg = (reg & ~LIS2DH12_CTRL_REG4_FS) | fs; |
| |
| rc = lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG4, |
| ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Gets the full scale selection |
| * |
| * @param The sensor interface |
| * @param ptr to fs |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_get_full_scale(struct sensor_itf *itf, uint8_t *fs) |
| { |
| int rc; |
| uint8_t reg; |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG4, |
| ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| *fs = (reg & LIS2DH12_CTRL_REG4_FS) >> 4; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Calculates the acceleration in m/s^2 from mg |
| * |
| * @param acc value in mg |
| * @param float ptr to return calculated value in ms2 |
| */ |
| void |
| lis2dh12_calc_acc_ms2(int16_t acc_mg, float *acc_ms2) |
| { |
| *acc_ms2 = (acc_mg * STANDARD_ACCEL_GRAVITY)/1000; |
| } |
| |
| /** |
| * Calculates the acceleration in mg from m/s^2 |
| * |
| * @param acc value in m/s^2 |
| * @param int16 ptr to return calculated value in mg |
| */ |
| void |
| lis2dh12_calc_acc_mg(float acc_ms2, int16_t *acc_mg) |
| { |
| *acc_mg = (acc_ms2 * 1000)/STANDARD_ACCEL_GRAVITY; |
| } |
| |
| /** |
| * Sets the rate |
| * |
| * @param The sensor interface |
| * @param The rate |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_set_rate(struct sensor_itf *itf, uint8_t rate) |
| { |
| int rc; |
| uint8_t reg; |
| |
| if (rate > LIS2DH12_DATA_RATE_HN_1344HZ_L_5376HZ) { |
| LIS2DH12_LOG(ERROR, "Invalid rate value\n"); |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| /* |
| * As per the datasheet, REFERENCE(26h) needs to be read |
| * for a reset of the filter block before switching to |
| * normal/high-performance mode from power down mode |
| */ |
| if (rate != LIS2DH12_DATA_RATE_0HZ || rate != LIS2DH12_DATA_RATE_L_1620HZ) { |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_REFERENCE, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG1, |
| ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| reg = (reg & ~LIS2DH12_CTRL_REG1_ODR) | rate; |
| |
| rc = lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG1, |
| ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Gets the rate |
| * |
| * @param The sensor ineterface |
| * @param ptr to the rate |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_get_rate(struct sensor_itf *itf, uint8_t *rate) |
| { |
| int rc; |
| uint8_t reg; |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG1, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| *rate = reg & LIS2DH12_CTRL_REG1_ODR; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Set FIFO mode |
| * |
| * @param the sensor interface |
| * @param mode |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_set_fifo_mode(struct sensor_itf *itf, uint8_t mode) |
| { |
| int rc; |
| uint8_t reg; |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG5, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| reg |= LIS2DH12_CTRL_REG5_FIFO_EN; |
| |
| rc = lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG5, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_FIFO_CTRL_REG, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| reg |= mode; |
| |
| rc = lis2dh12_writelen(itf, LIS2DH12_REG_FIFO_CTRL_REG, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_FIFO_SRC_REG, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| if (mode == LIS2DH12_FIFO_M_BYPASS && reg != LIS2DH12_FIFO_SRC_EMPTY) { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * |
| * Get operating mode |
| * |
| * @param the sensor interface |
| * @param ptr to mode |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_get_op_mode(struct sensor_itf *itf, uint8_t *mode) |
| { |
| int rc; |
| uint8_t reg1; |
| uint8_t reg4; |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG1, ®1, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| reg1 = (reg1 & LIS2DH12_CTRL_REG1_LPEN) << 4; |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG4, ®4, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| reg4 = (reg4 & LIS2DH12_CTRL_REG4_HR); |
| |
| *mode = reg1 | reg4; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Set high pass filter cfg |
| * |
| * @param the sensor interface |
| * @param filter register settings |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_hpf_cfg(struct sensor_itf *itf, uint8_t reg) |
| { |
| return lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG2, ®, 1); |
| } |
| |
| /** |
| * Set operating mode |
| * |
| * @param the sensor interface |
| * @param mode CTRL_REG1[3:0]:CTRL_REG4[3:0] |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_set_op_mode(struct sensor_itf *itf, uint8_t mode) |
| { |
| int rc; |
| uint8_t reg; |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG1, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| reg &= ~LIS2DH12_CTRL_REG1_LPEN; |
| reg |= ((mode & 0x80) >> 4); |
| |
| rc = lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG1, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG4, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| reg &= ~LIS2DH12_CTRL_REG4_HR; |
| reg |= (mode & 0x08); |
| |
| rc = lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG4, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| os_time_delay(OS_TICKS_PER_SEC/1000 + 1); |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Gets a new data sample from the light sensor. |
| * |
| * @param The sensor interface |
| * @param x axis data |
| * @param y axis data |
| * @param z axis data |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_get_data(struct sensor_itf *itf, int16_t *x, int16_t *y, int16_t *z) |
| { |
| int rc; |
| uint8_t payload[6] = {0}; |
| uint8_t fs; |
| |
| *x = *y = *z = 0; |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_OUT_X_L, payload, 1); |
| rc |= lis2dh12_readlen(itf, LIS2DH12_REG_OUT_X_H, &payload[1], 1); |
| rc |= lis2dh12_readlen(itf, LIS2DH12_REG_OUT_Y_L, &payload[2], 1); |
| rc |= lis2dh12_readlen(itf, LIS2DH12_REG_OUT_Y_H, &payload[3], 1); |
| rc |= lis2dh12_readlen(itf, LIS2DH12_REG_OUT_Z_L, &payload[4], 1); |
| rc |= lis2dh12_readlen(itf, LIS2DH12_REG_OUT_Z_H, &payload[5], 1); |
| if (rc) { |
| goto err; |
| } |
| |
| *x = payload[0] | (payload[1] << 8); |
| *y = payload[2] | (payload[3] << 8); |
| *z = payload[4] | (payload[5] << 8); |
| |
| rc = lis2dh12_get_full_scale(itf, &fs); |
| if (rc) { |
| goto err; |
| } |
| |
| if (fs == LIS2DH12_FS_2G) { |
| fs = 2; |
| } else if (fs == LIS2DH12_FS_4G) { |
| fs = 4; |
| } else if (fs == LIS2DH12_FS_8G) { |
| fs = 8; |
| } else if (fs == LIS2DH12_FS_16G) { |
| fs = 16; |
| } else { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| /* |
| * Since full scale is +/-(fs)g, |
| * fs should be multiplied by 2 to account for full scale. |
| * To calculate mg from g we use the 1000 multiple. |
| * Since the full scale is represented by 16 bit value, |
| * we use that as a divisor. |
| * The calculation is based on an example present in AN5005 |
| * application note |
| */ |
| *x = (fs * 2 * 1000 * *x)/UINT16_MAX; |
| *y = (fs * 2 * 1000 * *y)/UINT16_MAX; |
| *z = (fs * 2 * 1000 * *z)/UINT16_MAX; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Expects to be called back through os_dev_create(). |
| * |
| * @param The device object associated with this accelerometer |
| * @param Argument passed to OS device init, unused |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| lis2dh12_init(struct os_dev *dev, void *arg) |
| { |
| struct lis2dh12 *lis2dh12; |
| struct sensor *sensor; |
| int rc; |
| |
| if (!arg || !dev) { |
| rc = SYS_ENODEV; |
| goto err; |
| } |
| |
| lis2dh12 = (struct lis2dh12 *) dev; |
| |
| lis2dh12->cfg.lc_s_mask = SENSOR_TYPE_ALL; |
| |
| sensor = &lis2dh12->sensor; |
| |
| /* Initialise the stats entry */ |
| rc = stats_init( |
| STATS_HDR(g_lis2dh12stats), |
| STATS_SIZE_INIT_PARMS(g_lis2dh12stats, STATS_SIZE_32), |
| STATS_NAME_INIT_PARMS(lis2dh12_stat_section)); |
| SYSINIT_PANIC_ASSERT(rc == 0); |
| /* Register the entry with the stats registry */ |
| rc = stats_register(dev->od_name, STATS_HDR(g_lis2dh12stats)); |
| SYSINIT_PANIC_ASSERT(rc == 0); |
| |
| rc = sensor_init(sensor, dev); |
| if (rc) { |
| goto err; |
| } |
| |
| /* Add the light driver */ |
| rc = sensor_set_driver(sensor, SENSOR_TYPE_ACCELEROMETER, |
| (struct sensor_driver *) &g_lis2dh12_sensor_driver); |
| if (rc) { |
| goto err; |
| } |
| |
| /* Set the interface */ |
| rc = sensor_set_interface(sensor, arg); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = sensor_mgr_register(sensor); |
| if (rc) { |
| goto err; |
| } |
| |
| if (sensor->s_itf.si_type == SENSOR_ITF_SPI) { |
| |
| rc = hal_spi_disable(sensor->s_itf.si_num); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = hal_spi_config(sensor->s_itf.si_num, &spi_lis2dh12_settings); |
| if (rc == EINVAL) { |
| /* If spi is already enabled, for nrf52, it returns -1, We should not |
| * fail if the spi is already enabled |
| */ |
| goto err; |
| } |
| |
| rc = hal_spi_enable(sensor->s_itf.si_num); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = hal_gpio_init_out(sensor->s_itf.si_cs_pin, 1); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| return 0; |
| err: |
| return rc; |
| |
| } |
| |
| /** |
| * Self test mode |
| * |
| * @param the sensor interface |
| * @param mode to set |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_set_self_test_mode(struct sensor_itf *itf, uint8_t mode) |
| { |
| uint8_t reg; |
| int rc; |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG4, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| reg &= ~LIS2DH12_CTRL_REG4_ST; |
| |
| reg |= mode; |
| |
| rc = lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG4, ®, 1); |
| |
| err: |
| return rc; |
| } |
| |
| static int |
| lis2dh12_sensor_read(struct sensor *sensor, sensor_type_t type, |
| sensor_data_func_t data_func, void *data_arg, uint32_t timeout) |
| { |
| struct sensor_accel_data sad; |
| struct sensor_itf *itf; |
| int16_t x, y ,z; |
| float fx, fy ,fz; |
| int rc; |
| |
| /* If the read isn't looking for accel or mag data, don't do anything. */ |
| if (!(type & SENSOR_TYPE_ACCELEROMETER)) { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| itf = SENSOR_GET_ITF(sensor); |
| |
| x = y = z = 0; |
| |
| if (itf->si_type == SENSOR_ITF_SPI) { |
| |
| rc = hal_spi_disable(sensor->s_itf.si_num); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = hal_spi_config(sensor->s_itf.si_num, &spi_lis2dh12_settings); |
| if (rc == EINVAL) { |
| /* If spi is already enabled, for nrf52, it returns -1, We should not |
| * fail if the spi is already enabled |
| */ |
| goto err; |
| } |
| |
| rc = hal_spi_enable(sensor->s_itf.si_num); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| rc = lis2dh12_get_data(itf, &x, &y, &z); |
| if (rc) { |
| goto err; |
| } |
| |
| /* converting values from mg to ms^2 */ |
| lis2dh12_calc_acc_ms2(x, &fx); |
| lis2dh12_calc_acc_ms2(y, &fy); |
| lis2dh12_calc_acc_ms2(z, &fz); |
| |
| sad.sad_x = fx; |
| sad.sad_y = fy; |
| sad.sad_z = fz; |
| |
| sad.sad_x_is_valid = 1; |
| sad.sad_y_is_valid = 1; |
| sad.sad_z_is_valid = 1; |
| |
| /* Call data function */ |
| rc = data_func(sensor, data_arg, &sad, SENSOR_TYPE_ACCELEROMETER); |
| if (rc != 0) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| static int |
| lis2dh12_sensor_get_config(struct sensor *sensor, sensor_type_t type, |
| struct sensor_cfg *cfg) |
| { |
| int rc; |
| |
| if (type != SENSOR_TYPE_ACCELEROMETER) { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| cfg->sc_valtype = SENSOR_VALUE_TYPE_FLOAT_TRIPLET; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Set interrupt threshold for int 2 |
| * |
| * @param the sensor interface |
| * @param threshold |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_set_int2_thresh(struct sensor_itf *itf, uint8_t ths) |
| { |
| int rc; |
| |
| rc = lis2dh12_writelen(itf, LIS2DH12_REG_INT2_THS, &ths, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Set interrupt threshold for int 1 |
| * |
| * @param the sensor interface |
| * @param threshold |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_set_int1_thresh(struct sensor_itf *itf, uint8_t ths) |
| { |
| |
| int rc; |
| |
| rc = lis2dh12_writelen(itf, LIS2DH12_REG_INT1_THS, &ths, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Clear interrupt 2 |
| * |
| * @param the sensor interface |
| */ |
| int |
| lis2dh12_clear_int2(struct sensor_itf *itf) |
| { |
| uint8_t reg; |
| |
| return lis2dh12_readlen(itf, LIS2DH12_REG_INT2_SRC, ®, 1); |
| } |
| |
| /** |
| * Clear interrupt 1 |
| * |
| * @param the sensor interface |
| */ |
| int |
| lis2dh12_clear_int1(struct sensor_itf *itf) |
| { |
| uint8_t reg; |
| |
| return lis2dh12_readlen(itf, LIS2DH12_REG_INT1_SRC, ®, 1); |
| } |
| |
| /** |
| * Enable interrupt 2 |
| * |
| * @param the sensor interface |
| * @param events to enable int for |
| */ |
| int |
| lis2dh12_enable_int2(struct sensor_itf *itf, uint8_t *reg) |
| { |
| return lis2dh12_writelen(itf, LIS2DH12_REG_INT2_CFG, reg, 1); |
| } |
| |
| /** |
| * Latch interrupt 1 |
| * |
| * @param the sensor interface |
| */ |
| int |
| lis2dh12_latch_int1(struct sensor_itf *itf) |
| { |
| uint8_t reg; |
| int rc; |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG5, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| reg |= LIS2DH12_CTRL_REG5_LIR_INT1; |
| |
| rc = lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG5, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Latch interrupt 2 |
| * |
| * @param the sensor interface |
| */ |
| int |
| lis2dh12_latch_int2(struct sensor_itf *itf) |
| { |
| uint8_t reg; |
| int rc; |
| |
| rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG5, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| reg |= LIS2DH12_CTRL_REG5_LIR_INT2; |
| |
| rc = lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG5, ®, 1); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Set interrupt pin configuration for interrupt 1 |
| * |
| * @param the sensor interface |
| * @param config |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_set_int1_pin_cfg(struct sensor_itf *itf, uint8_t cfg) |
| { |
| uint8_t reg; |
| |
| reg = ~0x08 & cfg; |
| |
| return lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG3, ®, 1); |
| } |
| |
| /** |
| * Set interrupt 1 duration |
| * |
| * @param duration in N/ODR units |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_set_int1_duration(struct sensor_itf *itf, uint8_t dur) |
| { |
| return lis2dh12_writelen(itf, LIS2DH12_REG_INT1_DURATION, &dur, 1); |
| } |
| |
| /** |
| * Set interrupt 2 duration |
| * |
| * @param duration in N/ODR units |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_set_int2_duration(struct sensor_itf *itf, uint8_t dur) |
| { |
| return lis2dh12_writelen(itf, LIS2DH12_REG_INT2_DURATION, &dur, 1); |
| } |
| |
| /** |
| * Set interrupt pin configuration for interrupt 2 |
| * |
| * @param the sensor interface |
| * @param config |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_set_int2_pin_cfg(struct sensor_itf *itf, uint8_t cfg) |
| { |
| return lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG6, &cfg, 1); |
| } |
| |
| /** |
| * Disable interrupt 1 |
| * |
| * @param the sensor interface |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_disable_int1(struct sensor_itf *itf) |
| { |
| uint8_t reg; |
| int rc; |
| |
| reg = 0; |
| |
| rc = lis2dh12_clear_int1(itf); |
| if (rc) { |
| goto err; |
| } |
| |
| os_time_delay((OS_TICKS_PER_SEC * 20)/1000 + 1); |
| |
| rc = lis2dh12_writelen(itf, LIS2DH12_REG_INT1_CFG, ®, 1); |
| |
| err: |
| return rc; |
| } |
| |
| /** |
| * Disable interrupt 2 |
| * |
| * @param the sensor interface |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| lis2dh12_disable_int2(struct sensor_itf *itf) |
| { |
| uint8_t reg; |
| int rc; |
| |
| reg = 0; |
| |
| rc = lis2dh12_clear_int2(itf); |
| if (rc) { |
| goto err; |
| } |
| |
| os_time_delay((OS_TICKS_PER_SEC * 20)/1000 + 1); |
| |
| rc = lis2dh12_writelen(itf, LIS2DH12_REG_INT2_CFG, ®, 1); |
| |
| err: |
| return rc; |
| } |
| |
| /** |
| * Enable interrupt 1 |
| * |
| * @param the sensor interface |
| * @param events to enable int for |
| */ |
| int |
| lis2dh12_enable_int1(struct sensor_itf *itf, uint8_t *reg) |
| { |
| return lis2dh12_writelen(itf, LIS2DH12_REG_INT1_CFG, reg, 1); |
| } |
| |
| /** |
| * IRQ handler for interrupts for high/low threshold |
| * |
| * @param arg |
| */ |
| static void |
| lis2dh12_int_irq_handler(void *arg) |
| { |
| sensor_mgr_put_read_evt(arg); |
| } |
| |
| /** |
| * Clear the low threshold values and disable interrupt |
| * |
| * @param ptr to sensor |
| * @param the Sensor type |
| * @param Sensor type traits |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| lis2dh12_sensor_clear_low_thresh(struct sensor *sensor, |
| sensor_type_t type) |
| { |
| int rc; |
| struct sensor_itf *itf; |
| |
| itf = SENSOR_GET_ITF(sensor); |
| |
| if (type != SENSOR_TYPE_ACCELEROMETER) { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| rc = lis2dh12_disable_int1(itf); |
| if (rc) { |
| goto err; |
| } |
| |
| hal_gpio_irq_release(itf->si_low_pin); |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Clear the high threshold values and disable interrupt |
| * |
| * @param ptr to sensor |
| * @param the Sensor type |
| * @param Sensor type traits |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| lis2dh12_sensor_clear_high_thresh(struct sensor *sensor, |
| sensor_type_t type) |
| { |
| int rc; |
| struct sensor_itf *itf; |
| |
| itf = SENSOR_GET_ITF(sensor); |
| |
| if (type != SENSOR_TYPE_ACCELEROMETER) { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| rc = lis2dh12_disable_int2(itf); |
| if (rc) { |
| goto err; |
| } |
| |
| hal_gpio_irq_release(itf->si_high_pin); |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| static int |
| lis2dh12_set_low_thresh(struct sensor_itf *itf, |
| sensor_data_t low_thresh, |
| uint8_t fs, |
| struct sensor_type_traits *stt) |
| { |
| int16_t acc_mg; |
| uint8_t reg; |
| int rc; |
| |
| rc = 0; |
| if (low_thresh.sad->sad_x_is_valid || |
| low_thresh.sad->sad_y_is_valid || |
| low_thresh.sad->sad_z_is_valid) { |
| |
| if (low_thresh.sad->sad_x_is_valid) { |
| lis2dh12_calc_acc_mg(low_thresh.sad->sad_x, &acc_mg); |
| reg = acc_mg/fs; |
| } |
| |
| if (low_thresh.sad->sad_y_is_valid) { |
| lis2dh12_calc_acc_mg(low_thresh.sad->sad_y, &acc_mg); |
| if (reg > acc_mg/fs) { |
| reg = acc_mg/fs; |
| } |
| } |
| |
| if (low_thresh.sad->sad_z_is_valid) { |
| lis2dh12_calc_acc_mg(low_thresh.sad->sad_z, &acc_mg); |
| if (reg > acc_mg/fs) { |
| reg = acc_mg/fs; |
| } |
| } |
| |
| rc = lis2dh12_set_int1_thresh(itf, reg); |
| if (rc) { |
| goto err; |
| } |
| |
| reg = LIS2DH12_CTRL_REG3_I1_IA1; |
| |
| rc = lis2dh12_set_int1_pin_cfg(itf, reg); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = lis2dh12_set_int1_duration(itf, 3); |
| if (rc) { |
| goto err; |
| } |
| |
| os_time_delay((OS_TICKS_PER_SEC * 100)/1000 + 1); |
| |
| hal_gpio_irq_release(itf->si_low_pin); |
| |
| rc = hal_gpio_irq_init(itf->si_low_pin, lis2dh12_int_irq_handler, stt, |
| HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_NONE); |
| if (rc) { |
| goto err; |
| } |
| |
| reg = low_thresh.sad->sad_x_is_valid ? LIS2DH12_INT2_CFG_XLIE : 0; |
| reg |= low_thresh.sad->sad_y_is_valid ? LIS2DH12_INT2_CFG_YLIE : 0; |
| reg |= low_thresh.sad->sad_z_is_valid ? LIS2DH12_INT2_CFG_ZLIE : 0; |
| |
| rc = lis2dh12_clear_int1(itf); |
| if (rc) { |
| goto err; |
| } |
| |
| os_time_delay((OS_TICKS_PER_SEC * 20)/1000 + 1); |
| |
| hal_gpio_irq_enable(itf->si_low_pin); |
| |
| rc = lis2dh12_enable_int1(itf, ®); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| err: |
| hal_gpio_irq_release(itf->si_low_pin); |
| return rc; |
| } |
| |
| static int |
| lis2dh12_set_high_thresh(struct sensor_itf *itf, |
| sensor_data_t high_thresh, |
| uint8_t fs, |
| struct sensor_type_traits *stt) |
| { |
| int16_t acc_mg; |
| uint8_t reg; |
| int rc; |
| |
| rc = 0; |
| if (high_thresh.sad->sad_x_is_valid || |
| high_thresh.sad->sad_y_is_valid || |
| high_thresh.sad->sad_z_is_valid) { |
| |
| if (high_thresh.sad->sad_x_is_valid) { |
| lis2dh12_calc_acc_mg(high_thresh.sad->sad_x, &acc_mg); |
| reg = acc_mg/fs; |
| } |
| |
| if (high_thresh.sad->sad_y_is_valid) { |
| lis2dh12_calc_acc_mg(high_thresh.sad->sad_y, &acc_mg); |
| if (reg < acc_mg/fs) { |
| reg = acc_mg/fs; |
| } |
| } |
| |
| if (high_thresh.sad->sad_z_is_valid) { |
| lis2dh12_calc_acc_mg(high_thresh.sad->sad_z, &acc_mg); |
| if (reg < acc_mg/fs) { |
| reg = acc_mg/fs; |
| } |
| } |
| |
| rc = lis2dh12_set_int2_thresh(itf, reg); |
| if (rc) { |
| goto err; |
| } |
| |
| reg = LIS2DH12_CTRL_REG6_I2_IA2; |
| |
| rc = lis2dh12_set_int2_pin_cfg(itf, reg); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = lis2dh12_set_int2_duration(itf, 3); |
| if (rc) { |
| goto err; |
| } |
| |
| os_time_delay((OS_TICKS_PER_SEC * 100)/1000 + 1); |
| |
| hal_gpio_irq_release(itf->si_high_pin); |
| |
| rc = hal_gpio_irq_init(itf->si_high_pin, lis2dh12_int_irq_handler, stt, |
| HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_NONE); |
| if (rc) { |
| goto err; |
| } |
| |
| reg = high_thresh.sad->sad_x_is_valid ? LIS2DH12_INT2_CFG_XHIE : 0; |
| reg |= high_thresh.sad->sad_y_is_valid ? LIS2DH12_INT2_CFG_YHIE : 0; |
| reg |= high_thresh.sad->sad_z_is_valid ? LIS2DH12_INT2_CFG_ZHIE : 0; |
| |
| rc = lis2dh12_clear_int2(itf); |
| if (rc) { |
| goto err; |
| } |
| |
| hal_gpio_irq_enable(itf->si_high_pin); |
| |
| rc = lis2dh12_enable_int2(itf, ®); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| err: |
| hal_gpio_irq_release(itf->si_high_pin); |
| return rc; |
| } |
| |
| |
| /** |
| * Set the trigger threshold values and enable interrupts |
| * |
| * @param ptr to sensor |
| * @param the Sensor type |
| * @param Sensor type traits |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| lis2dh12_sensor_set_trigger_thresh(struct sensor *sensor, |
| sensor_type_t type, |
| struct sensor_type_traits *stt) |
| { |
| int rc; |
| uint8_t fs; |
| struct sensor_itf *itf; |
| sensor_data_t low_thresh; |
| sensor_data_t high_thresh; |
| |
| itf = SENSOR_GET_ITF(sensor); |
| |
| if (type != SENSOR_TYPE_ACCELEROMETER) { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| memcpy(&low_thresh, &stt->stt_low_thresh, sizeof(low_thresh)); |
| memcpy(&high_thresh, &stt->stt_high_thresh, sizeof(high_thresh)); |
| |
| rc = lis2dh12_get_full_scale(itf, &fs); |
| if (rc) { |
| goto err; |
| } |
| |
| if (fs == LIS2DH12_FS_2G) { |
| fs = 16; |
| } else if (fs == LIS2DH12_FS_4G) { |
| fs = 32; |
| } else if (fs == LIS2DH12_FS_8G) { |
| fs = 62; |
| } else if (fs == LIS2DH12_FS_16G) { |
| fs = 186; |
| } else { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| /* Set low threshold and enable interrupt */ |
| rc = lis2dh12_set_low_thresh(itf, low_thresh, fs, stt); |
| if (rc) { |
| goto err; |
| } |
| |
| /* Set high threshold and enable interrupt */ |
| rc = lis2dh12_set_high_thresh(itf, high_thresh, fs, stt); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| |
| err: |
| return rc; |
| } |
| |
| /** |
| * Configure the sensor |
| * |
| * @param ptr to sensor driver |
| * @param ptr to sensor driver config |
| */ |
| int |
| lis2dh12_config(struct lis2dh12 *lis2dh12, struct lis2dh12_cfg *cfg) |
| { |
| int rc; |
| struct sensor_itf *itf; |
| uint8_t chip_id; |
| struct sensor *sensor; |
| |
| itf = SENSOR_GET_ITF(&(lis2dh12->sensor)); |
| sensor = &(lis2dh12->sensor); |
| |
| if (itf->si_type == SENSOR_ITF_SPI) { |
| |
| rc = hal_spi_disable(sensor->s_itf.si_num); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = hal_spi_config(sensor->s_itf.si_num, &spi_lis2dh12_settings); |
| if (rc == EINVAL) { |
| /* If spi is already enabled, for nrf52, it returns -1, We should not |
| * fail if the spi is already enabled |
| */ |
| goto err; |
| } |
| |
| rc = hal_spi_enable(sensor->s_itf.si_num); |
| if (rc) { |
| goto err; |
| } |
| } |
| |
| rc = lis2dh12_get_chip_id(itf, &chip_id); |
| if (rc) { |
| goto err; |
| } |
| |
| if (chip_id != LIS2DH12_ID) { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| rc = lis2dh12_reset(itf); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = lis2dh12_pull_up_disc(itf, cfg->lc_pull_up_disc); |
| if (rc) { |
| goto err; |
| } |
| |
| lis2dh12->cfg.lc_pull_up_disc = cfg->lc_pull_up_disc; |
| |
| rc = lis2dh12_hpf_cfg(itf, 0x00); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = lis2dh12_set_full_scale(itf, cfg->lc_fs); |
| if (rc) { |
| goto err; |
| } |
| |
| lis2dh12->cfg.lc_fs = cfg->lc_fs; |
| |
| rc = lis2dh12_set_rate(itf, cfg->lc_rate); |
| if (rc) { |
| goto err; |
| } |
| |
| lis2dh12->cfg.lc_rate = cfg->lc_rate; |
| |
| rc = lis2dh12_chan_enable(itf, LIS2DH12_CTRL_REG1_XPEN | |
| LIS2DH12_CTRL_REG1_YPEN | |
| LIS2DH12_CTRL_REG1_ZPEN); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = lis2dh12_set_self_test_mode(itf, LIS2DH12_ST_MODE_DISABLE); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = lis2dh12_set_op_mode(itf, LIS2DH12_OM_HIGH_RESOLUTION); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = lis2dh12_set_fifo_mode(itf, LIS2DH12_FIFO_M_BYPASS); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = sensor_set_type_mask(&(lis2dh12->sensor), cfg->lc_s_mask); |
| if (rc) { |
| goto err; |
| } |
| |
| lis2dh12->cfg.lc_s_mask = cfg->lc_s_mask; |
| |
| return 0; |
| err: |
| return rc; |
| } |