1 /*
2  * Copyright (c) 2021 Teslabs Engineering S.L.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT maxim_max6675
8 
9 #include <zephyr/drivers/sensor.h>
10 #include <zephyr/drivers/spi.h>
11 #include <zephyr/sys/byteorder.h>
12 
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(max6675, CONFIG_SENSOR_LOG_LEVEL);
15 
16 /** Thermocouple input bit (goes high if thermocouple is disconnected). */
17 #define THERMOCOUPLE_INPUT BIT(2)
18 /** Temperature position. */
19 #define TEMPERATURE_POS 3U
20 /** Temperature resolution (cDeg/LSB). */
21 #define TEMPERATURE_RES 25U
22 
23 struct max6675_config {
24 	struct spi_dt_spec spi;
25 };
26 
27 struct max6675_data {
28 	uint16_t sample;
29 };
30 
max6675_sample_fetch(const struct device * dev,enum sensor_channel chan)31 static int max6675_sample_fetch(const struct device *dev,
32 				enum sensor_channel chan)
33 {
34 	struct max6675_data *data = dev->data;
35 	const struct max6675_config *config = dev->config;
36 
37 	int ret;
38 	uint8_t buf_rx[2];
39 	const struct spi_buf rx_buf = {
40 		.buf = buf_rx,
41 		.len = ARRAY_SIZE(buf_rx)
42 	};
43 	const struct spi_buf_set rx_bufs = {
44 		.buffers = &rx_buf,
45 		.count = 1U
46 	};
47 
48 	if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP) {
49 		return -ENOTSUP;
50 	}
51 
52 	ret = spi_read_dt(&config->spi, &rx_bufs);
53 	if (ret < 0) {
54 		return ret;
55 	}
56 
57 	data->sample = sys_get_be16(buf_rx);
58 
59 	if (data->sample & THERMOCOUPLE_INPUT) {
60 		LOG_INF("Thermocouple not connected");
61 		return -ENOENT;
62 	}
63 
64 	return 0;
65 }
66 
max6675_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)67 static int max6675_channel_get(const struct device *dev, enum sensor_channel chan,
68 			      struct sensor_value *val)
69 {
70 	struct max6675_data *data = dev->data;
71 
72 	int32_t temperature;
73 
74 	if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
75 		return -ENOTSUP;
76 	}
77 
78 	temperature = (data->sample >> TEMPERATURE_POS) * TEMPERATURE_RES;
79 	val->val1 = temperature / 100;
80 	val->val2 = (temperature - val->val1 * 100) * 10000;
81 
82 	return 0;
83 }
84 
85 static DEVICE_API(sensor, max6675_api) = {
86 	.sample_fetch = &max6675_sample_fetch,
87 	.channel_get = &max6675_channel_get,
88 };
89 
max6675_init(const struct device * dev)90 static int max6675_init(const struct device *dev)
91 {
92 	const struct max6675_config *config = dev->config;
93 
94 	if (!spi_is_ready_dt(&config->spi)) {
95 		LOG_ERR("SPI bus is not ready");
96 		return -ENODEV;
97 	}
98 
99 	return 0;
100 }
101 
102 #define MAX6675_INIT(n)							\
103 	static struct max6675_data max6675_data_##n;			\
104 	static const struct max6675_config max6675_config_##n = {	\
105 		.spi = SPI_DT_SPEC_INST_GET(n,				\
106 					    SPI_OP_MODE_MASTER |	\
107 					    SPI_WORD_SET(8U),		\
108 					    0U),			\
109 	};								\
110 	SENSOR_DEVICE_DT_INST_DEFINE(n, &max6675_init, NULL,		\
111 			      &max6675_data_##n, &max6675_config_##n,	\
112 			      POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,	\
113 			      &max6675_api);
114 
115 DT_INST_FOREACH_STATUS_OKAY(MAX6675_INIT)
116