1 /*
2  * Copyright 2024 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_p3t1755
8 
9 #include "p3t1755.h"
10 #include <zephyr/sys/util.h>
11 #include <zephyr/sys/__assert.h>
12 #include <zephyr/logging/log.h>
13 #include <stdlib.h>
14 
15 LOG_MODULE_REGISTER(P3T1755, CONFIG_SENSOR_LOG_LEVEL);
16 
17 
18 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
p3t1755_i3c_read_reg(const struct device * dev,uint8_t reg,uint8_t * value,uint8_t len)19 static int p3t1755_i3c_read_reg(const struct device *dev, uint8_t reg, uint8_t *value, uint8_t len)
20 {
21 	struct p3t1755_data *data = dev->data;
22 
23 	return i3c_burst_read(data->i3c_dev, reg, value, len);
24 }
25 
p3t1755_i3c_write_reg(const struct device * dev,uint8_t reg,uint8_t * byte,uint8_t len)26 static int p3t1755_i3c_write_reg(const struct device *dev, uint8_t reg, uint8_t *byte, uint8_t len)
27 {
28 	struct p3t1755_data *data = dev->data;
29 
30 	return i3c_burst_write(data->i3c_dev, reg, byte, len);
31 }
32 #endif
33 
34 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
p3t1755_i2c_read_reg(const struct device * dev,uint8_t reg,uint8_t * value,uint8_t len)35 int p3t1755_i2c_read_reg(const struct device *dev, uint8_t reg, uint8_t *value, uint8_t len)
36 {
37 	const struct p3t1755_config *config = dev->config;
38 
39 	return i2c_burst_read_dt(&config->bus_cfg.i2c, reg, value, len);
40 }
41 
p3t1755_i2c_write_reg(const struct device * dev,uint8_t reg,uint8_t * byte,uint8_t len)42 int p3t1755_i2c_write_reg(const struct device *dev, uint8_t reg, uint8_t *byte, uint8_t len)
43 {
44 	const struct p3t1755_config *config = dev->config;
45 
46 	return i2c_burst_write_dt(&config->bus_cfg.i2c, reg, byte, len);
47 }
48 #endif
49 
p3t1755_sample_fetch(const struct device * dev,enum sensor_channel chan)50 static int p3t1755_sample_fetch(const struct device *dev, enum sensor_channel chan)
51 {
52 	const struct p3t1755_config *config = dev->config;
53 	struct p3t1755_data *data = dev->data;
54 	uint8_t raw_temp[2] = {0};
55 
56 	if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP) {
57 		LOG_ERR("Invalid channel provided");
58 		return -ENOTSUP;
59 	}
60 
61 	if (config->oneshot_mode) {
62 		data->config_reg |= P3T1755_CONFIG_REG_OS;
63 		config->ops.write(dev, P3T1755_CONFIG_REG, &data->config_reg, 1);
64 		/* Maximum one-shot conversion time per specification is 12ms */
65 		k_sleep(K_MSEC(12));
66 	}
67 
68 	int status = config->ops.read(dev, P3T1755_TEMPERATURE_REG, raw_temp, 2);
69 
70 	if (status) {
71 		LOG_ERR("read return error %d", status);
72 		return -ENOTSUP;
73 	}
74 
75 	/* Byte 1 contains the MSByte and Byte 2 contains the LSByte, we need to swap the 2 bytes.
76 	 * The 4 least significant bits of the LSByte are zero and should be ignored.
77 	 */
78 	data->sample = (((uint16_t)raw_temp[0] << 8U) | (uint16_t)raw_temp[1]) >>
79 		       P3T1755_TEMPERATURE_REG_SHIFT;
80 
81 	return 0;
82 }
83 
84 /* Decode a register temperature value to a signed temperature */
p3t1755_convert_to_signed(uint16_t reg)85 static inline int p3t1755_convert_to_signed(uint16_t reg)
86 {
87 	int rv = reg & P3T1755_TEMPERATURE_ABS_MASK;
88 
89 	if (reg & P3T1755_TEMPERATURE_SIGN_BIT) {
90 		/* Convert 12-bit 2s complement to signed negative
91 		 * value.
92 		 */
93 		rv = -(1U + (rv ^ P3T1755_TEMPERATURE_ABS_MASK));
94 	}
95 	return rv;
96 }
97 
p3t1755_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)98 static int p3t1755_channel_get(const struct device *dev, enum sensor_channel chan,
99 			       struct sensor_value *val)
100 {
101 	struct p3t1755_data *data = dev->data;
102 	int32_t raw_val;
103 
104 	if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
105 		return -ENOTSUP;
106 	}
107 
108 	raw_val = p3t1755_convert_to_signed(data->sample);
109 
110 	/* Temperature data resolution is 0.0625 C, apply a temperature scale */
111 	raw_val = raw_val * P3T1755_TEMPERATURE_SCALE;
112 
113 	sensor_value_from_micro(val, raw_val);
114 
115 	return 0;
116 }
117 
p3t1755_init(const struct device * dev)118 static int p3t1755_init(const struct device *dev)
119 {
120 	const struct p3t1755_config *config = dev->config;
121 	struct p3t1755_data *data = dev->data;
122 
123 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
124 	if (config->i3c.bus != NULL) {
125 		data->i3c_dev = i3c_device_find(config->i3c.bus, &config->i3c.dev_id);
126 		if (data->i3c_dev == NULL) {
127 			LOG_ERR("Cannot find I3C device descriptor");
128 			return -ENODEV;
129 		}
130 	}
131 #endif
132 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
133 	if (config->inst_on_bus == P3T1755_BUS_I2C) {
134 		if (!i2c_is_ready_dt(&config->bus_cfg.i2c)) {
135 			LOG_ERR("I2C bus device not ready");
136 			return -ENODEV;
137 		}
138 	}
139 #endif
140 
141 	if (config->oneshot_mode) {
142 		config->ops.read(dev, P3T1755_CONFIG_REG, &data->config_reg, 1);
143 		/* Operate in shutdown mode. Set the OS bit to start the
144 		 * one-shot temperature measurement.
145 		 */
146 		data->config_reg |= P3T1755_CONFIG_REG_SD;
147 		config->ops.write(dev, P3T1755_CONFIG_REG, &data->config_reg, 1);
148 	}
149 
150 	LOG_DBG("Init complete");
151 
152 	return 0;
153 }
154 
155 static DEVICE_API(sensor, p3t1755_driver_api) = {
156 	.sample_fetch = p3t1755_sample_fetch,
157 	.channel_get = p3t1755_channel_get,
158 };
159 
160 /*
161  * Instantiation macros used when a device is on an I2C bus.
162  */
163 #define P3T1755_CONFIG_I2C(inst)                                                                   \
164 	.bus_cfg = {.i2c = I2C_DT_SPEC_INST_GET(inst)},                                            \
165 	.ops = {                                                                                   \
166 		.read = p3t1755_i2c_read_reg,                                                      \
167 		.write = p3t1755_i2c_write_reg,                                                    \
168 	},                                                                                         \
169 	.inst_on_bus = P3T1755_BUS_I2C,
170 
171 /*
172  * Instantiation macros used when a device is on an I#C bus.
173  */
174 #define P3T1755_CONFIG_I3C(inst)                                                                   \
175 	.bus_cfg = {.i3c = &p3t1755_data_##inst.i3c_dev},                                          \
176 	.ops = {                                                                                   \
177 		.read = p3t1755_i3c_read_reg,                                                      \
178 		.write = p3t1755_i3c_write_reg,                                                    \
179 	},                                                                                         \
180 	.inst_on_bus = P3T1755_BUS_I3C,                                                            \
181 	.i3c.bus = DEVICE_DT_GET(DT_INST_BUS(inst)), .i3c.dev_id = I3C_DEVICE_ID_DT_INST(inst),
182 
183 #define P3T1755_INIT(n)                                                                            \
184 	static struct p3t1755_data p3t1755_data_##n;                                               \
185 	static const struct p3t1755_config p3t1755_config_##n = {                                  \
186 		COND_CODE_1(DT_INST_ON_BUS(n, i3c),                                                \
187 				(P3T1755_CONFIG_I3C(n)),                                           \
188 				(P3T1755_CONFIG_I2C(n)))                                           \
189 		.oneshot_mode = DT_INST_PROP(n, oneshot_mode),                                     \
190 	};                                                                                         \
191                                                                                                    \
192 	SENSOR_DEVICE_DT_INST_DEFINE(n, p3t1755_init, NULL, &p3t1755_data_##n,                     \
193 				     &p3t1755_config_##n, POST_KERNEL,                             \
194 				     CONFIG_SENSOR_INIT_PRIORITY, &p3t1755_driver_api);
195 
196 DT_INST_FOREACH_STATUS_OKAY(P3T1755_INIT)
197