1 /*
2 * Copyright (c) 2016 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ti_tmp007
8
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/gpio.h>
11 #include <zephyr/sys/util.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/drivers/sensor.h>
14
15 #include "tmp007.h"
16
17 extern struct tmp007_data tmp007_driver;
18
19 #include <zephyr/logging/log.h>
20 LOG_MODULE_DECLARE(TMP007, CONFIG_SENSOR_LOG_LEVEL);
21
setup_int(const struct device * dev,bool enable)22 static inline void setup_int(const struct device *dev,
23 bool enable)
24 {
25 const struct tmp007_config *cfg = dev->config;
26
27 gpio_pin_interrupt_configure_dt(&cfg->int_gpio,
28 enable
29 ? GPIO_INT_LEVEL_ACTIVE
30 : GPIO_INT_DISABLE);
31 }
32
tmp007_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)33 int tmp007_attr_set(const struct device *dev,
34 enum sensor_channel chan,
35 enum sensor_attribute attr,
36 const struct sensor_value *val)
37 {
38 const struct tmp007_config *cfg = dev->config;
39 int64_t value;
40 uint8_t reg;
41
42 if (!cfg->int_gpio.port) {
43 return -ENOTSUP;
44 }
45
46 if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
47 return -ENOTSUP;
48 }
49
50 if (attr == SENSOR_ATTR_UPPER_THRESH) {
51 reg = TMP007_REG_TOBJ_TH_HIGH;
52 } else if (attr == SENSOR_ATTR_LOWER_THRESH) {
53 reg = TMP007_REG_TOBJ_TH_LOW;
54 } else {
55 return -ENOTSUP;
56 }
57
58 value = (int64_t)val->val1 * 1000000 + val->val2;
59 value = (value / TMP007_TEMP_TH_SCALE) << 6;
60
61 if (tmp007_reg_write(&cfg->i2c, reg, value) < 0) {
62 LOG_DBG("Failed to set attribute!");
63 return -EIO;
64 }
65
66 return 0;
67 }
68
tmp007_gpio_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)69 static void tmp007_gpio_callback(const struct device *dev,
70 struct gpio_callback *cb, uint32_t pins)
71 {
72 struct tmp007_data *drv_data =
73 CONTAINER_OF(cb, struct tmp007_data, gpio_cb);
74
75 setup_int(drv_data->dev, false);
76
77 #if defined(CONFIG_TMP007_TRIGGER_OWN_THREAD)
78 k_sem_give(&drv_data->gpio_sem);
79 #elif defined(CONFIG_TMP007_TRIGGER_GLOBAL_THREAD)
80 k_work_submit(&drv_data->work);
81 #endif
82 }
83
tmp007_thread_cb(const struct device * dev)84 static void tmp007_thread_cb(const struct device *dev)
85 {
86 struct tmp007_data *drv_data = dev->data;
87 const struct tmp007_config *cfg = dev->config;
88 uint16_t status;
89
90 if (tmp007_reg_read(&cfg->i2c, TMP007_REG_STATUS, &status) < 0) {
91 return;
92 }
93
94 if (status & TMP007_DATA_READY_INT_BIT &&
95 drv_data->drdy_handler != NULL) {
96 drv_data->drdy_handler(dev, drv_data->drdy_trigger);
97 }
98
99 if (status & TMP007_TOBJ_TH_INT_BITS &&
100 drv_data->th_handler != NULL) {
101 drv_data->th_handler(dev, drv_data->th_trigger);
102 }
103
104 setup_int(dev, true);
105 }
106
107 #ifdef CONFIG_TMP007_TRIGGER_OWN_THREAD
tmp007_thread(void * p1,void * p2,void * p3)108 static void tmp007_thread(void *p1, void *p2, void *p3)
109 {
110 ARG_UNUSED(p2);
111 ARG_UNUSED(p3);
112
113 struct tmp007_data *drv_data = p1;
114
115 while (1) {
116 k_sem_take(&drv_data->gpio_sem, K_FOREVER);
117 tmp007_thread_cb(drv_data->dev);
118 }
119 }
120 #endif
121
122 #ifdef CONFIG_TMP007_TRIGGER_GLOBAL_THREAD
tmp007_work_cb(struct k_work * work)123 static void tmp007_work_cb(struct k_work *work)
124 {
125 struct tmp007_data *drv_data =
126 CONTAINER_OF(work, struct tmp007_data, work);
127
128 tmp007_thread_cb(drv_data->dev);
129 }
130 #endif
131
tmp007_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)132 int tmp007_trigger_set(const struct device *dev,
133 const struct sensor_trigger *trig,
134 sensor_trigger_handler_t handler)
135 {
136 struct tmp007_data *drv_data = dev->data;
137 const struct tmp007_config *cfg = dev->config;
138
139 if (!cfg->int_gpio.port) {
140 return -ENOTSUP;
141 }
142
143 setup_int(dev, false);
144
145 if (trig->type == SENSOR_TRIG_DATA_READY) {
146 drv_data->drdy_handler = handler;
147 drv_data->drdy_trigger = trig;
148 } else if (trig->type == SENSOR_TRIG_THRESHOLD) {
149 drv_data->th_handler = handler;
150 drv_data->th_trigger = trig;
151 }
152
153 setup_int(dev, true);
154
155 return 0;
156 }
157
tmp007_init_interrupt(const struct device * dev)158 int tmp007_init_interrupt(const struct device *dev)
159 {
160 struct tmp007_data *drv_data = dev->data;
161 const struct tmp007_config *cfg = dev->config;
162
163 if (tmp007_reg_update(&cfg->i2c, TMP007_REG_CONFIG,
164 TMP007_ALERT_EN_BIT, TMP007_ALERT_EN_BIT) < 0) {
165 LOG_DBG("Failed to enable interrupt pin!");
166 return -EIO;
167 }
168
169 drv_data->dev = dev;
170
171 if (!gpio_is_ready_dt(&cfg->int_gpio)) {
172 LOG_ERR("%s: device %s is not ready", dev->name,
173 cfg->int_gpio.port->name);
174 return -ENODEV;
175 }
176
177 gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INT_LEVEL_ACTIVE);
178
179 gpio_init_callback(&drv_data->gpio_cb,
180 tmp007_gpio_callback,
181 BIT(cfg->int_gpio.pin));
182
183 if (gpio_add_callback(cfg->int_gpio.port, &drv_data->gpio_cb) < 0) {
184 LOG_DBG("Failed to set gpio callback!");
185 return -EIO;
186 }
187
188 #if defined(CONFIG_TMP007_TRIGGER_OWN_THREAD)
189 k_sem_init(&drv_data->gpio_sem, 0, K_SEM_MAX_LIMIT);
190
191 k_thread_create(&drv_data->thread, drv_data->thread_stack,
192 CONFIG_TMP007_THREAD_STACK_SIZE,
193 tmp007_thread, drv_data,
194 NULL, NULL, K_PRIO_COOP(CONFIG_TMP007_THREAD_PRIORITY),
195 0, K_NO_WAIT);
196 #elif defined(CONFIG_TMP007_TRIGGER_GLOBAL_THREAD)
197 drv_data->work.handler = tmp007_work_cb;
198 #endif
199
200 return 0;
201 }
202