1 /*
2 * SPDX-License-Identifier: Apache-2.0
3 *
4 * Würth Elektronic WSEN-ITDS 3-axis accel sensor driver
5 *
6 * Copyright (c) 2020 Linumiz
7 * Author: Saravanan Sekar <saravanan@linumiz.com>
8 */
9
10 #include <zephyr/init.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/sys/__assert.h>
15 #include <zephyr/logging/log.h>
16 #include "itds.h"
17
18 #define DT_DRV_COMPAT we_wsen_itds
19 #define ITDS_TEMP_CONST 62500
20
21 LOG_MODULE_REGISTER(ITDS, CONFIG_SENSOR_LOG_LEVEL);
22
23 static const struct itds_odr itds_odr_map[ITDS_ODR_MAX] = {
24 {0}, {1, 600}, {12, 500}, {25}, {50}, {100}, {200},
25 {400}, {800}, {1600}
26 };
27
28 static const int16_t itds_sensitivity_scale[][ITDS_ACCL_RANGE_END] = {
29 {976, 1952, 3904, 7808},
30
31 /* high performance mode */
32 {244, 488, 976, 1952}
33 };
34
itds_get_odr_for_index(const struct device * dev,enum itds_odr_const idx,uint16_t * freq,uint16_t * mfreq)35 static int itds_get_odr_for_index(const struct device *dev,
36 enum itds_odr_const idx,
37 uint16_t *freq, uint16_t *mfreq)
38 {
39 struct itds_device_data *ddata = dev->data;
40 int start, end;
41 bool hp_mode;
42
43 hp_mode = !!(ddata->op_mode & ITDS_OP_MODE_HIGH_PERF);
44 if (hp_mode) {
45 start = ITDS_ODR_12_5;
46 end = ITDS_ODR_1600;
47 } else {
48 start = ITDS_ODR_1_6;
49 end = ITDS_ODR_200;
50 }
51
52 if (idx < start || idx > end) {
53 LOG_ERR("invalid odr for the operating mode");
54 return -EINVAL;
55 }
56
57 *freq = itds_odr_map[idx].freq;
58 *mfreq = itds_odr_map[idx].mfreq;
59
60 return 0;
61 }
62
itds_accl_odr_set(const struct device * dev,uint16_t freq,uint16_t mfreq)63 static int itds_accl_odr_set(const struct device *dev, uint16_t freq,
64 uint16_t mfreq)
65 {
66 struct itds_device_data *ddata = dev->data;
67 const struct itds_device_config *cfg = dev->config;
68 int start, end, i;
69 bool hp_mode;
70
71 hp_mode = !!(ddata->op_mode & ITDS_OP_MODE_HIGH_PERF);
72 if (hp_mode) {
73 start = ITDS_ODR_12_5;
74 end = ITDS_ODR_1600;
75 } else {
76 start = ITDS_ODR_1_6;
77 end = ITDS_ODR_200;
78 }
79
80 for (i = start; i <= end; i++) {
81 if ((freq == itds_odr_map[i].freq) &&
82 (mfreq == itds_odr_map[i].mfreq)) {
83
84 return i2c_reg_update_byte_dt(&cfg->i2c,
85 ITDS_REG_CTRL1, ITDS_MASK_ODR, i << 4);
86 }
87 }
88
89 LOG_ERR("invalid odr, not in range");
90 return -EINVAL;
91 }
92
itds_accl_range_set(const struct device * dev,int32_t range)93 static int itds_accl_range_set(const struct device *dev, int32_t range)
94 {
95 struct itds_device_data *ddata = dev->data;
96 const struct itds_device_config *cfg = dev->config;
97 int i, ret;
98 bool hp_mode;
99
100 for (i = 0; i < ITDS_ACCL_RANGE_END; i++) {
101 if (range <= (2 << i)) {
102 break;
103 }
104 }
105
106 if (i == ITDS_ACCL_RANGE_END) {
107 LOG_ERR("Accl out of range");
108 return -EINVAL;
109 }
110
111 ret = i2c_reg_update_byte_dt(&cfg->i2c, ITDS_REG_CTRL6,
112 ITDS_MASK_SCALE, i << 4);
113 if (ret) {
114 LOG_ERR("Accl set full scale failed %d", ret);
115 return ret;
116 }
117
118 hp_mode = !!(ddata->op_mode & ITDS_OP_MODE_HIGH_PERF);
119 ddata->scale = itds_sensitivity_scale[hp_mode][i];
120
121 return 0;
122 }
123
itds_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)124 static int itds_attr_set(const struct device *dev, enum sensor_channel chan,
125 enum sensor_attribute attr,
126 const struct sensor_value *val)
127 {
128 if (chan != SENSOR_CHAN_ACCEL_X &&
129 chan != SENSOR_CHAN_ACCEL_Y &&
130 chan != SENSOR_CHAN_ACCEL_Z &&
131 chan != SENSOR_CHAN_ACCEL_XYZ) {
132 LOG_ERR("attr_set() not supported on this channel.");
133 return -ENOTSUP;
134 }
135
136 switch (attr) {
137 case SENSOR_ATTR_FULL_SCALE:
138 return itds_accl_range_set(dev, sensor_ms2_to_g(val));
139
140 case SENSOR_ATTR_SAMPLING_FREQUENCY:
141 return itds_accl_odr_set(dev, val->val1, val->val2 / 1000);
142
143 default:
144 LOG_ERR("Accel attribute not supported.");
145 return -ENOTSUP;
146 }
147 }
148
itds_fetch_temperature(struct itds_device_data * ddata,const struct itds_device_config * cfg)149 static int itds_fetch_temperature(struct itds_device_data *ddata,
150 const struct itds_device_config *cfg)
151 {
152 uint8_t rval;
153 int16_t temp_raw = 0;
154 int ret;
155
156 ret = i2c_reg_read_byte_dt(&cfg->i2c,
157 ITDS_REG_STATUS_DETECT, &rval);
158 if (ret) {
159 return ret;
160 }
161
162 if (!(rval & ITDS_EVENT_DRDY_T)) {
163 return -EAGAIN;
164 }
165
166 ret = i2c_burst_read_dt(&cfg->i2c, ITDS_REG_TEMP_L,
167 (uint8_t *)&temp_raw, sizeof(uint16_t));
168 if (ret) {
169 return ret;
170 }
171
172 ddata->temperature = sys_le16_to_cpu(temp_raw);
173
174 return 0;
175 }
176
itds_fetch_accel(struct itds_device_data * ddata,const struct itds_device_config * cfg)177 static int itds_fetch_accel(struct itds_device_data *ddata,
178 const struct itds_device_config *cfg)
179 {
180 size_t i, ret;
181 uint8_t rval;
182
183 ret = i2c_reg_read_byte_dt(&cfg->i2c,
184 ITDS_REG_STATUS, &rval);
185 if (ret) {
186 return ret;
187 }
188
189 if (!(rval & ITDS_EVENT_DRDY)) {
190 return -EAGAIN;
191 }
192
193 ret = i2c_burst_read_dt(&cfg->i2c, ITDS_REG_X_OUT_L,
194 (uint8_t *)ddata->samples,
195 sizeof(uint16_t) * ITDS_SAMPLE_SIZE);
196 if (ret) {
197 return ret;
198 }
199
200 /* convert samples to cpu endianness */
201 for (i = 0; i < ITDS_SAMPLE_SIZE; i += 2) {
202 int16_t *sample = (int16_t *) &ddata->samples[i];
203
204 *sample = sys_le16_to_cpu(*sample);
205 if (ddata->op_mode & ITDS_OP_MODE_NORMAL ||
206 ddata->op_mode & ITDS_OP_MODE_HIGH_PERF) {
207 *sample = *sample >> 2;
208 } else {
209 *sample = *sample >> 4;
210 }
211 LOG_DBG("itds sample %d %X\n", i, *sample);
212 }
213
214 return 0;
215 }
216
itds_sample_fetch(const struct device * dev,enum sensor_channel chan)217 static int itds_sample_fetch(const struct device *dev,
218 enum sensor_channel chan)
219 {
220 struct itds_device_data *ddata = dev->data;
221 const struct itds_device_config *cfg = dev->config;
222
223 switch (chan) {
224 case SENSOR_CHAN_ACCEL_XYZ:
225 case SENSOR_CHAN_ACCEL_X:
226 case SENSOR_CHAN_ACCEL_Y:
227 case SENSOR_CHAN_ACCEL_Z:
228 return itds_fetch_accel(ddata, cfg);
229
230 case SENSOR_CHAN_DIE_TEMP:
231 return itds_fetch_temperature(ddata, cfg);
232
233 case SENSOR_CHAN_ALL:
234 return itds_fetch_accel(ddata, cfg) ||
235 itds_fetch_temperature(ddata, cfg);
236
237 default:
238 return -EINVAL;
239 }
240 }
241
itds_accl_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)242 static inline void itds_accl_channel_get(const struct device *dev,
243 enum sensor_channel chan,
244 struct sensor_value *val)
245 {
246 int i;
247 struct itds_device_data *ddata = dev->data;
248 uint8_t ofs_start, ofs_stop;
249
250 switch (chan) {
251 case SENSOR_CHAN_ACCEL_X:
252 ofs_start = ofs_stop = 0U;
253 break;
254 case SENSOR_CHAN_ACCEL_Y:
255 ofs_start = ofs_stop = 1U;
256 break;
257 case SENSOR_CHAN_ACCEL_Z:
258 ofs_start = ofs_stop = 2U;
259 break;
260 default:
261 ofs_start = 0U; ofs_stop = 2U;
262 break;
263 }
264
265 for (i = ofs_start; i <= ofs_stop ; i++, val++) {
266 int64_t dval;
267
268 /* Sensitivity is exposed in ug/LSB */
269 /* Convert to m/s^2 */
270 dval = (int64_t)((ddata->samples[i] * ddata->scale * SENSOR_G) /
271 1000000LL);
272 val->val1 = (int32_t)(dval / 1000000);
273 val->val2 = (int32_t)(dval % 1000000);
274 }
275 }
276
itds_temp_channel_get(const struct device * dev,struct sensor_value * val)277 static int itds_temp_channel_get(const struct device *dev,
278 struct sensor_value *val)
279 {
280 int32_t temp_processed;
281 struct itds_device_data *ddata = dev->data;
282
283 temp_processed = (ddata->temperature >> 4) * ITDS_TEMP_CONST;
284
285 val->val1 = ITDS_TEMP_OFFSET;
286 val->val2 = temp_processed;
287
288 return 0;
289 }
290
itds_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)291 static int itds_channel_get(const struct device *dev,
292 enum sensor_channel chan,
293 struct sensor_value *val)
294 {
295 switch (chan) {
296 case SENSOR_CHAN_ACCEL_X:
297 case SENSOR_CHAN_ACCEL_Y:
298 case SENSOR_CHAN_ACCEL_Z:
299 case SENSOR_CHAN_ACCEL_XYZ:
300 itds_accl_channel_get(dev, chan, val);
301 return 0;
302
303 case SENSOR_CHAN_DIE_TEMP:
304 return itds_temp_channel_get(dev, val);
305
306 default:
307 LOG_ERR("Channel not supported.");
308 return -ENOTSUP;
309 }
310
311 return 0;
312 }
313
itds_init(const struct device * dev)314 static int itds_init(const struct device *dev)
315 {
316 struct itds_device_data *ddata = dev->data;
317 const struct itds_device_config *cfg = dev->config;
318 int ret;
319 uint16_t freq, mfreq;
320 uint8_t rval;
321
322 if (!device_is_ready(cfg->i2c.bus)) {
323 LOG_ERR("Bus device is not ready");
324 return -ENODEV;
325 }
326
327 ret = i2c_reg_read_byte_dt(&cfg->i2c,
328 ITDS_REG_DEV_ID, &rval);
329 if (ret) {
330 LOG_ERR("device init fail: %d", ret);
331 return ret;
332 }
333
334 if (rval != ITDS_DEVICE_ID) {
335 LOG_ERR("device ID mismatch: %x", rval);
336 return ret;
337 }
338
339 ret = i2c_reg_update_byte_dt(&cfg->i2c, ITDS_REG_CTRL2,
340 ITDS_MASK_BDU_INC_ADD, ITDS_MASK_BDU_INC_ADD);
341 if (ret) {
342 LOG_ERR("unable to set block data update %d", ret);
343 return ret;
344 }
345
346 ret = i2c_reg_write_byte_dt(&cfg->i2c, ITDS_REG_WAKEUP_EVENT, 0);
347 if (ret) {
348 LOG_ERR("disable wakeup event fail %d", ret);
349 return ret;
350 }
351
352 ret = i2c_reg_update_byte_dt(&cfg->i2c, ITDS_REG_CTRL1,
353 ITDS_MASK_MODE, 1 << cfg->def_op_mode);
354 if (ret) {
355 LOG_ERR("set operating mode fail %d", ret);
356 return ret;
357 }
358
359 ddata->op_mode = 1 << cfg->def_op_mode;
360
361 ret = itds_get_odr_for_index(dev, cfg->def_odr, &freq, &mfreq);
362 if (ret) {
363 LOG_ERR("odr not in range for operating mode %d", ret);
364 return ret;
365 }
366
367 ret = itds_accl_odr_set(dev, freq, mfreq);
368 if (ret) {
369 LOG_ERR("odr not in range for operating mode %d", ret);
370 return ret;
371 }
372
373 #ifdef CONFIG_ITDS_TRIGGER
374 ret = itds_trigger_mode_init(dev);
375 if (ret) {
376 LOG_ERR("trigger mode init failed %d", ret);
377 return ret;
378 }
379 #endif
380 return 0;
381 }
382
383 static const struct sensor_driver_api itds_api = {
384 .attr_set = itds_attr_set,
385 #ifdef CONFIG_ITDS_TRIGGER
386 .trigger_set = itds_trigger_set,
387 #endif
388 .sample_fetch = itds_sample_fetch,
389 .channel_get = itds_channel_get,
390 };
391
392 #ifdef CONFIG_ITDS_TRIGGER
393 #define WSEN_ITDS_CFG_IRQ(inst) \
394 .int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, { 0 }),
395 #else
396 #define WSEN_ITDS_CFG_IRQ(inst)
397 #endif
398
399 #define WSEN_ITDS_INIT(idx) \
400 \
401 static struct itds_device_data itds_data_##idx; \
402 \
403 static const struct itds_device_config itds_config_##idx = { \
404 .i2c = I2C_DT_SPEC_INST_GET(idx), \
405 .def_odr = DT_INST_ENUM_IDX(idx, odr), \
406 .def_op_mode = DT_INST_ENUM_IDX(idx, op_mode), \
407 WSEN_ITDS_CFG_IRQ(idx) \
408 }; \
409 \
410 SENSOR_DEVICE_DT_INST_DEFINE(idx, itds_init, NULL, \
411 &itds_data_##idx, &itds_config_##idx, \
412 POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \
413 &itds_api); \
414
415 DT_INST_FOREACH_STATUS_OKAY(WSEN_ITDS_INIT)
416