1 /*
2  * Copyright (c) 2020 Christian Hirsch
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #define DT_DRV_COMPAT maxim_max31855
7 
8 #include <zephyr/kernel.h>
9 #include <zephyr/drivers/sensor.h>
10 #include <zephyr/init.h>
11 #include <zephyr/drivers/gpio.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/sys/__assert.h>
14 #include <zephyr/drivers/spi.h>
15 #include <zephyr/logging/log.h>
16 #include <zephyr/types.h>
17 #include <zephyr/device.h>
18 
19 #define THERMOCOUPLE_TEMPERATURE_POS 18
20 #define INTERNAL_TEMPERATURE_POS     4
21 #define THERMOCOUPLE_SIGN_BITS	     0xffff2000
22 #define INTERNAL_SIGN_BITS	     0xfffff800
23 #define THERMOCOUPLE_RESOLUTION	     25
24 #define INTERNAL_RESOLUTION	     625
25 
26 LOG_MODULE_REGISTER(MAX31855, CONFIG_SENSOR_LOG_LEVEL);
27 
28 struct max31855_config {
29 	struct spi_dt_spec spi;
30 };
31 
32 struct max31855_data {
33 	uint32_t sample;
34 };
35 
max31855_sample_fetch(const struct device * dev,enum sensor_channel chan)36 static int max31855_sample_fetch(const struct device *dev, enum sensor_channel chan)
37 {
38 	struct max31855_data *data = dev->data;
39 	const struct max31855_config *config = dev->config;
40 	int ret;
41 
42 	__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);
43 
44 	struct spi_buf rx_buf = {
45 		.buf = &(data->sample),
46 		.len = sizeof(data->sample),
47 	};
48 	const struct spi_buf_set rx = {.buffers = &rx_buf, .count = 1};
49 
50 	ret = spi_read_dt(&config->spi, &rx);
51 	if (ret < 0) {
52 		LOG_ERR("max31855_read FAIL %d", ret);
53 		return ret;
54 	}
55 
56 	return 0;
57 }
58 
max31855_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)59 static int max31855_channel_get(const struct device *dev, enum sensor_channel chan,
60 				struct sensor_value *val)
61 {
62 	struct max31855_data *data = dev->data;
63 	uint32_t temp = sys_be32_to_cpu(data->sample);
64 
65 	if (temp & BIT(16)) {
66 		return -EIO;
67 	}
68 
69 	switch (chan) {
70 
71 	case SENSOR_CHAN_AMBIENT_TEMP:
72 		temp = (temp >> THERMOCOUPLE_TEMPERATURE_POS) & 0x3fff;
73 
74 		/* if sign bit is set, make value negative */
75 		if (temp & BIT(14)) {
76 			temp |= THERMOCOUPLE_SIGN_BITS;
77 		}
78 
79 		temp = temp * THERMOCOUPLE_RESOLUTION;
80 
81 		val->val1 = temp / 100;
82 		val->val2 = (temp - val->val1 * 100) * 10000;
83 		break;
84 
85 	case SENSOR_CHAN_DIE_TEMP:
86 		temp = (temp >> INTERNAL_TEMPERATURE_POS) & 0xfff;
87 
88 		/* if sign bit is set, make value negative */
89 		if (temp & BIT(12)) {
90 			temp |= INTERNAL_SIGN_BITS;
91 		}
92 
93 		temp = temp * INTERNAL_RESOLUTION;
94 
95 		val->val1 = temp / 10000;
96 		val->val2 = (temp - val->val1 * 10000) * 100;
97 		break;
98 
99 	default:
100 		return -ENOTSUP;
101 	}
102 
103 	return 0;
104 }
105 
106 static DEVICE_API(sensor, max31855_api) = {
107 	.sample_fetch = max31855_sample_fetch,
108 	.channel_get = max31855_channel_get,
109 };
110 
max31855_init(const struct device * dev)111 static int max31855_init(const struct device *dev)
112 {
113 	const struct max31855_config *config = dev->config;
114 
115 	if (!spi_is_ready_dt(&config->spi)) {
116 		LOG_ERR("SPI bus is not ready");
117 		return -ENODEV;
118 	}
119 
120 	return 0;
121 }
122 
123 #define MAX31855_INIT(n)                                                                           \
124 	static struct max31855_data max31855_data_##n;                                             \
125 	static const struct max31855_config max31855_config_##n = {                                \
126 		.spi = SPI_DT_SPEC_INST_GET(n, SPI_OP_MODE_MASTER | SPI_WORD_SET(8U), 0U),         \
127 	};                                                                                         \
128 	SENSOR_DEVICE_DT_INST_DEFINE(n, &max31855_init, NULL, &max31855_data_##n,                  \
129 				     &max31855_config_##n, POST_KERNEL,                            \
130 				     CONFIG_SENSOR_INIT_PRIORITY, &max31855_api);
131 
132 DT_INST_FOREACH_STATUS_OKAY(MAX31855_INIT)
133