22// driver/battery/smart.c
33// include/battery_smart.h
44use alloc:: vec:: Vec ;
5- use num_traits:: FromPrimitive ;
65
7- use crate :: chromium_ec:: command:: EcRequestRaw ;
8- use crate :: chromium_ec:: commands:: { EcRequestGetGpuPcie , GpuVendor } ;
96use crate :: chromium_ec:: i2c_passthrough:: * ;
107use crate :: chromium_ec:: { CrosEc , EcResult } ;
11- use crate :: os_specific;
8+ // use crate::os_specific;
129
13- #[ repr( u8 ) ]
10+ #[ repr( u16 ) ]
1411enum SmartBatReg {
1512 Mode = 0x03 ,
1613 Temp = 0x08 ,
1714 ManufactureDate = 0x1B ,
1815 SerialNum = 0x1C ,
1916 CycleCount = 0x17 ,
17+ /// String
18+ ManufacturerName = 0x20 ,
2019 DeviceName = 0x21 ,
20+ Soh = 0x4F ,
2121}
2222
23- #[ repr( u8 ) ]
23+ #[ repr( u16 ) ]
2424/// ManufacturerAccess block
2525/// Needs unseal
26+ /// On EC Console can read these with
27+ /// If CONFIG_CMD_BATT_MFG_ACCESS
28+ /// > mattmfgacc 0xBEEF 0x50 2
2629enum ManufReg {
2730 SafetyAlert = 0x50 ,
2831 SafetyStatus = 0x51 ,
@@ -32,50 +35,113 @@ enum ManufReg {
3235 LifeTimeDataBlock3 = 0x62 ,
3336}
3437
35- // fn get_i16(ec: &CrosEC) ->
38+ pub struct SmartBattery {
39+ i2c_port : u8 ,
40+ i2c_addr : u16 ,
41+ }
42+
43+ impl SmartBattery {
44+ pub fn new ( ) -> Self {
45+ SmartBattery {
46+ // Same on all our Nuvoton ECs
47+ i2c_port : 3 ,
48+ // 0x0B 7-bit, 0x016 8-bit address
49+ // Same for all our batteries, they use the same IC
50+ i2c_addr : 0x16 ,
51+ }
52+ }
3653
37- pub fn dump_data ( ec : & CrosEc ) -> EcResult < Option < Vec < u8 > > > {
38- // I2C Port on the EC
39- let i2c_port = 3 ;
40- // 8-bit I2C address of the battery
41- // EC passthrough needs 7-bit, so shift one over before sending to EC
42- let i2c_addr = 0x0b << 1 ;
54+ fn read_bytes ( & self , ec : & CrosEc , addr : u16 , len : u16 ) -> EcResult < Vec < u8 > > {
55+ let i2c_response = i2c_read ( ec, self . i2c_port , self . i2c_addr >> 1 , addr, len) ?;
56+ i2c_response. is_successful ( ) ?;
57+ Ok ( i2c_response. data )
58+ }
59+ fn read_i16 ( & self , ec : & CrosEc , addr : u16 ) -> EcResult < i16 > {
60+ let i2c_response = i2c_read ( ec, self . i2c_port , self . i2c_addr >> 1 , addr, 0x02 ) ?;
61+ i2c_response. is_successful ( ) ?;
62+ Ok ( i16:: from_le_bytes ( [
63+ i2c_response. data [ 1 ] ,
64+ i2c_response. data [ 1 ] ,
65+ ] ) )
66+ }
67+ fn read_string ( & self , ec : & CrosEc , addr : u16 ) -> EcResult < String > {
68+ let i2c_response = i2c_read ( ec, self . i2c_port , self . i2c_addr >> 1 , addr, 16 ) ?;
69+ i2c_response. is_successful ( ) ?;
4370
44- // Check mode
45- let i2c_response = i2c_read ( ec, i2c_port, i2c_addr >> 1 , 0x03 , 0x01 ) ?;
46- println ! ( "Mode: {:?}" , i2c_response. data) ;
47- let i2c_response = i2c_read ( ec, i2c_port, i2c_addr >> 1 , 0x1c , 0x02 ) ?;
48- println ! ( "Serial: {:X?}" , i2c_response. data) ;
49- let i2c_response = i2c_read ( ec, i2c_port, i2c_addr >> 1 , 0x08 , 0x02 ) ?;
50- println ! ( "Temp: {:X?}" , i2c_response. data) ;
51- let i2c_response = i2c_read ( ec, i2c_port, i2c_addr >> 1 , 0x17 , 0x02 ) ?;
52- println ! ( "Cycle Ct: {:?}" , i2c_response. data) ;
53- let i2c_response = i2c_read ( ec, i2c_port, i2c_addr >> 1 , 0x21 , 0x08 ) ?;
54- // 0A 46 52 41 "FRAN...
55- println ! ( "Dev Name: {:X?}" , i2c_response. data) ;
71+ // First byte is the returned string length
72+ let str_bytes = & i2c_response. data [ 1 ..=( i2c_response. data [ 0 ] as usize ) ] ;
73+ Ok ( String :: from_utf8_lossy ( str_bytes) . to_string ( ) )
74+ }
5675
57- let i2c_response = i2c_read ( ec, i2c_port, i2c_addr >> 1 , 0x4F , 0x02 ) ?;
58- println ! ( "SOH: {:?}" , i2c_response. data) ;
76+ pub fn dump_data ( & self , ec : & CrosEc ) -> EcResult < ( ) > {
77+ // Check mode
78+ println ! (
79+ "Mode: {:?}" ,
80+ self . read_i16( ec, SmartBatReg :: Mode as u16 ) ?
81+ ) ;
82+ println ! (
83+ "Serial Num: {:04X?}" ,
84+ self . read_i16( ec, SmartBatReg :: SerialNum as u16 ) ?
85+ ) ;
86+ println ! (
87+ "Manuf Date: {:04X?}" ,
88+ self . read_i16( ec, SmartBatReg :: ManufactureDate as u16 ) ?
89+ ) ;
90+ println ! (
91+ "Temperature: {:?}" ,
92+ self . read_i16( ec, SmartBatReg :: Temp as u16 ) ?
93+ ) ;
94+ println ! (
95+ "Cycle Count: {:?}" ,
96+ self . read_i16( ec, SmartBatReg :: CycleCount as u16 ) ?
97+ ) ;
98+ println ! (
99+ "Device Name: {}" ,
100+ self . read_string( ec, SmartBatReg :: DeviceName as u16 ) ?
101+ ) ;
102+ println ! (
103+ "Manuf Name: {}" ,
104+ self . read_string( ec, SmartBatReg :: ManufacturerName as u16 ) ?
105+ ) ;
106+ println ! (
107+ "StateOfHealth: {:?}" ,
108+ self . read_i16( ec, SmartBatReg :: Soh as u16 ) ?
109+ ) ;
59110
60- // Need to unseal for access
61- // SE [US] [FA]
62- let i2c_response = i2c_read ( ec, i2c_port, i2c_addr >> 1 , 0x51 , 0x02 ) ?;
63- println ! ( "SafetyAlrt{:?}" , i2c_response. data) ;
64- let i2c_response = i2c_read ( ec, i2c_port, i2c_addr >> 1 , 0x53 , 0x02 ) ?;
65- println ! ( "SafetySts:{:?}" , i2c_response. data) ;
66- let i2c_response = i2c_read ( ec, i2c_port, i2c_addr >> 1 , 0x51 , 0x02 ) ?;
67- println ! ( "PFAlert: {:?}" , i2c_response. data) ;
68- let i2c_response = i2c_read ( ec, i2c_port, i2c_addr >> 1 , 0x53 , 0x02 ) ?;
69- println ! ( "PFStatus: {:?}" , i2c_response. data) ;
70- let i2c_response = i2c_read ( ec, i2c_port, i2c_addr >> 1 , 0x60 , 0x02 ) ?;
71- println ! ( "LifeTime1 {:?}" , i2c_response. data) ;
72- let i2c_response = i2c_read ( ec, i2c_port, i2c_addr >> 1 , 0x61 , 0x02 ) ?;
73- println ! ( "LifeTime2 {:?}" , i2c_response. data) ;
74- let i2c_response = i2c_read ( ec, i2c_port, i2c_addr >> 1 , 0x61 , 0x02 ) ?;
75- println ! ( "LifeTime3 {:?}" , i2c_response. data) ;
111+ // Need to unseal for access
112+ // SE [US] [FA]
113+ println ! (
114+ "Safety Alert: {:?}" ,
115+ self . read_i16( & ec, ManufReg :: SafetyAlert as u16 ) ?
116+ ) ;
117+ println ! (
118+ "Safety Status: {:?}" ,
119+ self . read_i16( & ec, ManufReg :: SafetyStatus as u16 ) ?
120+ ) ;
121+ println ! (
122+ "PFAlert: {:?}" ,
123+ self . read_i16( & ec, ManufReg :: PFAlert as u16 ) ?
124+ ) ;
125+ println ! (
126+ "PFStatus: {:?}" ,
127+ self . read_i16( & ec, ManufReg :: SafetyAlert as u16 ) ?
128+ ) ;
129+ println ! (
130+ "LifeTime1 {:X?}" ,
131+ self . read_bytes( ec, ManufReg :: LifeTimeDataBlock1 as u16 , 4 ) ?
132+ ) ;
133+ println ! (
134+ "LifeTime2 {:X?}" ,
135+ self . read_bytes( ec, ManufReg :: LifeTimeDataBlock2 as u16 , 4 ) ?
136+ ) ;
137+ println ! (
138+ "LifeTime3 {:X?}" ,
139+ self . read_bytes( ec, ManufReg :: LifeTimeDataBlock3 as u16 , 4 ) ?
140+ ) ;
76141
77- // i2c_write(ec, i2c_port, (i2c_addr + 2) >> 1, 0x70, &[0x00])?;
78- // os_specific::sleep(50_000);
142+ // i2c_write(ec, i2c_port, (i2c_addr + 2) >> 1, 0x70, &[0x00])?;
143+ // os_specific::sleep(50_000);
79144
80- Ok ( Some ( i2c_response. data ) )
145+ Ok ( ( ) )
146+ }
81147}
0 commit comments