1 /*
2 * Copyright (c) 2016 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ti_hdc
8
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/drivers/gpio.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/drivers/sensor.h>
14 #include <zephyr/sys/util.h>
15 #include <zephyr/sys/__assert.h>
16 #include <zephyr/logging/log.h>
17
18 #include "ti_hdc.h"
19
20 LOG_MODULE_REGISTER(TI_HDC, CONFIG_SENSOR_LOG_LEVEL);
21
ti_hdc_gpio_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)22 static void ti_hdc_gpio_callback(const struct device *dev,
23 struct gpio_callback *cb, uint32_t pins)
24 {
25 struct ti_hdc_data *drv_data =
26 CONTAINER_OF(cb, struct ti_hdc_data, gpio_cb);
27 const struct ti_hdc_config *cfg = drv_data->dev->config;
28
29 ARG_UNUSED(pins);
30
31 gpio_pin_interrupt_configure_dt(&cfg->drdy, GPIO_INT_DISABLE);
32 k_sem_give(&drv_data->data_sem);
33 }
34
ti_hdc_sample_fetch(const struct device * dev,enum sensor_channel chan)35 static int ti_hdc_sample_fetch(const struct device *dev,
36 enum sensor_channel chan)
37 {
38 struct ti_hdc_data *drv_data = dev->data;
39 const struct ti_hdc_config *cfg = dev->config;
40 uint8_t buf[4];
41
42 __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);
43
44 if (cfg->drdy.port) {
45 gpio_pin_interrupt_configure_dt(&cfg->drdy, GPIO_INT_EDGE_TO_ACTIVE);
46 }
47
48 buf[0] = TI_HDC_REG_TEMP;
49 if (i2c_write_dt(&cfg->i2c, buf, 1) < 0) {
50 LOG_DBG("Failed to write address pointer");
51 return -EIO;
52 }
53
54 if (cfg->drdy.port) {
55 k_sem_take(&drv_data->data_sem, K_FOREVER);
56 } else {
57 /* wait for the conversion to finish */
58 k_msleep(HDC_CONVERSION_TIME);
59 }
60
61 if (i2c_read_dt(&cfg->i2c, buf, 4) < 0) {
62 LOG_DBG("Failed to read sample data");
63 return -EIO;
64 }
65
66 drv_data->t_sample = (buf[0] << 8) + buf[1];
67 drv_data->rh_sample = (buf[2] << 8) + buf[3];
68
69 return 0;
70 }
71
72
ti_hdc_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)73 static int ti_hdc_channel_get(const struct device *dev,
74 enum sensor_channel chan,
75 struct sensor_value *val)
76 {
77 struct ti_hdc_data *drv_data = dev->data;
78 uint64_t tmp;
79
80 /*
81 * See datasheet "Temperature Register" and "Humidity
82 * Register" sections for more details on processing
83 * sample data.
84 */
85 if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
86 /* val = -40 + 165 * sample / 2^16 */
87 tmp = (uint64_t)drv_data->t_sample * 165U;
88 val->val1 = (int32_t)(tmp >> 16) - 40;
89 val->val2 = ((tmp & 0xFFFF) * 1000000U) >> 16;
90 } else if (chan == SENSOR_CHAN_HUMIDITY) {
91 /* val = 100 * sample / 2^16 */
92 tmp = (uint64_t)drv_data->rh_sample * 100U;
93 val->val1 = tmp >> 16;
94 /* x * 1000000 / 65536 == x * 15625 / 1024 */
95 val->val2 = ((tmp & 0xFFFF) * 15625U) >> 10;
96 } else {
97 return -ENOTSUP;
98 }
99
100 return 0;
101 }
102
103 static DEVICE_API(sensor, ti_hdc_driver_api) = {
104 .sample_fetch = ti_hdc_sample_fetch,
105 .channel_get = ti_hdc_channel_get,
106 };
107
read16(const struct i2c_dt_spec * i2c,uint8_t d)108 static uint16_t read16(const struct i2c_dt_spec *i2c, uint8_t d)
109 {
110 uint8_t buf[2];
111 if (i2c_burst_read_dt(i2c, d, (uint8_t *)buf, 2) < 0) {
112 LOG_ERR("Error reading register.");
113 }
114 return (buf[0] << 8 | buf[1]);
115 }
116
ti_hdc_init(const struct device * dev)117 static int ti_hdc_init(const struct device *dev)
118 {
119 const struct ti_hdc_config *cfg = dev->config;
120 uint16_t tmp;
121
122 if (!device_is_ready(cfg->i2c.bus)) {
123 LOG_ERR("Bus device is not ready");
124 return -ENODEV;
125 }
126
127 if (read16(&cfg->i2c, TI_HDC_REG_MANUFID) != TI_HDC_MANUFID) {
128 LOG_ERR("Failed to get correct manufacturer ID");
129 return -EINVAL;
130 }
131 tmp = read16(&cfg->i2c, TI_HDC_REG_DEVICEID);
132 if (tmp != TI_HDC1000_DEVID && tmp != TI_HDC1050_DEVID) {
133 LOG_ERR("Unsupported device ID");
134 return -EINVAL;
135 }
136
137 if (cfg->drdy.port) {
138 struct ti_hdc_data *drv_data = dev->data;
139
140 drv_data->dev = dev;
141
142 k_sem_init(&drv_data->data_sem, 0, K_SEM_MAX_LIMIT);
143
144 /* setup data ready gpio interrupt */
145 if (!gpio_is_ready_dt(&cfg->drdy)) {
146 LOG_ERR("%s: device %s is not ready", dev->name,
147 cfg->drdy.port->name);
148 return -ENODEV;
149 }
150
151 gpio_pin_configure_dt(&cfg->drdy, GPIO_INPUT);
152
153 gpio_init_callback(&drv_data->gpio_cb,
154 ti_hdc_gpio_callback,
155 BIT(cfg->drdy.pin));
156
157 if (gpio_add_callback(cfg->drdy.port, &drv_data->gpio_cb) < 0) {
158 LOG_DBG("Failed to set GPIO callback");
159 return -EIO;
160 }
161
162 gpio_pin_interrupt_configure_dt(&cfg->drdy, GPIO_INT_EDGE_TO_ACTIVE);
163 }
164
165 LOG_INF("Initialized device successfully");
166
167 return 0;
168 }
169
170 #define TI_HDC_DEFINE(inst) \
171 static struct ti_hdc_data ti_hdc_data_##inst; \
172 \
173 static const struct ti_hdc_config ti_hdc_config_##inst = { \
174 .i2c = I2C_DT_SPEC_INST_GET(inst), \
175 .drdy = GPIO_DT_SPEC_INST_GET_OR(inst, drdy_gpios, { 0 }), \
176 }; \
177 \
178 SENSOR_DEVICE_DT_INST_DEFINE(inst, ti_hdc_init, NULL, \
179 &ti_hdc_data_##inst, &ti_hdc_config_##inst, POST_KERNEL, \
180 CONFIG_SENSOR_INIT_PRIORITY, &ti_hdc_driver_api); \
181
182 DT_INST_FOREACH_STATUS_OKAY(TI_HDC_DEFINE)
183