1 /*
2 * Copyright (c) 2017, NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nxp_fxas21002
8
9 #include "fxas21002.h"
10 #include <sys/util.h>
11 #include <sys/__assert.h>
12 #include <logging/log.h>
13
14 LOG_MODULE_REGISTER(FXAS21002, CONFIG_SENSOR_LOG_LEVEL);
15
16 /* Sample period in microseconds, indexed by output data rate encoding (DR) */
17 static const uint32_t sample_period[] = {
18 1250, 2500, 5000, 10000, 20000, 40000, 80000, 80000
19 };
20
fxas21002_sample_fetch(const struct device * dev,enum sensor_channel chan)21 static int fxas21002_sample_fetch(const struct device *dev,
22 enum sensor_channel chan)
23 {
24 const struct fxas21002_config *config = dev->config;
25 struct fxas21002_data *data = dev->data;
26 uint8_t buffer[FXAS21002_MAX_NUM_BYTES];
27 int16_t *raw;
28 int ret = 0;
29 int i;
30
31 if (chan != SENSOR_CHAN_ALL) {
32 LOG_ERR("Unsupported sensor channel");
33 return -ENOTSUP;
34 }
35
36 k_sem_take(&data->sem, K_FOREVER);
37
38 /* Read all the channels in one I2C transaction. */
39 if (i2c_burst_read(data->i2c, config->i2c_address,
40 FXAS21002_REG_OUTXMSB, buffer, sizeof(buffer))) {
41 LOG_ERR("Could not fetch sample");
42 ret = -EIO;
43 goto exit;
44 }
45
46 /* Parse the buffer into raw channel data (16-bit integers). To save
47 * RAM, store the data in raw format and wait to convert to the
48 * normalized sensor_value type until later.
49 */
50 raw = &data->raw[0];
51
52 for (i = 0; i < sizeof(buffer); i += 2) {
53 *raw++ = (buffer[i] << 8) | (buffer[i+1]);
54 }
55
56 exit:
57 k_sem_give(&data->sem);
58
59 return ret;
60 }
61
fxas21002_convert(struct sensor_value * val,int16_t raw,enum fxas21002_range range)62 static void fxas21002_convert(struct sensor_value *val, int16_t raw,
63 enum fxas21002_range range)
64 {
65 int32_t micro_rad;
66
67 /* Convert units to micro radians per second.
68 * 62500 micro dps * 2*pi/360 = 1091 micro radians per second
69 */
70 micro_rad = (raw * 1091) >> range;
71
72 val->val1 = micro_rad / 1000000;
73 val->val2 = micro_rad % 1000000;
74 }
75
fxas21002_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)76 static int fxas21002_channel_get(const struct device *dev,
77 enum sensor_channel chan,
78 struct sensor_value *val)
79 {
80 const struct fxas21002_config *config = dev->config;
81 struct fxas21002_data *data = dev->data;
82 int start_channel;
83 int num_channels;
84 int16_t *raw;
85 int ret;
86 int i;
87
88 k_sem_take(&data->sem, K_FOREVER);
89
90 /* Start with an error return code by default, then clear it if we find
91 * a supported sensor channel.
92 */
93 ret = -ENOTSUP;
94
95 /* Convert raw gyroscope data to the normalized sensor_value type. */
96 switch (chan) {
97 case SENSOR_CHAN_GYRO_X:
98 start_channel = FXAS21002_CHANNEL_GYRO_X;
99 num_channels = 1;
100 break;
101 case SENSOR_CHAN_GYRO_Y:
102 start_channel = FXAS21002_CHANNEL_GYRO_Y;
103 num_channels = 1;
104 break;
105 case SENSOR_CHAN_GYRO_Z:
106 start_channel = FXAS21002_CHANNEL_GYRO_Z;
107 num_channels = 1;
108 break;
109 case SENSOR_CHAN_GYRO_XYZ:
110 start_channel = FXAS21002_CHANNEL_GYRO_X;
111 num_channels = 3;
112 break;
113 default:
114 start_channel = 0;
115 num_channels = 0;
116 break;
117 }
118
119 raw = &data->raw[start_channel];
120 for (i = 0; i < num_channels; i++) {
121 fxas21002_convert(val++, *raw++, config->range);
122 }
123
124 if (num_channels > 0) {
125 ret = 0;
126 }
127
128 if (ret != 0) {
129 LOG_ERR("Unsupported sensor channel");
130 }
131
132 k_sem_give(&data->sem);
133
134 return ret;
135 }
136
fxas21002_get_power(const struct device * dev,enum fxas21002_power * power)137 int fxas21002_get_power(const struct device *dev, enum fxas21002_power *power)
138 {
139 const struct fxas21002_config *config = dev->config;
140 struct fxas21002_data *data = dev->data;
141 uint8_t val = *power;
142
143 if (i2c_reg_read_byte(data->i2c, config->i2c_address,
144 FXAS21002_REG_CTRLREG1,
145 &val)) {
146 LOG_ERR("Could not get power setting");
147 return -EIO;
148 }
149 val &= FXAS21002_CTRLREG1_POWER_MASK;
150 *power = val;
151
152 return 0;
153 }
154
fxas21002_set_power(const struct device * dev,enum fxas21002_power power)155 int fxas21002_set_power(const struct device *dev, enum fxas21002_power power)
156 {
157 const struct fxas21002_config *config = dev->config;
158 struct fxas21002_data *data = dev->data;
159
160 return i2c_reg_update_byte(data->i2c, config->i2c_address,
161 FXAS21002_REG_CTRLREG1,
162 FXAS21002_CTRLREG1_POWER_MASK,
163 power);
164 }
165
fxas21002_get_transition_time(enum fxas21002_power start,enum fxas21002_power end,uint8_t dr)166 uint32_t fxas21002_get_transition_time(enum fxas21002_power start,
167 enum fxas21002_power end,
168 uint8_t dr)
169 {
170 uint32_t transition_time;
171
172 /* If not transitioning to active mode, then don't need to wait */
173 if (end != FXAS21002_POWER_ACTIVE) {
174 return 0;
175 }
176
177 /* Otherwise, the transition time depends on which state we're
178 * transitioning from. These times are defined by the datasheet.
179 */
180 transition_time = sample_period[dr];
181
182 if (start == FXAS21002_POWER_READY) {
183 transition_time += 5000U;
184 } else {
185 transition_time += 60000U;
186 }
187
188 return transition_time;
189 }
190
fxas21002_init(const struct device * dev)191 static int fxas21002_init(const struct device *dev)
192 {
193 const struct fxas21002_config *config = dev->config;
194 struct fxas21002_data *data = dev->data;
195 uint32_t transition_time;
196 uint8_t whoami;
197 uint8_t ctrlreg1;
198
199 /* Get the I2C device */
200 data->i2c = device_get_binding(config->i2c_name);
201 if (data->i2c == NULL) {
202 LOG_ERR("Could not find I2C device");
203 return -EINVAL;
204 }
205
206 /* Read the WHOAMI register to make sure we are talking to FXAS21002
207 * and not some other type of device that happens to have the same I2C
208 * address.
209 */
210 if (i2c_reg_read_byte(data->i2c, config->i2c_address,
211 FXAS21002_REG_WHOAMI, &whoami)) {
212 LOG_ERR("Could not get WHOAMI value");
213 return -EIO;
214 }
215
216 if (whoami != config->whoami) {
217 LOG_ERR("WHOAMI value received 0x%x, expected 0x%x",
218 whoami, config->whoami);
219 return -EIO;
220 }
221
222 /* Reset the sensor. Upon issuing a software reset command over the I2C
223 * interface, the sensor immediately resets and does not send any
224 * acknowledgment (ACK) of the written byte to the master. Therefore,
225 * do not check the return code of the I2C transaction.
226 */
227 i2c_reg_write_byte(data->i2c, config->i2c_address,
228 FXAS21002_REG_CTRLREG1, FXAS21002_CTRLREG1_RST_MASK);
229
230 /* Wait for the reset sequence to complete */
231 do {
232 if (i2c_reg_read_byte(data->i2c, config->i2c_address,
233 FXAS21002_REG_CTRLREG1, &ctrlreg1)) {
234 LOG_ERR("Could not get ctrlreg1 value");
235 return -EIO;
236 }
237 } while (ctrlreg1 & FXAS21002_CTRLREG1_RST_MASK);
238
239 /* Set the full-scale range */
240 if (i2c_reg_update_byte(data->i2c, config->i2c_address,
241 FXAS21002_REG_CTRLREG0,
242 FXAS21002_CTRLREG0_FS_MASK,
243 config->range)) {
244 LOG_ERR("Could not set range");
245 return -EIO;
246 }
247
248 /* Set the output data rate */
249 if (i2c_reg_update_byte(data->i2c, config->i2c_address,
250 FXAS21002_REG_CTRLREG1,
251 FXAS21002_CTRLREG1_DR_MASK,
252 config->dr << FXAS21002_CTRLREG1_DR_SHIFT)) {
253 LOG_ERR("Could not set output data rate");
254 return -EIO;
255 }
256
257 k_sem_init(&data->sem, 0, K_SEM_MAX_LIMIT);
258
259 #if CONFIG_FXAS21002_TRIGGER
260 if (fxas21002_trigger_init(dev)) {
261 LOG_ERR("Could not initialize interrupts");
262 return -EIO;
263 }
264 #endif
265
266 /* Set active */
267 if (fxas21002_set_power(dev, FXAS21002_POWER_ACTIVE)) {
268 LOG_ERR("Could not set active");
269 return -EIO;
270 }
271
272 /* Wait the transition time from standby to active mode */
273 transition_time = fxas21002_get_transition_time(FXAS21002_POWER_STANDBY,
274 FXAS21002_POWER_ACTIVE,
275 config->dr);
276 k_busy_wait(transition_time);
277 k_sem_give(&data->sem);
278
279 LOG_DBG("Init complete");
280
281 return 0;
282 }
283
284 static const struct sensor_driver_api fxas21002_driver_api = {
285 .sample_fetch = fxas21002_sample_fetch,
286 .channel_get = fxas21002_channel_get,
287 #if CONFIG_FXAS21002_TRIGGER
288 .trigger_set = fxas21002_trigger_set,
289 #endif
290 };
291
292 static const struct fxas21002_config fxas21002_config = {
293 .i2c_name = DT_INST_BUS_LABEL(0),
294 .i2c_address = DT_INST_REG_ADDR(0),
295 .whoami = CONFIG_FXAS21002_WHOAMI,
296 .range = CONFIG_FXAS21002_RANGE,
297 .dr = CONFIG_FXAS21002_DR,
298 #ifdef CONFIG_FXAS21002_TRIGGER
299 #ifdef CONFIG_FXAS21002_DRDY_INT1
300 .gpio_name = DT_INST_GPIO_LABEL(0, int1_gpios),
301 .gpio_pin = DT_INST_GPIO_PIN(0, int1_gpios),
302 .gpio_flags = DT_INST_GPIO_FLAGS(0, int1_gpios),
303 #else
304 .gpio_name = DT_INST_GPIO_LABEL(0, int2_gpios),
305 .gpio_pin = DT_INST_GPIO_PIN(0, int2_gpios),
306 .gpio_flags = DT_INST_GPIO_FLAGS(0, int2_gpios),
307 #endif
308 #endif
309 };
310
311 static struct fxas21002_data fxas21002_data;
312
313 DEVICE_DT_INST_DEFINE(0, fxas21002_init, NULL,
314 &fxas21002_data, &fxas21002_config,
315 POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,
316 &fxas21002_driver_api);
317