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