mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-08 08:12:43 +00:00
Put all the devicetree configuration data into a config structure in flash, which removes some ultra-long identifiers from the code and makes it more readable, and prepares for multiple instance support. Consistently use the interrupt signal datasheet name for all objects that are specific to that signal, including configuration structure tags and function names. Update the trigger idiom for setup/handle/process stages. Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
192 lines
4.9 KiB
C
192 lines
4.9 KiB
C
/*
|
|
* Copyright (c) 2016 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <drivers/i2c.h>
|
|
#include <init.h>
|
|
#include <sys/__assert.h>
|
|
#include <sys/byteorder.h>
|
|
#include <drivers/sensor.h>
|
|
#include <string.h>
|
|
#include <logging/log.h>
|
|
|
|
#include "hts221.h"
|
|
|
|
LOG_MODULE_REGISTER(HTS221, CONFIG_SENSOR_LOG_LEVEL);
|
|
|
|
static const char * const hts221_odr_strings[] = {
|
|
"1", "7", "12.5"
|
|
};
|
|
|
|
static int hts221_channel_get(struct device *dev,
|
|
enum sensor_channel chan,
|
|
struct sensor_value *val)
|
|
{
|
|
struct hts221_data *data = dev->driver_data;
|
|
s32_t conv_val;
|
|
|
|
/*
|
|
* see "Interpreting humidity and temperature readings" document
|
|
* for more details
|
|
*/
|
|
if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
|
|
conv_val = (s32_t)(data->t1_degc_x8 - data->t0_degc_x8) *
|
|
(data->t_sample - data->t0_out) /
|
|
(data->t1_out - data->t0_out) +
|
|
data->t0_degc_x8;
|
|
|
|
/* convert temperature x8 to degrees Celsius */
|
|
val->val1 = conv_val / 8;
|
|
val->val2 = (conv_val % 8) * (1000000 / 8);
|
|
} else if (chan == SENSOR_CHAN_HUMIDITY) {
|
|
conv_val = (s32_t)(data->h1_rh_x2 - data->h0_rh_x2) *
|
|
(data->rh_sample - data->h0_t0_out) /
|
|
(data->h1_t0_out - data->h0_t0_out) +
|
|
data->h0_rh_x2;
|
|
|
|
/* convert humidity x2 to percent */
|
|
val->val1 = conv_val / 2;
|
|
val->val2 = (conv_val % 2) * 500000;
|
|
} else {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int hts221_sample_fetch(struct device *dev, enum sensor_channel chan)
|
|
{
|
|
struct hts221_data *data = dev->driver_data;
|
|
const struct hts221_config *cfg = dev->config->config_info;
|
|
u8_t buf[4];
|
|
|
|
__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);
|
|
|
|
if (i2c_burst_read(data->i2c, cfg->i2c_addr,
|
|
HTS221_REG_DATA_START | HTS221_AUTOINCREMENT_ADDR,
|
|
buf, 4) < 0) {
|
|
LOG_ERR("Failed to fetch data sample.");
|
|
return -EIO;
|
|
}
|
|
|
|
data->rh_sample = sys_le16_to_cpu(buf[0] | (buf[1] << 8));
|
|
data->t_sample = sys_le16_to_cpu(buf[2] | (buf[3] << 8));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int hts221_read_conversion_data(struct device *dev)
|
|
{
|
|
struct hts221_data *data = dev->driver_data;
|
|
const struct hts221_config *cfg = dev->config->config_info;
|
|
u8_t buf[16];
|
|
|
|
if (i2c_burst_read(data->i2c, cfg->i2c_addr,
|
|
HTS221_REG_CONVERSION_START |
|
|
HTS221_AUTOINCREMENT_ADDR, buf, 16) < 0) {
|
|
LOG_ERR("Failed to read conversion data.");
|
|
return -EIO;
|
|
}
|
|
|
|
data->h0_rh_x2 = buf[0];
|
|
data->h1_rh_x2 = buf[1];
|
|
data->t0_degc_x8 = sys_le16_to_cpu(buf[2] | ((buf[5] & 0x3) << 8));
|
|
data->t1_degc_x8 = sys_le16_to_cpu(buf[3] | ((buf[5] & 0xC) << 6));
|
|
data->h0_t0_out = sys_le16_to_cpu(buf[6] | (buf[7] << 8));
|
|
data->h1_t0_out = sys_le16_to_cpu(buf[10] | (buf[11] << 8));
|
|
data->t0_out = sys_le16_to_cpu(buf[12] | (buf[13] << 8));
|
|
data->t1_out = sys_le16_to_cpu(buf[14] | (buf[15] << 8));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct sensor_driver_api hts221_driver_api = {
|
|
#if CONFIG_HTS221_TRIGGER
|
|
.trigger_set = hts221_trigger_set,
|
|
#endif
|
|
.sample_fetch = hts221_sample_fetch,
|
|
.channel_get = hts221_channel_get,
|
|
};
|
|
|
|
int hts221_init(struct device *dev)
|
|
{
|
|
const struct hts221_config *cfg = dev->config->config_info;
|
|
struct hts221_data *data = dev->driver_data;
|
|
u8_t id, idx;
|
|
|
|
data->i2c = device_get_binding(cfg->i2c_bus);
|
|
if (data->i2c == NULL) {
|
|
LOG_ERR("Could not get pointer to %s device.", cfg->i2c_bus);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* check chip ID */
|
|
if (i2c_reg_read_byte(data->i2c, cfg->i2c_addr,
|
|
HTS221_REG_WHO_AM_I, &id) < 0) {
|
|
LOG_ERR("Failed to read chip ID.");
|
|
return -EIO;
|
|
}
|
|
|
|
if (id != HTS221_CHIP_ID) {
|
|
LOG_ERR("Invalid chip ID.");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* check if CONFIG_HTS221_ODR is valid */
|
|
for (idx = 0U; idx < ARRAY_SIZE(hts221_odr_strings); idx++) {
|
|
if (!strcmp(hts221_odr_strings[idx], CONFIG_HTS221_ODR)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (idx == ARRAY_SIZE(hts221_odr_strings)) {
|
|
LOG_ERR("Invalid ODR value.");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (i2c_reg_write_byte(data->i2c, cfg->i2c_addr,
|
|
HTS221_REG_CTRL1,
|
|
(idx + 1) << HTS221_ODR_SHIFT | HTS221_BDU_BIT |
|
|
HTS221_PD_BIT) < 0) {
|
|
LOG_ERR("Failed to configure chip.");
|
|
return -EIO;
|
|
}
|
|
|
|
/*
|
|
* the device requires about 2.2 ms to download the flash content
|
|
* into the volatile mem
|
|
*/
|
|
k_sleep(K_MSEC(3));
|
|
|
|
if (hts221_read_conversion_data(dev) < 0) {
|
|
LOG_ERR("Failed to read conversion data.");
|
|
return -EINVAL;
|
|
}
|
|
|
|
#ifdef CONFIG_HTS221_TRIGGER
|
|
if (hts221_init_interrupt(dev) < 0) {
|
|
LOG_ERR("Failed to initialize interrupt.");
|
|
return -EIO;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct hts221_data hts221_driver;
|
|
static const struct hts221_config hts221_cfg = {
|
|
.i2c_bus = DT_INST_0_ST_HTS221_BUS_NAME,
|
|
.i2c_addr = DT_INST_0_ST_HTS221_BASE_ADDRESS,
|
|
#ifdef CONFIG_HTS221_TRIGGER
|
|
.drdy_pin = DT_INST_0_ST_HTS221_DRDY_GPIOS_PIN,
|
|
.drdy_flags = DT_INST_0_ST_HTS221_DRDY_GPIOS_FLAGS,
|
|
.drdy_controller = DT_INST_0_ST_HTS221_DRDY_GPIOS_CONTROLLER,
|
|
#endif /* CONFIG_HTS221_TRIGGER */
|
|
};
|
|
|
|
DEVICE_AND_API_INIT(hts221, DT_INST_0_ST_HTS221_LABEL, hts221_init,
|
|
&hts221_driver, &hts221_cfg, POST_KERNEL,
|
|
CONFIG_SENSOR_INIT_PRIORITY, &hts221_driver_api);
|