blob: 1a06314dd4dfc0174f2da33a42aa484c84e72677 [file] [log] [blame]
Benjamin Doron289a67d2019-09-22 17:33:12 +10001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#if !CONFIG(EC_USE_LGMR)
4/* TODO: Consider actually enforcing mutex? */
5Mutex (BMTX, 0)
6#endif
7Name (B0ST, 0) /* Battery 0 status */
8
9/*
10 * EC Registers
11 *
12 * "EBID" is the battery page selector.
13 *
14 *
15 * Data on the 128 bits following offset
16 * 0xE0 is accessed in the following order:
17 *
18 * Information:
19 * Page 0: EBCM # start on page 0 #
20 * Page 0: EBFC
21 * Page 1: EBDC # switch to page 1 #
22 * Page 1: EBDV
23 * Page 1: EBSN
24 * Page 3: EBDN # switch to page 3 #
25 * Page 4: EBCH # switch to page 4 #
26 * Page 2: EBMN # switch to page 2 #
27 *
28 * Status:
29 * Page 0: EBAC # start on page 0 #
30 * Page 0: EBRC
31 * Page 0: EBFC
32 * Page 0: EBVO
33 */
34/* Page 0 */
35Field (RAM, ByteAcc, Lock, Preserve)
36{
37 Offset (0xE0),
38 EBRC, 16, /* Battery remaining capacity */
39 EBFC, 16, /* Battery full charge capacity */
40 EBPE, 16,
41 EBAC, 16, /* Battery present rate */
42 EBVO, 16, /* Battery voltage */
43 , 15,
44 EBCM, 1, /* Battery charging */
45 EBCU, 16,
46 EBTV, 16,
47}
48
49/* Page 1 */
50Field (RAM, ByteAcc, Lock, Preserve)
51{
52 Offset (0xE0),
53 EBDC, 16, /* Battery design capacity */
54 EBDV, 16, /* Battery design voltage */
55 EBSN, 16, /* Battery serial number */
56}
57
58/* Page 2 */
59Field (RAM, ByteAcc, NoLock, Preserve)
60{
61 Offset (0xE0),
62 EBMN, 128, /* Battery manufacturer */
63}
64
65/* Page 3 */
66Field (RAM, ByteAcc, NoLock, Preserve)
67{
68 Offset (0xE0),
69 EBDN, 128, /* Battery model */
70}
71
72/* Page 4 */
73Field (RAM, ByteAcc, NoLock, Preserve)
74{
75 Offset (0xE0),
76 EBCH, 128, /* Battery type */
77}
78
79#if CONFIG(EC_USE_LGMR)
80OperationRegion (MBB0, SystemMemory, (LGMR + 0x80), 0xFF)
81Field (MBB0, ByteAcc, Lock, Preserve)
82{
83 MBRC, 16,
84 MBFC, 16,
85 MBPE, 16,
86 MBAC, 16,
87 MBVO, 16,
88 , 15,
89 MBCM, 1,
90 MBCU, 16,
91 MBTV, 16,
92}
93
94Field (MBB0, ByteAcc, Lock, Preserve)
95{
96 Offset (0x10),
97 MBDC, 16,
98 MBDV, 16,
99 MBSN, 16,
100}
101
102Field (MBB0, ByteAcc, Lock, Preserve)
103{
104 Offset (0x40),
105 MBMN, 128,
106}
107
108Field (MBB0, ByteAcc, Lock, Preserve)
109{
110 Offset (0x50),
111 MBDN, 256,
112}
113
114Field (MBB0, ByteAcc, Lock, Preserve)
115{
116 Offset (0x70),
117 MBCH, 128,
118}
119#endif
120
121/*
122 * Arg0: Battery number
123 * Arg1: Battery Information Package
124 * Arg2: Status
125 */
126#if !CONFIG(EC_USE_LGMR)
127Method (GBIF, 3, Serialized)
128{
129 Acquire (BMTX, 0xFFFF) // Due to EC paging, don't run this with another function
130#else
131Method (GBIF, 3, NotSerialized)
132{
133#endif
134 If (Arg2)
135 {
136 Arg1[1] = 0xFFFFFFFF
137 Arg1[2] = 0xFFFFFFFF
138 Arg1[4] = 0xFFFFFFFF
139 Arg1[5] = 0
140 Arg1[6] = 0
141 }
142 Else
143 {
144#if CONFIG(EC_USE_LGMR)
145 Local0 = MBCM
146#else
147 EBID = 0 // We don't know which page was active
148 Local0 = EBCM
149#endif
150 Arg1[0] = (Local0 ^ 1)
151
152#if CONFIG(EC_USE_LGMR)
153 Local2 = MBFC
154 Local1 = MBDC
155#else
156 Local2 = EBFC
157 EBID = 1
158 Local1 = EBDC
159#endif
160 If (Local0)
161 {
162 Local2 *= 10
163 Local1 *= 10
164 }
165
166 Arg1[1] = Local1 // Design capacity
167 Arg1[2] = Local2 // Last full charge capacity
168#if CONFIG(EC_USE_LGMR)
169 Arg1[4] = MBDV // Design voltage
170#else
171 Arg1[4] = EBDV // Design voltage
172#endif
173 Local6 = (Local2 / 100) // Warning capacities; Remainders ignored
174 Arg1[5] = (Local6 * 7) /* Low: 7% */
175 Arg1[6] = ((Local6 * 11) / 2) /* Very low: 5.5% */
176#if CONFIG(EC_USE_LGMR)
177 Local7 = MBSN
178#else
179 Local7 = EBSN
180#endif
181 Name (SERN, Buffer (0x06) { " " })
182 /*
183 * Convert hex to decimal.
184 * - There appears to be a bug in the vendor's implementation:
185 * The correct answer has, or can have, 5 digits, so Local6 = 5.
186 * Also see "SERN" buffer.
187 * - Userspace prints reversed serial number?
188 */
189 Local6 = 4
190 While (Local7)
191 {
Felix Singer81713642022-12-25 16:54:45 +0100192 Local5 = Local7 % 10
193 Local7 = Local7 / 10
Benjamin Doron289a67d2019-09-22 17:33:12 +1000194 SERN[Local6] = (Local5 + 0x30) // Add 0x30 to get numeric ASCII
195 Local6--
196 }
197
198 Arg1[10] = SERN // Serial number
199#if CONFIG(EC_USE_LGMR)
200 Arg1[9] = MBDN // Model number
201 Arg1[11] = MBCH // Battery type
202 Arg1[12] = MBMN // OEM information
203#else
204 EBID = 3
205 Arg1[9] = EBDN // Model number
206 EBID = 4
207 Arg1[11] = EBCH // Battery type
208 EBID = 2
209 Arg1[12] = EBMN // OEM information
210#endif
211 }
212
213#if !CONFIG(EC_USE_LGMR)
214 Release (BMTX)
215#endif
216 Return (Arg1)
217}
218
219/*
220 * Arg0: Battery number
221 * Arg1: State information
222 * Arg2: Power units
223 * Arg3: Battery Status Package
224 */
225Method (GBST, 4, NotSerialized) // All on one page
226{
227#if !CONFIG(EC_USE_LGMR)
228 Acquire (BMTX, 0xFFFF) // Due to EC paging, don't run this with another function
229#endif
230 If (Arg1 & 0x02) // BIT1 in "MB0S/EB0S"
231 {
232 Local0 = 2
233 If (Arg1 & 0x20) // "EB0F"
234 {
235 Local0 = 0
236 }
237 }
238 ElseIf (Arg1 & 0x04) // BIT2 in "MB0S/EB0S"
239 {
240 Local0 = 1
241 }
242 Else
243 {
244 Local0 = 0
245 }
246
247 If (Arg1 & 0x10) // "EB0L"
248 {
249 Local0 |= 0x04
250 }
251
252 If (Arg1 & 0x01) // "EB0A"
253 {
254 /*
255 * Present rate is a 16bit signed int, positive while charging
256 * and negative while discharging.
257 */
258#if CONFIG(EC_USE_LGMR)
259 Local1 = MBAC
260 Local2 = MBRC
261 If (MACS) // Charging
262#else
263 EBID = 0 // We don't know which page was active
264 Local1 = EBAC
265 Local2 = EBRC
266 If (EACS) // Charging
267#endif
268 {
269 If (Arg1 & 0x20) // "EB0F"
270 {
271#if CONFIG(EC_USE_LGMR)
272 Local2 = MBFC
273#else
274 Local2 = EBFC
275#endif
276 }
277 }
278
279 If (Arg2)
280 {
281 Local2 *= 10
282 }
283
284#if CONFIG(EC_USE_LGMR)
285 Local3 = MBVO
286#else
287 Local3 = EBVO
288#endif
289 /*
290 * The present rate value should be positive unless discharging. If so,
291 * negate present rate.
292 */
293 If (Local1 >= 0x8000)
294 {
295 If (Local0 & 0x01)
296 {
297 Local1 = (0x00010000 - Local1)
298 }
299 Else
300 {
301 Local1 = 0 // Full battery, force to 0
302 }
303 }
304 /*
305 * If that was not the case, we have an EC bug or inconsistency
306 * and force the value to 0.
307 */
308 ElseIf ((Local0 & 0x02) == 0)
309 {
310 Local1 = 0
311 }
312
313 If (Arg2)
314 {
315 Local1 *= Local3
316 Local1 /= 1000 /* Remainder ignored by vendor */
317 }
318 }
319 Else
320 {
321 Local0 = 0
322 Local1 = 0xFFFFFFFF
323 Local2 = 0xFFFFFFFF
324 Local3 = 0xFFFFFFFF
325 }
326
327 Arg3[0] = Local0
328 Arg3[1] = Local1
329 Arg3[2] = Local2
330 Arg3[3] = Local3
331
332#if !CONFIG(EC_USE_LGMR)
333 Release (BMTX)
334#endif
335 Return (Arg3)
336}
337
338Device (BAT0)
339{
340 Name (_HID, EisaId ("PNP0C0A") /* Control Method Battery */) // _HID: Hardware ID
341 Name (_UID, 0) // _UID: Unique ID
342 Name (_PCL, Package () { \_SB }) // _PCL: Power Consumer List
343
344 Name (B0IP, Package (0x0D)
345 {
346 1, /* 0x00: Power Unit: mAh */
347 0xFFFFFFFF, /* 0x01: Design Capacity */
348 0xFFFFFFFF, /* 0x02: Last Full Charge Capacity */
349 1, /* 0x03: Battery Technology: Rechargeable */
350 0xFFFFFFFF, /* 0x04: Design Voltage */
351 0, /* 0x05: Design Capacity of Warning */
352 0, /* 0x06: Design Capacity of Low */
353 1, /* 0x07: Capacity Granularity 1 */
354 1, /* 0x08: Capacity Granularity 2 */
355 "", /* 0x09: Model Number */
356 "100", /* 0x0a: Serial Number */
357 "Lion", /* 0x0b: Battery Type */
358 0 /* 0x0c: OEM Information */
359 })
360 Name (B0SP, Package (0x04)
361 {
362 0, /* 0x00: Battery State */
363 0xFFFFFFFF, /* 0x01: Battery Present Rate */
364 0xFFFFFFFF, /* 0x02: Battery Remaining Capacity */
365 0xFFFFFFFF /* 0x03: Battery Present Voltage */
366 })
367 Method (_STA, 0, NotSerialized) // _STA: Status
368 {
369 /* Bitwise AND by vendor is lossy? */
370 Local1 = EB0A
371 If (Local1 & 0x40)
372 {
373 Local1 = 0
374 }
375
376 B0ST = Local1
377 If (Local1)
378 {
379 Return (0x1F)
380 }
381 Else
382 {
383 Return (0x0F)
384 }
385 }
386
387 Method (_BIF, 0, NotSerialized) // _BIF: Battery Information
388 {
389 Local6 = B0ST
390 Local7 = 20
391 While (Local6 && Local7)
392 {
393 If (EB0R)
394 {
395 Local6 = 0
396 }
397 Else
398 {
399 Sleep (500)
400 Local7--
401 }
402 }
403
404 Return (GBIF (0, B0IP, Local6))
405 }
406
407 Method (_BST, 0, NotSerialized) // _BST: Battery Status
408 {
409 Local0 = (DerefOf (B0IP[0]) ^ 1)
410#if CONFIG(EC_USE_LGMR)
411 Local5 = MB0S
412#else
413 Local5 = EB0S
414#endif
415 Return (GBST (0, Local5, Local0, B0SP))
416 }
417}