1 /*
2  * Copyright (c) 2023 Google LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT fintek_f75303
8 
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/pm/device.h>
13 #include <zephyr/pm/device_runtime.h>
14 #include <zephyr/logging/log.h>
15 #include <zephyr/drivers/sensor/f75303.h>
16 #include "f75303.h"
17 
18 #define F75303_SAMPLE_INT_SHIFT 3
19 #define F75303_SAMPLE_FRAC_MASK GENMASK(2, 0)
20 #define F75303_SAMPLE_MICROCELSIUS_PER_BIT 125000
21 
22 LOG_MODULE_REGISTER(F75303, CONFIG_SENSOR_LOG_LEVEL);
23 
f75303_fetch(const struct i2c_dt_spec * i2c,uint8_t off_h,uint8_t off_l,uint16_t * sample)24 static int f75303_fetch(const struct i2c_dt_spec *i2c,
25 			uint8_t off_h, uint8_t off_l, uint16_t *sample)
26 {
27 	uint8_t val_h;
28 	uint8_t val_l;
29 	int res;
30 
31 	res = i2c_reg_read_byte_dt(i2c, off_h, &val_h);
32 	if (res) {
33 		return res;
34 	}
35 
36 	res = i2c_reg_read_byte_dt(i2c, off_l, &val_l);
37 	if (res) {
38 		return res;
39 	}
40 
41 	*sample = val_h << 3 | val_l >> 5;
42 
43 	return 0;
44 }
45 
f75303_fetch_local(const struct device * dev)46 static int f75303_fetch_local(const struct device *dev)
47 {
48 	struct f75303_data *data = dev->data;
49 	const struct f75303_config *config = dev->config;
50 
51 	return f75303_fetch(&config->i2c,
52 			    F75303_LOCAL_TEMP_H,
53 			    F75303_LOCAL_TEMP_L,
54 			    &data->sample_local);
55 }
56 
f75303_fetch_remote1(const struct device * dev)57 static int f75303_fetch_remote1(const struct device *dev)
58 {
59 	struct f75303_data *data = dev->data;
60 	const struct f75303_config *config = dev->config;
61 
62 	return f75303_fetch(&config->i2c,
63 			    F75303_REMOTE1_TEMP_H,
64 			    F75303_REMOTE1_TEMP_L,
65 			    &data->sample_remote1);
66 }
67 
f75303_fetch_remote2(const struct device * dev)68 static int f75303_fetch_remote2(const struct device *dev)
69 {
70 	struct f75303_data *data = dev->data;
71 	const struct f75303_config *config = dev->config;
72 
73 	return f75303_fetch(&config->i2c,
74 			    F75303_REMOTE2_TEMP_H,
75 			    F75303_REMOTE2_TEMP_L,
76 			    &data->sample_remote2);
77 }
78 
f75303_sample_fetch(const struct device * dev,enum sensor_channel chan)79 static int f75303_sample_fetch(const struct device *dev,
80 			       enum sensor_channel chan)
81 {
82 	enum pm_device_state pm_state;
83 	int res;
84 
85 	(void)pm_device_state_get(dev, &pm_state);
86 	if (pm_state != PM_DEVICE_STATE_ACTIVE) {
87 		return -EIO;
88 	}
89 
90 	switch ((uint32_t)chan) {
91 	case SENSOR_CHAN_ALL:
92 		res = f75303_fetch_local(dev);
93 		if (res) {
94 			break;
95 		}
96 		res = f75303_fetch_remote1(dev);
97 		if (res) {
98 			break;
99 		}
100 		res = f75303_fetch_remote2(dev);
101 		break;
102 	case SENSOR_CHAN_AMBIENT_TEMP:
103 		return f75303_fetch_local(dev);
104 	case SENSOR_CHAN_F75303_REMOTE1:
105 		return f75303_fetch_remote1(dev);
106 	case SENSOR_CHAN_F75303_REMOTE2:
107 		return f75303_fetch_remote2(dev);
108 	default:
109 		return -ENOTSUP;
110 	}
111 
112 	return res;
113 }
114 
f75303_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)115 static int f75303_channel_get(const struct device *dev,
116 			      enum sensor_channel chan,
117 			      struct sensor_value *val)
118 {
119 	struct f75303_data *data = dev->data;
120 	uint16_t sample;
121 
122 	switch ((uint32_t)chan) {
123 	case SENSOR_CHAN_AMBIENT_TEMP:
124 		sample = data->sample_local;
125 		break;
126 	case SENSOR_CHAN_F75303_REMOTE1:
127 		sample = data->sample_remote1;
128 		break;
129 	case SENSOR_CHAN_F75303_REMOTE2:
130 		sample = data->sample_remote2;
131 		break;
132 	default:
133 		return -ENOTSUP;
134 	}
135 
136 	/*
137 	 * The reading is given in steps of 0.125 degrees celsius, i.e. the
138 	 * temperature in degrees celsius is equal to sample / 8.
139 	 */
140 	val->val1 = sample >> F75303_SAMPLE_INT_SHIFT;
141 	val->val2 = (sample & F75303_SAMPLE_FRAC_MASK) * F75303_SAMPLE_MICROCELSIUS_PER_BIT;
142 
143 	return 0;
144 }
145 
146 static DEVICE_API(sensor, f75303_driver_api) = {
147 	.sample_fetch = f75303_sample_fetch,
148 	.channel_get = f75303_channel_get,
149 };
150 
f75303_init(const struct device * dev)151 static int f75303_init(const struct device *dev)
152 {
153 	const struct f75303_config *config = dev->config;
154 	int res = 0;
155 
156 	if (!i2c_is_ready_dt(&config->i2c)) {
157 		LOG_ERR("I2C device not ready");
158 		return -ENODEV;
159 	}
160 
161 #ifdef CONFIG_PM_DEVICE_RUNTIME
162 	pm_device_init_suspended(dev);
163 
164 	res = pm_device_runtime_enable(dev);
165 	if (res) {
166 		LOG_ERR("Failed to enable runtime power management");
167 	}
168 #endif
169 
170 	return res;
171 }
172 
173 #ifdef CONFIG_PM_DEVICE
f75303_pm_action(const struct device * dev,enum pm_device_action action)174 static int f75303_pm_action(const struct device *dev, enum pm_device_action action)
175 {
176 	switch (action) {
177 	case PM_DEVICE_ACTION_TURN_ON:
178 	case PM_DEVICE_ACTION_RESUME:
179 	case PM_DEVICE_ACTION_TURN_OFF:
180 	case PM_DEVICE_ACTION_SUSPEND:
181 		return 0;
182 	default:
183 		return -ENOTSUP;
184 	}
185 }
186 #endif
187 
188 #define F75303_INST(inst)								\
189 	static struct f75303_data f75303_data_##inst;					\
190 	static const struct f75303_config f75303_config_##inst = {			\
191 		.i2c = I2C_DT_SPEC_INST_GET(inst),					\
192 	};										\
193 	PM_DEVICE_DT_INST_DEFINE(inst, f75303_pm_action);				\
194 	SENSOR_DEVICE_DT_INST_DEFINE(inst, f75303_init, PM_DEVICE_DT_INST_GET(inst),	\
195 			      &f75303_data_##inst, &f75303_config_##inst, POST_KERNEL,	\
196 			      CONFIG_SENSOR_INIT_PRIORITY, &f75303_driver_api);
197 
198 DT_INST_FOREACH_STATUS_OKAY(F75303_INST)
199