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