1 /*
2  * Copyright (c) 2024 Arrow Electronics.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT ti_tmp1075
8 
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/drivers/gpio.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/sys/util.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/drivers/sensor.h>
16 #include <zephyr/sys/__assert.h>
17 #include <zephyr/logging/log.h>
18 
19 #include "tmp1075.h"
20 
21 LOG_MODULE_REGISTER(TMP1075, CONFIG_SENSOR_LOG_LEVEL);
22 
23 #define I2C_REG_ADDR_SIZE   1
24 #define I2C_REG_SENSOR_SIZE sizeof(uint16_t)
25 #define I2C_BUFFER_SIZE     I2C_REG_ADDR_SIZE + I2C_REG_SENSOR_SIZE
26 
27 #define I2C_REG_ADDR_OFFSET   0
28 #define I2C_WRITE_DATA_OFFSET 1
29 
tmp1075_reg_read(const struct tmp1075_config * cfg,uint8_t reg,uint16_t * val)30 static int tmp1075_reg_read(const struct tmp1075_config *cfg, uint8_t reg, uint16_t *val)
31 {
32 	if (i2c_burst_read_dt(&cfg->bus, reg, (uint8_t *)val, sizeof(*val)) < 0) {
33 		return -EIO;
34 	}
35 	*val = sys_be16_to_cpu(*val);
36 	return 0;
37 }
38 
tmp1075_reg_write(const struct tmp1075_config * cfg,uint8_t reg,uint16_t val)39 static int tmp1075_reg_write(const struct tmp1075_config *cfg, uint8_t reg, uint16_t val)
40 {
41 	uint8_t buf[I2C_REG_ADDR_SIZE + I2C_REG_SENSOR_SIZE];
42 
43 	buf[I2C_REG_ADDR_OFFSET] = reg;
44 	sys_put_be16(val, &buf[I2C_WRITE_DATA_OFFSET]);
45 
46 	return i2c_write_dt(&cfg->bus, buf, sizeof(buf));
47 }
48 
49 #if CONFIG_TMP1075_ALERT_INTERRUPTS
set_threshold_attribute(const struct device * dev,uint8_t reg,int16_t value,const char * error_msg)50 static int set_threshold_attribute(const struct device *dev, uint8_t reg, int16_t value,
51 				   const char *error_msg)
52 {
53 	if (tmp1075_reg_write(dev->config, reg, value) < 0) {
54 		LOG_ERR("Failed to set %s attribute!", error_msg);
55 		return -EIO;
56 	}
57 	return 0;
58 }
59 #endif
60 
tmp1075_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)61 static int tmp1075_attr_set(const struct device *dev, enum sensor_channel chan,
62 			    enum sensor_attribute attr, const struct sensor_value *val)
63 {
64 	if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
65 		return -ENOTSUP;
66 	}
67 
68 	switch (attr) {
69 #if CONFIG_TMP1075_ALERT_INTERRUPTS
70 	case SENSOR_ATTR_LOWER_THRESH:
71 		return set_threshold_attribute(dev, TMP1075_REG_TLOW, val->val1 << 8,
72 					       "SENSOR_ATTR_LOWER_THRESH");
73 
74 	case SENSOR_ATTR_UPPER_THRESH:
75 		return set_threshold_attribute(dev, TMP1075_REG_THIGH, val->val1 << 8,
76 					       "SENSOR_ATTR_UPPER_THRESH");
77 #endif
78 
79 	default:
80 		return -ENOTSUP;
81 	}
82 }
83 
84 #if CONFIG_TMP1075_ALERT_INTERRUPTS
get_threshold_attribute(const struct device * dev,uint8_t reg,struct sensor_value * val,const char * error_msg)85 static int get_threshold_attribute(const struct device *dev, uint8_t reg, struct sensor_value *val,
86 				   const char *error_msg)
87 {
88 	uint16_t value;
89 
90 	if (tmp1075_reg_read(dev->config, reg, &value) < 0) {
91 		LOG_ERR("Failed to get %s attribute!", error_msg);
92 		return -EIO;
93 	}
94 	val->val1 = value >> 8;
95 	return 0;
96 }
97 #endif
98 
tmp1075_attr_get(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,struct sensor_value * val)99 static int tmp1075_attr_get(const struct device *dev, enum sensor_channel chan,
100 			    enum sensor_attribute attr, struct sensor_value *val)
101 {
102 	if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
103 		return -ENOTSUP;
104 	}
105 
106 	switch (attr) {
107 #if CONFIG_TMP1075_ALERT_INTERRUPTS
108 	case SENSOR_ATTR_LOWER_THRESH:
109 		return get_threshold_attribute(dev, TMP1075_REG_TLOW, val,
110 					       "SENSOR_ATTR_LOWER_THRESH");
111 
112 	case SENSOR_ATTR_UPPER_THRESH:
113 		return get_threshold_attribute(dev, TMP1075_REG_THIGH, val,
114 					       "SENSOR_ATTR_UPPER_THRESH");
115 #endif
116 
117 	default:
118 		return -ENOTSUP;
119 	}
120 }
121 
tmp1075_sample_fetch(const struct device * dev,enum sensor_channel chan)122 static int tmp1075_sample_fetch(const struct device *dev, enum sensor_channel chan)
123 {
124 	struct tmp1075_data *drv_data = dev->data;
125 	const struct tmp1075_config *cfg = dev->config;
126 	uint16_t val;
127 
128 	__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_AMBIENT_TEMP);
129 
130 	if (tmp1075_reg_read(cfg, TMP1075_REG_TEMPERATURE, &val) < 0) {
131 		return -EIO;
132 	}
133 	drv_data->sample = arithmetic_shift_right((int16_t)val, TMP1075_DATA_NORMAL_SHIFT);
134 	return 0;
135 }
136 
tmp1075_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)137 static int tmp1075_channel_get(const struct device *dev, enum sensor_channel chan,
138 			       struct sensor_value *val)
139 {
140 	struct tmp1075_data *drv_data = dev->data;
141 	int32_t uval;
142 
143 	if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
144 		return -ENOTSUP;
145 	}
146 
147 	uval = (int32_t)drv_data->sample * TMP1075_TEMP_SCALE;
148 	val->val1 = uval / uCELSIUS_IN_CELSIUS;
149 	val->val2 = uval % uCELSIUS_IN_CELSIUS;
150 
151 	return 0;
152 }
153 
154 static DEVICE_API(sensor, tmp1075_driver_api) = {
155 	.attr_set = tmp1075_attr_set,
156 	.attr_get = tmp1075_attr_get,
157 	.sample_fetch = tmp1075_sample_fetch,
158 	.channel_get = tmp1075_channel_get,
159 #ifdef CONFIG_TMP1075_ALERT_INTERRUPTS
160 	.trigger_set = tmp1075_trigger_set,
161 #endif
162 };
163 
164 #ifdef CONFIG_TMP1075_ALERT_INTERRUPTS
setup_interrupts(const struct device * dev)165 static int setup_interrupts(const struct device *dev)
166 {
167 	struct tmp1075_data *drv_data = dev->data;
168 	const struct tmp1075_config *config = dev->config;
169 	const struct gpio_dt_spec *alert_gpio = &config->alert_gpio;
170 	int result;
171 
172 	if (!gpio_is_ready_dt(alert_gpio)) {
173 		LOG_ERR("tmp1075: gpio controller %s not ready", alert_gpio->port->name);
174 		return -ENODEV;
175 	}
176 
177 	result = gpio_pin_configure_dt(alert_gpio, GPIO_INPUT);
178 
179 	if (result < 0) {
180 		return result;
181 	}
182 
183 	gpio_init_callback(&drv_data->temp_alert_gpio_cb, tmp1075_trigger_handle_alert,
184 			   BIT(alert_gpio->pin));
185 
186 	result = gpio_add_callback(alert_gpio->port, &drv_data->temp_alert_gpio_cb);
187 
188 	if (result < 0) {
189 		return result;
190 	}
191 
192 	result = gpio_pin_interrupt_configure_dt(alert_gpio, GPIO_INT_EDGE_BOTH);
193 
194 	if (result < 0) {
195 		return result;
196 	}
197 
198 	return 0;
199 }
200 #endif
201 
tmp1075_init(const struct device * dev)202 static int tmp1075_init(const struct device *dev)
203 {
204 	const struct tmp1075_config *cfg = dev->config;
205 	struct tmp1075_data *data = dev->data;
206 
207 	if (!i2c_is_ready_dt(&cfg->bus)) {
208 		LOG_ERR("I2C dev %s not ready", cfg->bus.bus->name);
209 		return -EINVAL;
210 	}
211 #ifdef CONFIG_TMP1075_ALERT_INTERRUPTS
212 	int result = setup_interrupts(dev);
213 
214 	if (result < 0) {
215 		LOG_ERR("Couldn't setup interrupts");
216 		return -EIO;
217 	}
218 #endif
219 	data->tmp1075_dev = dev;
220 
221 	uint16_t config_reg = 0;
222 
223 	TMP1075_SET_ONE_SHOT_CONVERSION(config_reg, cfg->one_shot);
224 	TMP1075_SET_CONVERSION_RATE(config_reg, cfg->cr);
225 	TMP1075_SET_CONSECUTIVE_FAULT_MEASUREMENTS(config_reg, cfg->cf);
226 	TMP1075_SET_ALERT_PIN_POLARITY(config_reg, cfg->alert_pol);
227 	TMP1075_SET_ALERT_PIN_FUNCTION(config_reg, cfg->interrupt_mode);
228 	TMP1075_SET_SHUTDOWN_MODE(config_reg, cfg->shutdown_mode);
229 
230 	int rc = tmp1075_reg_write(dev->config, TMP1075_REG_CONFIG, config_reg);
231 
232 	if (rc == 0) {
233 		data->config_reg = config_reg;
234 	}
235 	return rc;
236 }
237 
238 #define TMP1075_INST(inst)                                                                         \
239 	static struct tmp1075_data tmp1075_data_##inst;                                            \
240 	static const struct tmp1075_config tmp1075_config_##inst = {                               \
241 		.cr = DT_INST_ENUM_IDX(inst, conversion_rate),                                     \
242 		.cf = DT_INST_ENUM_IDX(inst, consecutive_fault_measurements),                      \
243 		.alert_pol = DT_INST_PROP(inst, alert_pin_active_high),                            \
244 		.interrupt_mode = DT_INST_PROP(inst, interrupt_mode),                              \
245 		.shutdown_mode = DT_INST_PROP(inst, shutdown_mode),                                \
246 		.bus = I2C_DT_SPEC_INST_GET(inst),                                                 \
247 		.alert_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, alert_gpios, {0}),                    \
248 	};                                                                                         \
249 	SENSOR_DEVICE_DT_INST_DEFINE(inst, tmp1075_init, NULL, &tmp1075_data_##inst,               \
250                                                                                                    \
251 				     &tmp1075_config_##inst, POST_KERNEL,                          \
252 				     CONFIG_SENSOR_INIT_PRIORITY, &tmp1075_driver_api);
253 
254 DT_INST_FOREACH_STATUS_OKAY(TMP1075_INST)
255