1use core::cell::Cell;
47
48use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
49use kernel::hil::i2c;
50use kernel::syscall::{CommandReturn, SyscallDriver};
51use kernel::utilities::cells::{OptionalCell, TakeCell};
52use kernel::{ErrorCode, ProcessId};
53
54use capsules_core::driver;
56pub const DRIVER_NUM: usize = driver::NUM::Max17205 as usize;
57
58pub const BUFFER_LENGTH: usize = 8;
59
60enum Registers {
66 Status = 0x000,
67 RepCap = 0x005, FullCapRep = 0x035, NRomID = 0x1BC, Batt = 0x0DA, Current = 0x00A, Coulomb = 0x04D,
76}
77
78#[derive(Clone, Copy, PartialEq)]
79enum State {
80 Idle,
81
82 SetupReadCoulomb,
84 ReadCoulomb,
85 SetupReadStatus,
86 ReadStatus,
87 SetupReadSOC,
88 ReadSOC,
89 SetupReadCap,
90 ReadCap,
91 SetupReadVolt,
92 ReadVolt,
93 SetupReadCurrent,
94 ReadCurrent,
95 SetupReadRomID,
96 ReadRomID,
97}
98
99pub trait MAX17205Client {
100 fn status(&self, status: u16, error: Result<(), ErrorCode>);
101 fn state_of_charge(
102 &self,
103 percent: u16,
104 capacity: u16,
105 full_capacity: u16,
106 error: Result<(), ErrorCode>,
107 );
108 fn voltage_current(&self, voltage: u16, current: u16, error: Result<(), ErrorCode>);
109 fn coulomb(&self, coulomb: u16, error: Result<(), ErrorCode>);
110 fn romid(&self, rid: u64, error: Result<(), ErrorCode>);
111}
112
113pub struct MAX17205<'a, I: i2c::I2CDevice> {
114 i2c_lower: &'a I,
115 i2c_upper: &'a I,
116 state: Cell<State>,
117 soc: Cell<u16>,
118 soc_mah: Cell<u16>,
119 voltage: Cell<u16>,
120 buffer: TakeCell<'static, [u8]>,
121 client: OptionalCell<&'static dyn MAX17205Client>,
122}
123
124impl<'a, I: i2c::I2CDevice> MAX17205<'a, I> {
125 pub fn new(i2c_lower: &'a I, i2c_upper: &'a I, buffer: &'static mut [u8]) -> MAX17205<'a, I> {
126 MAX17205 {
127 i2c_lower,
128 i2c_upper,
129 state: Cell::new(State::Idle),
130 soc: Cell::new(0),
131 soc_mah: Cell::new(0),
132 voltage: Cell::new(0),
133 buffer: TakeCell::new(buffer),
134 client: OptionalCell::empty(),
135 }
136 }
137
138 pub fn set_client<C: MAX17205Client>(&self, client: &'static C) {
139 self.client.set(client);
140 }
141
142 fn setup_readstatus(&self) -> Result<(), ErrorCode> {
143 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buffer| {
144 self.i2c_lower.enable();
145
146 buffer[0] = Registers::Status as u8;
147
148 let _ = self.i2c_lower.write(buffer, 2);
150 self.state.set(State::SetupReadStatus);
151
152 Ok(())
153 })
154 }
155
156 fn setup_read_soc(&self) -> Result<(), ErrorCode> {
157 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buffer| {
158 self.i2c_lower.enable();
159
160 buffer[0] = Registers::RepCap as u8;
163 let _ = self.i2c_lower.write(buffer, 1);
165 self.state.set(State::SetupReadSOC);
166
167 Ok(())
168 })
169 }
170
171 fn setup_read_curvolt(&self) -> Result<(), ErrorCode> {
172 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buffer| {
173 self.i2c_lower.enable();
174
175 buffer[0] = Registers::Batt as u8;
178 let _ = self.i2c_lower.write(buffer, 1);
180 self.state.set(State::SetupReadVolt);
181
182 Ok(())
183 })
184 }
185
186 fn setup_read_coulomb(&self) -> Result<(), ErrorCode> {
187 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buffer| {
188 self.i2c_lower.enable();
189
190 buffer[0] = Registers::Coulomb as u8;
193 let _ = self.i2c_lower.write(buffer, 1);
195 self.state.set(State::SetupReadCoulomb);
196
197 Ok(())
198 })
199 }
200
201 fn setup_read_romid(&self) -> Result<(), ErrorCode> {
202 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buffer| {
203 self.i2c_upper.enable();
204 let nrom_id = Registers::NRomID as u16;
205
206 buffer[0] = (nrom_id & 0xFF) as u8;
207 buffer[1] = (nrom_id >> 8) as u8;
208 let _ = self.i2c_upper.write(buffer, 1);
210 self.state.set(State::SetupReadRomID);
211
212 Ok(())
213 })
214 }
215}
216
217impl<I: i2c::I2CDevice> i2c::I2CClient for MAX17205<'_, I> {
218 fn command_complete(&self, buffer: &'static mut [u8], error: Result<(), i2c::Error>) {
219 match self.state.get() {
220 State::SetupReadStatus => {
221 let _ = self.i2c_lower.read(buffer, 2);
224 self.state.set(State::ReadStatus);
225 }
226 State::ReadStatus => {
227 let status = ((buffer[1] as u16) << 8) | (buffer[0] as u16);
228
229 self.client.map(|client| {
230 client.status(
231 status,
232 match error {
233 Ok(()) => Ok(()),
234 Err(e) => Err(e.into()),
235 },
236 )
237 });
238
239 self.buffer.replace(buffer);
240 self.i2c_lower.disable();
241 self.state.set(State::Idle);
242 }
243 State::SetupReadSOC => {
244 let _ = self.i2c_lower.read(buffer, 4);
247 self.state.set(State::ReadSOC);
248 }
249 State::ReadSOC => {
250 self.soc_mah
252 .set(((buffer[1] as u16) << 8) | (buffer[0] as u16));
253 self.soc.set(((buffer[3] as u16) << 8) | (buffer[2] as u16));
254
255 self.buffer.replace(buffer);
256
257 self.buffer.take().map(|selfbuf| {
260 selfbuf[0] = (Registers::FullCapRep as u8) & 0xFF;
263 let _ = self.i2c_lower.write(selfbuf, 1);
265
266 self.state.set(State::SetupReadCap);
267 });
268 }
269 State::SetupReadCap => {
270 let _ = self.i2c_lower.read(buffer, 2);
273 self.state.set(State::ReadCap);
274 }
275 State::ReadCap => {
276 let full_mah = ((buffer[1] as u16) << 8) | (buffer[0] as u16);
277
278 self.client.map(|client| {
279 client.state_of_charge(
280 self.soc.get(),
281 self.soc_mah.get(),
282 full_mah,
283 match error {
284 Ok(()) => Ok(()),
285 Err(e) => Err(e.into()),
286 },
287 );
288 });
289
290 self.buffer.replace(buffer);
291 self.i2c_lower.disable();
292 self.state.set(State::Idle);
293 }
294 State::SetupReadCoulomb => {
295 let _ = self.i2c_lower.read(buffer, 2);
298 self.state.set(State::ReadCoulomb);
299 }
300 State::ReadCoulomb => {
301 let coulomb = ((buffer[1] as u16) << 8) | (buffer[0] as u16);
303
304 self.client.map(|client| {
305 client.coulomb(
306 coulomb,
307 match error {
308 Ok(()) => Ok(()),
309 Err(e) => Err(e.into()),
310 },
311 );
312 });
313
314 self.buffer.replace(buffer);
315 self.i2c_lower.disable();
316 self.state.set(State::Idle);
317 }
318 State::SetupReadVolt => {
319 let _ = self.i2c_lower.read(buffer, 2);
322 self.state.set(State::ReadVolt);
323 }
324 State::ReadVolt => {
325 self.voltage
327 .set(((buffer[1] as u16) << 8) | (buffer[0] as u16));
328
329 self.buffer.replace(buffer);
330
331 self.buffer.take().map(|selfbuf| {
334 selfbuf[0] = (Registers::Current as u8) & 0xFF;
335 let _ = self.i2c_lower.write(selfbuf, 1);
337
338 self.state.set(State::SetupReadCurrent);
339 });
340 }
341 State::SetupReadCurrent => {
342 let _ = self.i2c_lower.read(buffer, 2);
345 self.state.set(State::ReadCurrent);
346 }
347 State::ReadCurrent => {
348 let current = ((buffer[1] as u16) << 8) | (buffer[0] as u16);
349
350 self.client.map(|client| {
351 client.voltage_current(
352 self.voltage.get(),
353 current,
354 match error {
355 Ok(()) => Ok(()),
356 Err(e) => Err(e.into()),
357 },
358 )
359 });
360
361 self.buffer.replace(buffer);
362 self.i2c_lower.disable();
363 self.state.set(State::Idle);
364 }
365 State::SetupReadRomID => {
366 let _ = self.i2c_upper.read(buffer, 8);
368 self.state.set(State::ReadRomID);
369 }
370 State::ReadRomID => {
371 let rid = buffer
373 .iter()
374 .take(8)
375 .enumerate()
376 .fold(0u64, |rid, (i, b)| rid | ((*b as u64) << (i * 8)));
377 self.buffer.replace(buffer);
378
379 self.client.map(|client| {
380 client.romid(
381 rid,
382 match error {
383 Ok(()) => Ok(()),
384 Err(e) => Err(e.into()),
385 },
386 )
387 });
388
389 self.i2c_upper.disable();
390 self.state.set(State::Idle);
391 }
392 _ => {}
393 }
394 }
395}
396
397mod upcall {
399 pub const EVENT_COMPLETE: usize = 0;
401 pub const COUNT: u8 = 1;
403}
404
405#[derive(Default)]
406pub struct App {}
407
408pub struct MAX17205Driver<'a, I: i2c::I2CDevice> {
409 max17205: &'a MAX17205<'a, I>,
410 owning_process: OptionalCell<ProcessId>,
411 apps: Grant<App, UpcallCount<{ upcall::COUNT }>, AllowRoCount<0>, AllowRwCount<0>>,
412}
413
414impl<'a, I: i2c::I2CDevice> MAX17205Driver<'a, I> {
415 pub fn new(
416 max: &'a MAX17205<I>,
417 grant: Grant<App, UpcallCount<{ upcall::COUNT }>, AllowRoCount<0>, AllowRwCount<0>>,
418 ) -> Self {
419 Self {
420 max17205: max,
421 owning_process: OptionalCell::empty(),
422 apps: grant,
423 }
424 }
425}
426
427impl<I: i2c::I2CDevice> MAX17205Client for MAX17205Driver<'_, I> {
428 fn status(&self, status: u16, error: Result<(), ErrorCode>) {
429 self.owning_process.map(|pid| {
430 let _ = self.apps.enter(pid, |_app, upcalls| {
431 upcalls
432 .schedule_upcall(
433 upcall::EVENT_COMPLETE,
434 (
435 kernel::errorcode::into_statuscode(error),
436 status as usize,
437 0,
438 ),
439 )
440 .ok();
441 });
442 });
443 }
444
445 fn state_of_charge(
446 &self,
447 percent: u16,
448 capacity: u16,
449 full_capacity: u16,
450 error: Result<(), ErrorCode>,
451 ) {
452 self.owning_process.map(|pid| {
453 let _ = self.apps.enter(pid, |_app, upcalls| {
454 upcalls
455 .schedule_upcall(
456 upcall::EVENT_COMPLETE,
457 (
458 kernel::errorcode::into_statuscode(error),
459 percent as usize,
460 (capacity as usize) << 16 | (full_capacity as usize),
461 ),
462 )
463 .ok();
464 });
465 });
466 }
467
468 fn voltage_current(&self, voltage: u16, current: u16, error: Result<(), ErrorCode>) {
469 self.owning_process.map(|pid| {
470 let _ = self.apps.enter(pid, |_app, upcalls| {
471 upcalls
472 .schedule_upcall(
473 upcall::EVENT_COMPLETE,
474 (
475 kernel::errorcode::into_statuscode(error),
476 voltage as usize,
477 current as usize,
478 ),
479 )
480 .ok();
481 });
482 });
483 }
484
485 fn coulomb(&self, coulomb: u16, error: Result<(), ErrorCode>) {
486 self.owning_process.map(|pid| {
487 let _ = self.apps.enter(pid, |_app, upcalls| {
488 upcalls
489 .schedule_upcall(
490 upcall::EVENT_COMPLETE,
491 (
492 kernel::errorcode::into_statuscode(error),
493 coulomb as usize,
494 0,
495 ),
496 )
497 .ok();
498 });
499 });
500 }
501
502 fn romid(&self, rid: u64, error: Result<(), ErrorCode>) {
503 self.owning_process.map(|pid| {
504 let _ = self.apps.enter(pid, |_app, upcalls| {
505 upcalls
506 .schedule_upcall(
507 upcall::EVENT_COMPLETE,
508 (
509 kernel::errorcode::into_statuscode(error),
510 (rid & 0xffffffff) as usize,
511 (rid >> 32) as usize,
512 ),
513 )
514 .ok();
515 });
516 });
517 }
518}
519
520impl<I: i2c::I2CDevice> SyscallDriver for MAX17205Driver<'_, I> {
521 fn command(
532 &self,
533 command_num: usize,
534 _data: usize,
535 _: usize,
536 process_id: ProcessId,
537 ) -> CommandReturn {
538 if command_num == 0 {
539 return CommandReturn::success();
542 }
543 let match_or_empty_or_nonexistant = self.owning_process.map_or(true, |current_process| {
546 self.apps
547 .enter(current_process, |_, _| current_process == process_id)
548 .unwrap_or(true)
549 });
550 if match_or_empty_or_nonexistant {
551 self.owning_process.set(process_id);
552 } else {
553 return CommandReturn::failure(ErrorCode::NOMEM);
554 }
555 match command_num {
556 0 => CommandReturn::success(),
557
558 1 => self.max17205.setup_readstatus().into(),
560
561 2 => self.max17205.setup_read_soc().into(),
563
564 3 => self.max17205.setup_read_curvolt().into(),
566
567 4 => self.max17205.setup_read_coulomb().into(),
569
570 5 => self.max17205.setup_read_romid().into(),
572
573 _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
575 }
576 }
577
578 fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
579 self.apps.enter(processid, |_, _| {})
580 }
581}