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