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 upcalls
409 .schedule_upcall(
410 0,
411 (
412 into_statuscode(status.map_err(|i2c_error| i2c_error.into())),
413 usize::from(self.is_present.get()),
414 0,
415 ),
416 )
417 .ok();
418 });
419 });
420 }
421 State::Idle => {
422 }
424 State::ReadAccelerationXYZ => {
425 let mut x: usize = 0;
426 let mut y: usize = 0;
427 let mut z: usize = 0;
428
429 self.nine_dof_client.map(|nine_dof_client| {
430 if status == Ok(()) {
431 let scale_factor = self.accel_scale.get() as usize;
432 x = ((((buffer[0] as u16 + ((buffer[1] as u16) << 8)) as i16) as isize)
433 * (SCALE_FACTOR_ACCEL[scale_factor] as isize)
434 / 1000) as usize;
435 y = ((((buffer[2] as u16 + ((buffer[3] as u16) << 8)) as i16) as isize)
436 * (SCALE_FACTOR_ACCEL[scale_factor] as isize)
437 / 1000) as usize;
438
439 z = ((((buffer[4] as u16 + ((buffer[5] as u16) << 8)) as i16) as isize)
440 * (SCALE_FACTOR_ACCEL[scale_factor] as isize)
441 / 1000) as usize;
442 nine_dof_client.callback(x, y, z)
443 } else {
444 nine_dof_client.callback(0, 0, 0)
445 }
446 });
447 self.buffer.replace(buffer);
448 self.i2c.disable();
449 self.state.set(State::Idle);
450 }
451
452 State::ReadGyroscopeXYZ => {
453 let mut x: usize = 0;
454 let mut y: usize = 0;
455 let mut z: usize = 0;
456 self.nine_dof_client.map(|nine_dof_client| {
457 if status == Ok(()) {
458 let scale_factor = self.gyro_range.get() as usize;
459 x = (((buffer[0] as u16 + ((buffer[1] as u16) << 8)) as i16) as isize
460 * (SCALE_FACTOR_GYRO[scale_factor] as isize)
461 / 100) as usize;
462 y = (((buffer[2] as u16 + ((buffer[3] as u16) << 8)) as i16) as isize
463 * (SCALE_FACTOR_GYRO[scale_factor] as isize)
464 / 100) as usize;
465
466 z = (((buffer[4] as u16 + ((buffer[5] as u16) << 8)) as i16) as isize
467 * (SCALE_FACTOR_GYRO[scale_factor] as isize)
468 / 100) as usize;
469 nine_dof_client.callback(x, y, z)
470 } else {
471 nine_dof_client.callback(0, 0, 0)
472 }
473 });
474 self.buffer.replace(buffer);
475 self.i2c.disable();
476 self.state.set(State::Idle);
477 }
478
479 State::ReadTemperature => {
480 let temperature = match status {
481 Ok(()) => Ok(((((buffer[0] as u16 + ((buffer[1] as u16) << 8)) as i16)
482 as isize
483 / (TEMP_SENSITIVITY_FACTOR as isize)
484 + 25)
485 * 100) as i32),
486 Err(i2c_error) => Err(i2c_error.into()),
487 };
488 self.temperature_client
489 .map(|client| client.callback(temperature));
490 self.buffer.replace(buffer);
491 self.i2c.disable();
492 self.state.set(State::Idle);
493 }
494
495 State::SetPowerModeAccel => {
496 self.buffer.replace(buffer);
497 self.i2c.disable();
498 self.state.set(State::Idle);
499 if status == Ok(()) {
500 if self.config_in_progress.get() {
501 if let Err(_error) = self.set_gyroscope_power_mode(
502 self.gyro_data_rate.get(),
503 self.low_power.get(),
504 ) {
505 self.config_in_progress.set(false);
506 }
507 }
508 } else {
509 self.config_in_progress.set(false);
510 }
511 self.syscall_process.take().map(|pid| {
512 let _res = self.apps.enter(pid, |_app, upcalls| {
513 upcalls
514 .schedule_upcall(
515 0,
516 (
517 into_statuscode(status.map_err(|i2c_error| i2c_error.into())),
518 usize::from(status == Ok(())),
519 0,
520 ),
521 )
522 .ok();
523 });
524 });
525 }
526
527 State::SetPowerModeGyro => {
528 self.buffer.replace(buffer);
529 self.i2c.disable();
530 self.state.set(State::Idle);
531 self.config_in_progress.set(false);
532 self.syscall_process.take().map(|pid| {
533 let _res = self.apps.enter(pid, |_app, upcalls| {
534 upcalls
535 .schedule_upcall(
536 0,
537 (
538 into_statuscode(status.map_err(|i2c_error| i2c_error.into())),
539 usize::from(status == Ok(())),
540 0,
541 ),
542 )
543 .ok();
544 });
545 });
546 }
547 }
548 }
549}
550
551impl<I: i2c::I2CDevice> SyscallDriver for Lsm6dsoxtrI2C<'_, I> {
552 fn command(
553 &self,
554 command_num: usize,
555 data1: usize,
556 data2: usize,
557 process_id: ProcessId,
558 ) -> CommandReturn {
559 if command_num == 0 {
560 return CommandReturn::success();
563 }
564
565 match command_num {
566 1 => {
568 if self.state.get() == State::Idle {
569 match self.send_is_present() {
570 Ok(()) => {
571 self.syscall_process.set(process_id);
572 CommandReturn::success()
573 }
574 Err(error) => CommandReturn::failure(error),
575 }
576 } else {
577 CommandReturn::failure(ErrorCode::BUSY)
578 }
579 }
580 2 => {
582 if self.state.get() == State::Idle {
583 if let Some(data_rate) = LSM6DSOXAccelDataRate::from_usize(data1) {
584 match self.set_accelerometer_power_mode(data_rate, data2 != 0) {
585 Ok(()) => {
586 self.syscall_process.set(process_id);
587 CommandReturn::success()
588 }
589 Err(error) => CommandReturn::failure(error),
590 }
591 } else {
592 CommandReturn::failure(ErrorCode::INVAL)
593 }
594 } else {
595 CommandReturn::failure(ErrorCode::BUSY)
596 }
597 }
598 3 => {
600 if self.state.get() == State::Idle {
601 if let Some(data_rate) = LSM6DSOXGyroDataRate::from_usize(data1) {
602 match self.set_gyroscope_power_mode(data_rate, data2 != 0) {
603 Ok(()) => {
604 self.syscall_process.set(process_id);
605 CommandReturn::success()
606 }
607 Err(error) => CommandReturn::failure(error),
608 }
609 } else {
610 CommandReturn::failure(ErrorCode::INVAL)
611 }
612 } else {
613 CommandReturn::failure(ErrorCode::BUSY)
614 }
615 }
616
617 _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
618 }
619 }
620 fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
621 self.apps.enter(processid, |_, _| {})
622 }
623}
624
625impl<'a, I: i2c::I2CDevice> NineDof<'a> for Lsm6dsoxtrI2C<'a, I> {
626 fn set_client(&self, nine_dof_client: &'a dyn NineDofClient) {
627 self.nine_dof_client.replace(nine_dof_client);
628 }
629
630 fn read_accelerometer(&self) -> Result<(), ErrorCode> {
631 self.read_acceleration_xyz()
632 }
633
634 fn read_gyroscope(&self) -> Result<(), ErrorCode> {
635 self.read_gyroscope_xyz()
636 }
637}
638
639impl<'a, I: i2c::I2CDevice> sensors::TemperatureDriver<'a> for Lsm6dsoxtrI2C<'a, I> {
640 fn set_client(&self, temperature_client: &'a dyn sensors::TemperatureClient) {
641 self.temperature_client.replace(temperature_client);
642 }
643
644 fn read_temperature(&self) -> Result<(), ErrorCode> {
645 self.read_temperature()
646 }
647}