1#![allow(non_camel_case_types)]
18use capsules_core::driver;
19
20use core::cell::Cell;
21use enum_primitive::cast::FromPrimitive;
22use enum_primitive::enum_from_primitive;
23use kernel::errorcode::into_statuscode;
24use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
25use kernel::hil::i2c;
26use kernel::hil::sensors;
27use kernel::hil::sensors::{NineDof, NineDofClient};
28use kernel::syscall::{CommandReturn, SyscallDriver};
29use kernel::utilities::cells::{OptionalCell, TakeCell};
30use kernel::utilities::registers::LocalRegisterCopy;
31use kernel::{ErrorCode, ProcessId};
32
33pub const DRIVER_NUM: usize = driver::NUM::Lsm6dsoxtr as usize;
34
35use kernel::utilities::registers::register_bitfields;
36
37pub const CHIP_ID: u8 = 0x6C;
38pub const ACCELEROMETER_BASE_ADDRESS: u8 = 0x6A;
39
40enum_from_primitive! {
41 #[derive(Clone, Copy, PartialEq)]
42 pub enum LSM6DSOXGyroDataRate {
43 LSMDSOX_GYRO_RATE_SHUTDOWN = 0,
44 LSM6DSOX_GYRO_RATE_12_5_HZ = 1,
45 LSM6DSOX_GYRO_RATE_26_HZ = 2,
46 LSM6DSOX_GYRO_RATE_52_HZ = 3,
47 LSM6DSOX_GYRO_RATE_104_HZ = 4,
48 LSM6DSOX_GYRO_RATE_208_HZ = 5,
49 LSM6DSOX_GYRO_RATE_416_HZ = 6,
50 LSM6DSOX_GYRO_RATE_833_HZ = 7,
51 LSM6DSOX_GYRO_RATE_1_66k_HZ = 8,
52 LSM6DSOX_GYRO_RATE_3_33K_HZ = 9,
53 LSM6DSOX_GYRO_RATE_6_66K_HZ = 10
54 }
55}
56
57enum_from_primitive! {
58 #[derive(Clone, Copy, PartialEq)]
59 pub enum LSM6DSOXAccelDataRate {
60 LSMDSOX_ACCEL_RATE_SHUTDOWN = 0,
61 LSM6DSOX_ACCEL_RATE_12_5_HZ = 1,
62 LSM6DSOX_ACCEL_RATE_26_HZ = 2,
63 LSM6DSOX_ACCEL_RATE_52_HZ = 3,
64 LSM6DSOX_ACCEL_RATE_104_HZ = 4,
65 LSM6DSOX_ACCEL_RATE_208_HZ = 5,
66 LSM6DSOX_ACCEL_RATE_416_HZ = 6,
67 LSM6DSOX_ACCEL_RATE_833_HZ = 7,
68 LSM6DSOX_ACCEL_RATE_1_66k_HZ = 8,
69 LSM6DSOX_ACCEL_RATE_3_33K_HZ = 9,
70 LSM6DSOX_ACCEL_RATE_6_66K_HZ = 10
71 }
72}
73
74enum_from_primitive! {
75 #[derive(Clone, Copy, PartialEq)]
76 pub enum LSM6DSOXAccelRange {
77 LSM6DSOX_ACCEL_RANGE_2_G = 0,
78 LSM6DSOX_ACCEL_RANGE_16_G = 1,
79 LSM6DSOX_ACCEL_RANGE_4_G = 2,
80 LSM6DSOX_ACCEL_RANGE_8_G = 3
81 }
82}
83
84enum_from_primitive! {
85 #[derive(Clone, Copy, PartialEq)]
86 pub enum LSM6DSOXTRGyroRange {
87 LSM6DSOX_GYRO_RANGE_250_DPS = 0,
88 LSM6DSOX_GYRO_RANGE_500_DPS = 1,
89 LSM6DSOX_GYRO_RANGE_1000_DPS = 2,
90 LSM6DSOX_GYRO_RANGE_2000_DPS = 3
91 }
92}
93
94enum_from_primitive! {
95 #[derive(Clone, Copy, PartialEq)]
96 pub enum LSM6DSOXTRGyroRegisters {
97 CTRL2_G = 0x11,
98 CTRL7_G = 0x16,
99 OUT_X_L_G = 0x22,
100 OUT_X_H_G = 0x23,
101 OUT_Y_L_G = 0x24,
102 OUT_Y_H_G = 0x25,
103 OUT_Z_L_G = 0x26,
104 OUT_Z_H_G = 0x27
105 }
106}
107
108enum_from_primitive! {
109 #[derive(Clone, Copy, PartialEq)]
110 pub enum LSM6DSOXTRTempRegisters {
111 OUT_TEMP_L = 0x20,
112 OUT_TEMP_H = 0x21
113 }
114}
115
116pub const SCALE_FACTOR_ACCEL: [u16; 4] = [61, 488, 122, 244];
117pub const SCALE_FACTOR_GYRO: [u16; 4] = [875, 1750, 3500, 7000];
118pub const TEMP_SENSITIVITY_FACTOR: u16 = 256;
119
120enum_from_primitive! {
121 #[derive(Clone, Copy, PartialEq)]
122 pub enum LSM6DSOXTRAccelRegisters {
123 CTRL1_XL = 0x10,
124 CTRL8_XL = 0x17,
125 CTRL9_XL = 0x18,
126 OUT_X_L_A = 0x28,
127 OUT_X_H_A = 0x29,
128 OUT_Y_L_A = 0x2A,
129 OUT_Y_H_A = 0x2B,
130 OUT_Z_L_A = 0x2C,
131 OUT_Z_H_A = 0x2D
132 }
133}
134
135register_bitfields![u8,
136 pub (crate) CTRL1_XL [
137 ODR OFFSET(4) NUMBITS(4) [],
139
140 FS OFFSET(2) NUMBITS(2) [],
141
142 LPF OFFSET(1) NUMBITS(1) [],
143
144 ],
145];
146
147register_bitfields![u8,
148 pub (crate) CTRL2_G [
149 ODR OFFSET(4) NUMBITS(4) [],
151
152 FS OFFSET(2) NUMBITS(2) [],
153
154 LPF OFFSET(1) NUMBITS(1) [],
155
156 ],
157];
158
159#[derive(Clone, Copy, PartialEq, Debug)]
160enum State {
161 Idle,
162 IsPresent,
163 ReadAccelerationXYZ,
164 ReadGyroscopeXYZ,
165 ReadTemperature,
166 SetPowerModeAccel,
167 SetPowerModeGyro,
168}
169#[derive(Default)]
170pub struct App {}
171
172pub struct Lsm6dsoxtrI2C<'a, I: i2c::I2CDevice> {
173 i2c: &'a I,
174 state: Cell<State>,
175 config_in_progress: Cell<bool>,
176 gyro_data_rate: Cell<LSM6DSOXGyroDataRate>,
177 accel_data_rate: Cell<LSM6DSOXAccelDataRate>,
178 accel_scale: Cell<LSM6DSOXAccelRange>,
179 gyro_range: Cell<LSM6DSOXTRGyroRange>,
180 low_power: Cell<bool>,
181 temperature: Cell<bool>,
182 nine_dof_client: OptionalCell<&'a dyn sensors::NineDofClient>,
183 temperature_client: OptionalCell<&'a dyn sensors::TemperatureClient>,
184 is_present: Cell<bool>,
185 buffer: TakeCell<'static, [u8]>,
186 apps: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<0>>,
187 syscall_process: OptionalCell<ProcessId>,
188}
189
190impl<'a, I: i2c::I2CDevice> Lsm6dsoxtrI2C<'a, I> {
191 pub fn new(
192 i2c: &'a I,
193 buffer: &'static mut [u8],
194 grant: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<0>>,
195 ) -> Lsm6dsoxtrI2C<'a, I> {
196 Lsm6dsoxtrI2C {
197 i2c,
198 state: Cell::new(State::Idle),
199 config_in_progress: Cell::new(false),
200 gyro_data_rate: Cell::new(LSM6DSOXGyroDataRate::LSM6DSOX_GYRO_RATE_12_5_HZ),
201 accel_data_rate: Cell::new(LSM6DSOXAccelDataRate::LSM6DSOX_ACCEL_RATE_12_5_HZ),
202 accel_scale: Cell::new(LSM6DSOXAccelRange::LSM6DSOX_ACCEL_RANGE_2_G),
203 gyro_range: Cell::new(LSM6DSOXTRGyroRange::LSM6DSOX_GYRO_RANGE_250_DPS),
204 low_power: Cell::new(false),
205 temperature: Cell::new(false),
206 nine_dof_client: OptionalCell::empty(),
207 temperature_client: OptionalCell::empty(),
208 is_present: Cell::new(false),
209 buffer: TakeCell::new(buffer),
210 apps: grant,
211 syscall_process: OptionalCell::empty(),
212 }
213 }
214
215 pub fn configure(
216 &self,
217 gyro_data_rate: LSM6DSOXGyroDataRate,
218 accel_data_rate: LSM6DSOXAccelDataRate,
219 accel_scale: LSM6DSOXAccelRange,
220 gyro_range: LSM6DSOXTRGyroRange,
221 low_power: bool,
222 ) -> Result<(), ErrorCode> {
223 if self.state.get() == State::Idle {
224 self.gyro_data_rate.set(gyro_data_rate);
225 self.accel_data_rate.set(accel_data_rate);
226 self.accel_scale.set(accel_scale);
227 self.gyro_range.set(gyro_range);
228 self.low_power.set(low_power);
229 self.temperature.set(true);
230 if self.send_is_present() == Ok(()) {
231 self.config_in_progress.set(true);
232 Ok(())
233 } else {
234 Err(ErrorCode::NODEVICE)
235 }
236 } else {
237 Err(ErrorCode::BUSY)
238 }
239 }
240
241 pub fn send_is_present(&self) -> Result<(), ErrorCode> {
242 if self.state.get() == State::Idle {
243 self.state.set(State::IsPresent);
244 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
245 buf[0] = 0x0F;
247 self.i2c.enable();
248 if let Err((error, buf)) = self.i2c.write_read(buf, 1, 1) {
249 self.state.set(State::Idle);
250 self.buffer.replace(buf);
251 self.i2c.disable();
252 Err(error.into())
253 } else {
254 Ok(())
255 }
256 })
257 } else {
258 Err(ErrorCode::BUSY)
259 }
260 }
261
262 pub fn set_accelerometer_power_mode(
263 &self,
264 data_rate: LSM6DSOXAccelDataRate,
265 low_power: bool,
266 ) -> Result<(), ErrorCode> {
267 if self.state.get() == State::Idle {
268 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
269 self.state.set(State::SetPowerModeAccel);
270 buf[0] = LSM6DSOXTRAccelRegisters::CTRL1_XL as u8;
271 let mut reg: LocalRegisterCopy<u8, CTRL1_XL::Register> = LocalRegisterCopy::new(0);
272 reg.modify(CTRL1_XL::ODR.val(data_rate as u8));
273 reg.modify(CTRL1_XL::LPF.val(low_power as u8));
274 reg.modify(CTRL1_XL::FS.val(0));
275
276 buf[1] = reg.get();
277 self.i2c.enable();
278 if let Err((error, buf)) = self.i2c.write(buf, 2) {
279 self.state.set(State::Idle);
280 self.i2c.disable();
281 self.buffer.replace(buf);
282 Err(error.into())
283 } else {
284 Ok(())
285 }
286 })
287 } else {
288 Err(ErrorCode::BUSY)
289 }
290 }
291
292 pub fn set_gyroscope_power_mode(
293 &self,
294 data_rate: LSM6DSOXGyroDataRate,
295 low_power: bool,
296 ) -> Result<(), ErrorCode> {
297 if self.state.get() == State::Idle {
298 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
299 self.state.set(State::SetPowerModeGyro);
300 buf[0] = LSM6DSOXTRGyroRegisters::CTRL2_G as u8;
301 let mut reg: LocalRegisterCopy<u8, CTRL2_G::Register> = LocalRegisterCopy::new(0);
302 reg.modify(CTRL2_G::ODR.val(data_rate as u8));
303 reg.modify(CTRL2_G::LPF.val(low_power as u8));
304 reg.modify(CTRL2_G::FS.val(0));
305
306 buf[1] = reg.get();
307 self.i2c.enable();
308 if let Err((error, buf)) = self.i2c.write(buf, 2) {
309 self.state.set(State::Idle);
310 self.i2c.disable();
311 self.buffer.replace(buf);
312 Err(error.into())
313 } else {
314 Ok(())
315 }
316 })
317 } else {
318 Err(ErrorCode::BUSY)
319 }
320 }
321
322 pub fn read_acceleration_xyz(&self) -> Result<(), ErrorCode> {
323 if self.state.get() == State::Idle {
324 self.state.set(State::ReadAccelerationXYZ);
325 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
326 buf[0] = LSM6DSOXTRAccelRegisters::OUT_X_L_A as u8;
327 self.i2c.enable();
328 if let Err((error, buf)) = self.i2c.write_read(buf, 1, 6) {
329 self.state.set(State::Idle);
330 self.buffer.replace(buf);
331 self.i2c.disable();
332 Err(error.into())
333 } else {
334 Ok(())
335 }
336 })
337 } else {
338 Err(ErrorCode::BUSY)
339 }
340 }
341
342 pub fn read_gyroscope_xyz(&self) -> Result<(), ErrorCode> {
343 if self.state.get() == State::Idle {
344 self.state.set(State::ReadGyroscopeXYZ);
345 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
346 buf[0] = LSM6DSOXTRGyroRegisters::OUT_X_L_G as u8;
347 self.i2c.enable();
348 if let Err((error, buf)) = self.i2c.write_read(buf, 1, 6) {
349 self.state.set(State::Idle);
350 self.buffer.replace(buf);
351 self.i2c.disable();
352 Err(error.into())
353 } else {
354 Ok(())
355 }
356 })
357 } else {
358 Err(ErrorCode::BUSY)
359 }
360 }
361
362 pub fn read_temperature(&self) -> Result<(), ErrorCode> {
363 if self.state.get() == State::Idle {
364 self.state.set(State::ReadTemperature);
365 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buf| {
366 buf[0] = LSM6DSOXTRTempRegisters::OUT_TEMP_L as u8;
367 self.i2c.enable();
368 if let Err((error, buf)) = self.i2c.write_read(buf, 1, 6) {
369 self.state.set(State::Idle);
370 self.buffer.replace(buf);
371 self.i2c.disable();
372 Err(error.into())
373 } else {
374 Ok(())
375 }
376 })
377 } else {
378 Err(ErrorCode::BUSY)
379 }
380 }
381}
382
383impl<I: i2c::I2CDevice> i2c::I2CClient for Lsm6dsoxtrI2C<'_, I> {
384 fn command_complete(&self, buffer: &'static mut [u8], status: Result<(), i2c::Error>) {
385 match self.state.get() {
386 State::IsPresent => {
387 let id = buffer[0];
388 self.buffer.replace(buffer);
389 self.i2c.disable();
390 self.state.set(State::Idle);
391 if status == Ok(()) && id == 108 {
392 self.is_present.set(true);
393 if self.config_in_progress.get() {
394 if let Err(_error) = self.set_accelerometer_power_mode(
395 self.accel_data_rate.get(),
396 self.low_power.get(),
397 ) {
398 self.config_in_progress.set(false);
399 }
400 }
401 } else {
402 self.is_present.set(false);
403 self.config_in_progress.set(false);
404 }
405
406 self.syscall_process.take().map(|pid| {
407 let _res = self.apps.enter(pid, |_app, upcalls| {
408 let _ = upcalls.schedule_upcall(
409 0,
410 (
411 into_statuscode(status.map_err(|i2c_error| i2c_error.into())),
412 usize::from(self.is_present.get()),
413 0,
414 ),
415 );
416 });
417 });
418 }
419 State::Idle => {
420 }
422 State::ReadAccelerationXYZ => {
423 let mut x: usize = 0;
424 let mut y: usize = 0;
425 let mut z: usize = 0;
426
427 self.nine_dof_client.map(|nine_dof_client| {
428 if status == Ok(()) {
429 let scale_factor = self.accel_scale.get() as usize;
430 x = ((((buffer[0] as u16 + ((buffer[1] as u16) << 8)) as i16) as isize)
431 * (SCALE_FACTOR_ACCEL[scale_factor] as isize)
432 / 1000) as usize;
433 y = ((((buffer[2] as u16 + ((buffer[3] as u16) << 8)) as i16) as isize)
434 * (SCALE_FACTOR_ACCEL[scale_factor] as isize)
435 / 1000) as usize;
436
437 z = ((((buffer[4] as u16 + ((buffer[5] as u16) << 8)) as i16) as isize)
438 * (SCALE_FACTOR_ACCEL[scale_factor] as isize)
439 / 1000) as usize;
440 nine_dof_client.callback(x, y, z)
441 } else {
442 nine_dof_client.callback(0, 0, 0)
443 }
444 });
445 self.buffer.replace(buffer);
446 self.i2c.disable();
447 self.state.set(State::Idle);
448 }
449
450 State::ReadGyroscopeXYZ => {
451 let mut x: usize = 0;
452 let mut y: usize = 0;
453 let mut z: usize = 0;
454 self.nine_dof_client.map(|nine_dof_client| {
455 if status == Ok(()) {
456 let scale_factor = self.gyro_range.get() as usize;
457 x = (((buffer[0] as u16 + ((buffer[1] as u16) << 8)) as i16) as isize
458 * (SCALE_FACTOR_GYRO[scale_factor] as isize)
459 / 100) as usize;
460 y = (((buffer[2] as u16 + ((buffer[3] as u16) << 8)) as i16) as isize
461 * (SCALE_FACTOR_GYRO[scale_factor] as isize)
462 / 100) as usize;
463
464 z = (((buffer[4] as u16 + ((buffer[5] as u16) << 8)) as i16) as isize
465 * (SCALE_FACTOR_GYRO[scale_factor] as isize)
466 / 100) as usize;
467 nine_dof_client.callback(x, y, z)
468 } else {
469 nine_dof_client.callback(0, 0, 0)
470 }
471 });
472 self.buffer.replace(buffer);
473 self.i2c.disable();
474 self.state.set(State::Idle);
475 }
476
477 State::ReadTemperature => {
478 let temperature = match status {
479 Ok(()) => Ok(((((buffer[0] as u16 + ((buffer[1] as u16) << 8)) as i16)
480 as isize
481 / (TEMP_SENSITIVITY_FACTOR as isize)
482 + 25)
483 * 100) as i32),
484 Err(i2c_error) => Err(i2c_error.into()),
485 };
486 self.temperature_client
487 .map(|client| client.callback(temperature));
488 self.buffer.replace(buffer);
489 self.i2c.disable();
490 self.state.set(State::Idle);
491 }
492
493 State::SetPowerModeAccel => {
494 self.buffer.replace(buffer);
495 self.i2c.disable();
496 self.state.set(State::Idle);
497 if status == Ok(()) {
498 if self.config_in_progress.get() {
499 if let Err(_error) = self.set_gyroscope_power_mode(
500 self.gyro_data_rate.get(),
501 self.low_power.get(),
502 ) {
503 self.config_in_progress.set(false);
504 }
505 }
506 } else {
507 self.config_in_progress.set(false);
508 }
509 self.syscall_process.take().map(|pid| {
510 let _res = self.apps.enter(pid, |_app, upcalls| {
511 let _ = upcalls.schedule_upcall(
512 0,
513 (
514 into_statuscode(status.map_err(|i2c_error| i2c_error.into())),
515 usize::from(status == Ok(())),
516 0,
517 ),
518 );
519 });
520 });
521 }
522
523 State::SetPowerModeGyro => {
524 self.buffer.replace(buffer);
525 self.i2c.disable();
526 self.state.set(State::Idle);
527 self.config_in_progress.set(false);
528 self.syscall_process.take().map(|pid| {
529 let _res = self.apps.enter(pid, |_app, upcalls| {
530 let _ = upcalls.schedule_upcall(
531 0,
532 (
533 into_statuscode(status.map_err(|i2c_error| i2c_error.into())),
534 usize::from(status == Ok(())),
535 0,
536 ),
537 );
538 });
539 });
540 }
541 }
542 }
543}
544
545impl<I: i2c::I2CDevice> SyscallDriver for Lsm6dsoxtrI2C<'_, I> {
546 fn command(
547 &self,
548 command_num: usize,
549 data1: usize,
550 data2: usize,
551 process_id: ProcessId,
552 ) -> CommandReturn {
553 if command_num == 0 {
554 return CommandReturn::success();
557 }
558
559 match command_num {
560 1 => {
562 if self.state.get() == State::Idle {
563 match self.send_is_present() {
564 Ok(()) => {
565 self.syscall_process.set(process_id);
566 CommandReturn::success()
567 }
568 Err(error) => CommandReturn::failure(error),
569 }
570 } else {
571 CommandReturn::failure(ErrorCode::BUSY)
572 }
573 }
574 2 => {
576 if self.state.get() == State::Idle {
577 if let Some(data_rate) = LSM6DSOXAccelDataRate::from_usize(data1) {
578 match self.set_accelerometer_power_mode(data_rate, data2 != 0) {
579 Ok(()) => {
580 self.syscall_process.set(process_id);
581 CommandReturn::success()
582 }
583 Err(error) => CommandReturn::failure(error),
584 }
585 } else {
586 CommandReturn::failure(ErrorCode::INVAL)
587 }
588 } else {
589 CommandReturn::failure(ErrorCode::BUSY)
590 }
591 }
592 3 => {
594 if self.state.get() == State::Idle {
595 if let Some(data_rate) = LSM6DSOXGyroDataRate::from_usize(data1) {
596 match self.set_gyroscope_power_mode(data_rate, data2 != 0) {
597 Ok(()) => {
598 self.syscall_process.set(process_id);
599 CommandReturn::success()
600 }
601 Err(error) => CommandReturn::failure(error),
602 }
603 } else {
604 CommandReturn::failure(ErrorCode::INVAL)
605 }
606 } else {
607 CommandReturn::failure(ErrorCode::BUSY)
608 }
609 }
610
611 _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
612 }
613 }
614 fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
615 self.apps.enter(processid, |_, _| {})
616 }
617}
618
619impl<'a, I: i2c::I2CDevice> NineDof<'a> for Lsm6dsoxtrI2C<'a, I> {
620 fn set_client(&self, nine_dof_client: &'a dyn NineDofClient) {
621 self.nine_dof_client.replace(nine_dof_client);
622 }
623
624 fn read_accelerometer(&self) -> Result<(), ErrorCode> {
625 self.read_acceleration_xyz()
626 }
627
628 fn read_gyroscope(&self) -> Result<(), ErrorCode> {
629 self.read_gyroscope_xyz()
630 }
631}
632
633impl<'a, I: i2c::I2CDevice> sensors::TemperatureDriver<'a> for Lsm6dsoxtrI2C<'a, I> {
634 fn set_client(&self, temperature_client: &'a dyn sensors::TemperatureClient) {
635 self.temperature_client.replace(temperature_client);
636 }
637
638 fn read_temperature(&self) -> Result<(), ErrorCode> {
639 self.read_temperature()
640 }
641}