1 /*
2  * Copyright (c) 2021 Leica Geosystems AG
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT sbs_sbs_gauge
8 
9 #include <zephyr/drivers/i2c.h>
10 #include <zephyr/drivers/sensor.h>
11 #include <zephyr/sys/byteorder.h>
12 
13 #include "sbs_gauge.h"
14 
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(sbs_gauge, CONFIG_SENSOR_LOG_LEVEL);
17 
sbs_cmd_reg_read(const struct device * dev,uint8_t reg_addr,uint16_t * val)18 static int sbs_cmd_reg_read(const struct device *dev,
19 			    uint8_t reg_addr,
20 			    uint16_t *val)
21 {
22 	const struct sbs_gauge_config *cfg;
23 	uint8_t i2c_data[2];
24 	int status;
25 
26 	cfg = dev->config;
27 	status = i2c_burst_read_dt(&cfg->i2c, reg_addr, i2c_data,
28 				   ARRAY_SIZE(i2c_data));
29 	if (status < 0) {
30 		LOG_ERR("Unable to read register");
31 		return status;
32 	}
33 
34 	*val = sys_get_le16(i2c_data);
35 
36 	return 0;
37 }
38 
39 /**
40  * @brief sensor value get
41  *
42  * @return -ENOTSUP for unsupported channels
43  */
sbs_gauge_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)44 static int sbs_gauge_channel_get(const struct device *dev,
45 				 enum sensor_channel chan,
46 				 struct sensor_value *val)
47 {
48 	struct sbs_gauge_data *data;
49 	int32_t int_temp;
50 
51 	data = dev->data;
52 	val->val2 = 0;
53 
54 	switch (chan) {
55 	case SENSOR_CHAN_GAUGE_VOLTAGE:
56 		val->val1 = data->voltage / 1000;
57 		val->val2 = (data->voltage % 1000) * 1000;
58 		break;
59 
60 	case SENSOR_CHAN_GAUGE_AVG_CURRENT:
61 		val->val1 = data->avg_current / 1000;
62 		val->val2 = (data->avg_current % 1000) * 1000;
63 		break;
64 
65 	case SENSOR_CHAN_GAUGE_TEMP:
66 		int_temp = (data->internal_temperature * 10);
67 		int_temp = int_temp - 27315;
68 		val->val1 = int_temp / 100;
69 		val->val2 = (int_temp % 100) * 1000000;
70 		break;
71 
72 	case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE:
73 		val->val1 = data->state_of_charge;
74 		break;
75 
76 	case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY:
77 		val->val1 = data->full_charge_capacity;
78 		break;
79 
80 	case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY:
81 		val->val1 = data->remaining_charge_capacity;
82 		break;
83 
84 	case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY:
85 		val->val1 = data->nom_avail_capacity;
86 		break;
87 
88 	case SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY:
89 		val->val1 = data->full_avail_capacity;
90 		break;
91 
92 	case SENSOR_CHAN_GAUGE_TIME_TO_EMPTY:
93 		val->val1 = data->time_to_empty;
94 		break;
95 
96 	case SENSOR_CHAN_GAUGE_TIME_TO_FULL:
97 		val->val1 = data->time_to_full;
98 		break;
99 
100 	case SENSOR_CHAN_GAUGE_CYCLE_COUNT:
101 		val->val1 = data->cycle_count;
102 		break;
103 
104 	default:
105 		return -ENOTSUP;
106 	}
107 
108 	return 0;
109 }
110 
111 static const uint16_t all_channels[] = {
112 	SENSOR_CHAN_GAUGE_VOLTAGE,
113 	SENSOR_CHAN_GAUGE_AVG_CURRENT,
114 	SENSOR_CHAN_GAUGE_TEMP,
115 	SENSOR_CHAN_GAUGE_STATE_OF_CHARGE,
116 	SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY,
117 	SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY,
118 	SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY,
119 	SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY,
120 	SENSOR_CHAN_GAUGE_TIME_TO_EMPTY,
121 	SENSOR_CHAN_GAUGE_TIME_TO_FULL,
122 	SENSOR_CHAN_GAUGE_CYCLE_COUNT
123 };
124 
sbs_gauge_sample_fetch(const struct device * dev,enum sensor_channel chan)125 static int sbs_gauge_sample_fetch(const struct device *dev,
126 			    enum sensor_channel chan)
127 {
128 	struct sbs_gauge_data *data;
129 	int status = 0;
130 
131 	data = dev->data;
132 
133 	switch (chan) {
134 	case SENSOR_CHAN_GAUGE_VOLTAGE:
135 		status = sbs_cmd_reg_read(dev,
136 					  SBS_GAUGE_CMD_VOLTAGE,
137 					  &data->voltage);
138 		if (status < 0) {
139 			LOG_ERR("Failed to read voltage");
140 		}
141 		break;
142 
143 	case SENSOR_CHAN_GAUGE_AVG_CURRENT:
144 		status = sbs_cmd_reg_read(dev,
145 					  SBS_GAUGE_CMD_AVG_CURRENT,
146 					  &data->avg_current);
147 		if (status < 0) {
148 			LOG_ERR("Failed to read average current ");
149 		}
150 		break;
151 
152 	case SENSOR_CHAN_GAUGE_TEMP:
153 		status = sbs_cmd_reg_read(dev,
154 					  SBS_GAUGE_CMD_TEMP,
155 					  &data->internal_temperature);
156 		if (status < 0) {
157 			LOG_ERR("Failed to read internal temperature");
158 		}
159 		break;
160 
161 	case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE:
162 		status = sbs_cmd_reg_read(dev,
163 					  SBS_GAUGE_CMD_ASOC,
164 					  &data->state_of_charge);
165 		if (status < 0) {
166 			LOG_ERR("Failed to read state of charge");
167 		}
168 		break;
169 
170 	case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY:
171 		status = sbs_cmd_reg_read(dev,
172 					  SBS_GAUGE_CMD_FULL_CAPACITY,
173 					  &data->full_charge_capacity);
174 		if (status < 0) {
175 			LOG_ERR("Failed to read full charge capacity");
176 		}
177 		break;
178 
179 	case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY:
180 		status = sbs_cmd_reg_read(dev,
181 					  SBS_GAUGE_CMD_REM_CAPACITY,
182 					  &data->remaining_charge_capacity);
183 		if (status < 0) {
184 			LOG_ERR("Failed to read remaining charge capacity");
185 		}
186 		break;
187 
188 	case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY:
189 		status = sbs_cmd_reg_read(dev,
190 					  SBS_GAUGE_CMD_NOM_CAPACITY,
191 					  &data->nom_avail_capacity);
192 		if (status < 0) {
193 			LOG_ERR("Failed to read nominal available capacity");
194 		}
195 		break;
196 
197 	case SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY:
198 		status = sbs_cmd_reg_read(dev,
199 					  SBS_GAUGE_CMD_FULL_CAPACITY,
200 					  &data->full_avail_capacity);
201 		if (status < 0) {
202 			LOG_ERR("Failed to read full available capacity");
203 		}
204 		break;
205 
206 	case SENSOR_CHAN_GAUGE_TIME_TO_EMPTY:
207 		status = sbs_cmd_reg_read(dev,
208 					  SBS_GAUGE_CMD_AVG_TIME2EMPTY,
209 					  &data->time_to_empty);
210 		data->time_to_empty = (data->time_to_empty) & 0x00FF;
211 
212 		if (status < 0) {
213 			LOG_ERR("Failed to read time to empty");
214 		}
215 		break;
216 
217 	case SENSOR_CHAN_GAUGE_TIME_TO_FULL:
218 		status = sbs_cmd_reg_read(dev,
219 					  SBS_GAUGE_CMD_AVG_TIME2FULL,
220 					  &data->time_to_full);
221 		data->time_to_full = (data->time_to_full) & 0x00FF;
222 
223 		if (status < 0) {
224 			LOG_ERR("Failed to read time to full");
225 		}
226 		break;
227 
228 	case SENSOR_CHAN_GAUGE_CYCLE_COUNT:
229 		status = sbs_cmd_reg_read(dev,
230 					  SBS_GAUGE_CMD_CYCLE_COUNT,
231 					  &data->cycle_count);
232 		data->cycle_count = (data->cycle_count) & 0x00FF;
233 
234 		if (status < 0) {
235 			LOG_ERR("Failed to read cycle count");
236 		}
237 		break;
238 
239 	case SENSOR_CHAN_ALL:
240 		for (int i = 0; i < ARRAY_SIZE(all_channels); i++) {
241 			status = sbs_gauge_sample_fetch(dev, all_channels[i]);
242 			if (status != 0) {
243 				break;
244 			}
245 		}
246 
247 		break;
248 
249 	default:
250 		return -ENOTSUP;
251 	}
252 
253 	return status;
254 }
255 
256 /**
257  * @brief initialize the fuel gauge
258  *
259  * @return 0 for success
260  */
sbs_gauge_init(const struct device * dev)261 static int sbs_gauge_init(const struct device *dev)
262 {
263 	const struct sbs_gauge_config *cfg;
264 
265 	cfg = dev->config;
266 
267 	if (!device_is_ready(cfg->i2c.bus)) {
268 		LOG_ERR("Bus device is not ready");
269 		return -ENODEV;
270 	}
271 
272 	return 0;
273 }
274 
275 static const struct sensor_driver_api sbs_gauge_driver_api = {
276 	.sample_fetch = sbs_gauge_sample_fetch,
277 	.channel_get = sbs_gauge_channel_get,
278 };
279 
280 #define SBS_GAUGE_INIT(index) \
281 	static struct sbs_gauge_data sbs_gauge_driver_##index; \
282 \
283 	static const struct sbs_gauge_config sbs_gauge_config_##index = { \
284 		.i2c = I2C_DT_SPEC_INST_GET(index), \
285 	}; \
286 \
287 	SENSOR_DEVICE_DT_INST_DEFINE(index, \
288 			    &sbs_gauge_init, \
289 			    NULL, \
290 			    &sbs_gauge_driver_##index, \
291 			    &sbs_gauge_config_##index, POST_KERNEL, \
292 			    CONFIG_SENSOR_INIT_PRIORITY, \
293 			    &sbs_gauge_driver_api);
294 
295 DT_INST_FOREACH_STATUS_OKAY(SBS_GAUGE_INIT)
296