/* SPDX-License-Identifier: GPL-2.0-only */

// Scope (EC0)

/* Mutex for EC battery index interface */
Mutex (BATM, 0)

// Wait for desired battery index to be presented in shared memory
//   Arg0 = battery index
//   Returns 0 on success, 1 on error.
Method (BTSW, 1)
{
#ifdef EC_ENABLE_SECOND_BATTERY_DEVICE
	If (BTIX == Arg0) {
		Return (0)
	}
	If (Arg0 >= BTCN) {
		Return (1)
	}
	\_SB.PCI0.LPCB.EC0.BTID = Arg0
	Local0 = 5      // Timeout 5 msec
	While (BTIX != Arg0)
	{
		Sleep (1)
		Local0--
		If (Local0 == 0)
		{
			Return (1)
		}
	}
#else
	If (Arg0 != 0) {
		Return (1)
	}
#endif
	Return (0)
}

// _STA implementation.
//   Arg0 = battery index
Method (BSTA, 1, Serialized)
{
	If (Acquire (^BATM, 1000)) {
		Return (0)
	}

	If (~BTSW (Arg0) & BTEX) {
		Local0 = 0x1F
	} Else {
		Local0 = 0x0F
	}

	Release (^BATM)
	Return (Local0)
}

#if CONFIG(EC_GOOGLE_CHROMEEC_READ_BATTERY_LONG_STRING)
// Cached flag for BSRF FIFO readout support from EC.
Name(BRSS, 0xff)
#else
Name(BRSS, 0x0)
#endif
// Cached battery string response indicator
Name(BRI1, 0)
Name(BRI2, 0)
Name(BRI3, 0)
// Cached battery string response data to save suspend-resume time
Name(BRS1, Buffer(32) {0})
Name(BRS2, Buffer(32) {0})
Name(BRS3, Buffer(32) {0})
// Read extended battery strings from the selected battery.
//   Arg0 = string index
//
// If supported by the EC, strings of arbitrary length are read using the
// FIFO readout method. Otherwise short (no more than 8 bytes) strings are
// read from the EC shared memory map. The desired battery index should be
// selected with BTSW before calling this method.
//
// Currently supported string indexes:
//  * 1 = EC_ACPI_MEM_STRINGS_FIFO_ID_BATTERY_MODEL: battery model name,
//        equivalent to BMOD.
//  * 2 = EC_ACPI_MEM_STRINGS_FIFO_ID_BATTERY_SERIAL: battery serial number,
//        equivalent to BSER.
//  * 3 = EC_ACPI_MEM_STRINGS_FIFO_ID_BATTERY_MANUFACTURER: battery
//        manufacturer's name, equivalent to BMFG.
//
// These are assumed to be supported if the EC reports at least version 1 of
// string readout (it returns an integer greater than 0 and less than 255 when
// reading FIFO index 0). Future strings may require higher FIFO versions.
Method(BRSX, 1, Serialized)
{
	// It doesn't make sense to read the FIFO support indicator.
	if (Arg0 == 0 || Arg0 > 3)
	{
		Return ("")
	}

	// Check if response is already cached
	If (Arg0 == 1 && BRI1 == 1)
	{
		Return (BRS1) /* battery model name */
	}

	If (Arg0 == 2 && BRI2 == 1)
	{
		Return (BRS2) /* battery serial number */
	}

	If (Arg0 == 3 && BRI3 == 1)
	{
		Return (BRS3) /* battery manufacturer's name */
	}

	If (BRSS == 0xff)
	{
		// Write 0 to BSRF to read back a support indicator; nonzero and
		// non-0xFF if FIFO readout is supported, assuming minimum v1 support
		// for strings 1 through 3.
		BSRF = 0
		BRSS = BSRF

		// 0xff readback also means no support for FIFO readout, when the EC
		// doesn't even know what this command is.
		if (BRSS == 0xff)
		{
			BRSS = 0
		}
	}

	// If FIFO readout through BSRF is not supported, fall back to reading
	// the short strings in EMEM.
	If (BRSS == 0)
	{
		If (Arg0 == 1)
		{
			Local0 = ToString (Concatenate (BMOD, 0))
		}
		ElseIf (Arg0 == 2)
		{
			Local0 = ToString (Concatenate (BSER, 0))
		}
		ElseIf (Arg0 == 3)
		{
			Local0 = ToString (Concatenate (BMFG, 0))
		}
	}
	Else
	{
		// Select requested parameter to read
		BSRF = Arg0

		// Read to end of string, or up to a reasonable maximum length. Reads of
		// BSRF consume bytes from the FIFO, so take care to read it only once
		// per byte of data.
		Local0 = ""
		Local1 = BSRF
		While (Local1 != 0 && SizeOf (Local0) < 32)
		{
			Local0 = Concatenate (Local0, ToString (Local1))
			Local1 = BSRF
		}
	}

	// Store the result in the cache
	If (Arg0 == 1)
	{
		BRS1 = Local0
		BRI1 = 1
	}

	If (Arg0 == 2)
	{
		BRS2 = Local0
		BRI2 = 1
	}

	If (Arg0 == 3)
	{
		BRS3 = Local0
		BRI3 = 1
	}

	Return (Local0)
}

// _BIF implementation.
//   Arg0 = battery index
//   Arg1 = PBIF
Method (BBIF, 2, Serialized)
{
	If (Acquire (^BATM, 1000)) {
		Return (Arg1)
	}

	If (BTSW (Arg0)) {
		Release (^BATM)
		Return (Arg1)
	}
	// Last Full Charge Capacity
	Arg1[2] = BTDF

	// Design Voltage
	Arg1[4] = BTDV

	// Design Capacity
	Local0 = BTDA
	Arg1[1] = Local0

	// Design Capacity of Warning
	Local2 = Local0 * DWRN / 100
	Arg1[5] = Local2

	// Design Capacity of Low
	Local2 = Local0 * DLOW / 100
	Arg1[6] = Local2

	// Get battery info from mainboard
	Arg1[9] = BRSX (1)
	Arg1[10] = BRSX (2)
	Arg1[12] = BRSX (3)

	Release (^BATM)
	Return (Arg1)
}

// _BIX implementation.
//   Arg0 = battery index
//   Arg1 = PBIX
Method (BBIX, 2, Serialized)
{
	If (Acquire (^BATM, 1000)) {
		Return (Arg1)
	}

	If (BTSW (Arg0)) {
		Release (^BATM)
		Return (Arg1)
	}
	// Last Full Charge Capacity
	Arg1[3] = BTDF

	// Design Voltage
	Arg1[5] = BTDV

	// Design Capacity
	Local0 = BTDA
	Arg1[2] = Local0

	// Design Capacity of Warning
	Local2 = Local0 * DWRN / 100
	Arg1[6] = Local2

	// Design Capacity of Low
	Local2 = Local0 * DLOW / 100
	Arg1[7] = Local2

	// Cycle Count
	Arg1[8] = BTCC

	// Get battery info from mainboard
	Arg1[16] = BRSX (1)
	Arg1[17] = BRSX (2)
	Arg1[19] = BRSX (3)

	Release (^BATM)
	Return (Arg1)
}

// _BST implementation.
//   Arg0 = battery index
//   Arg1 = PBST
//   Arg2 = BSTP
//   Arg3 = BFWK
Method (BBST, 4, Serialized)
{
	If (Acquire (^BATM, 1000)) {
		Return (Arg1)
	}

	If (BTSW (Arg0)) {
		Release (^BATM)
		Return (Arg1)
	}
	//
	// 0: BATTERY STATE
	//
	// bit 0 = discharging
	// bit 1 = charging
	// bit 2 = critical level
	//
	Local1 = 0

	// Check if AC is present
	If (ACEX) {
		If (BFCG) {
			Local1 = 0x02
		} ElseIf (BFDC) {
			Local1 = 0x01
		}
	} Else {
		// Always discharging when on battery power
		Local1 = 0x01
	}

	// Check for critical battery level
	If (BFCR) {
		Local1 |= 4
	}
	Arg1[0] = Local1

	// Notify if battery state has changed since last time
	If (Local1 != DeRefOf (Arg2)) {
		Arg2 = Local1
		If (Arg0 == 0) {
			Notify (BAT0, 0x80)
		}
#ifdef EC_ENABLE_SECOND_BATTERY_DEVICE
		Else {
			Notify (BAT1, 0x80)
		}
#endif
	}

	//
	// 1: BATTERY PRESENT RATE
	//
	Arg1[1] = BTPR

	//
	// 2: BATTERY REMAINING CAPACITY
	//
	Local1 = BTRA
	If (Arg3 && ACEX && !(BFDC && BFCG)) {
		// On AC power and battery is neither charging
		// nor discharging.  Linux expects a full battery
		// to report same capacity as last full charge.
		// https://bugzilla.kernel.org/show_bug.cgi?id=12632
		Local2 = BTDF

		// See if within ~6% of full
		Local3 = Local2 >> 4
		If (Local1 > Local2 - Local3 && Local1 < Local2 + Local3)
		{
			Local1 = Local2
		}
	}
	Arg1[2] = Local1

	//
	// 3: BATTERY PRESENT VOLTAGE
	//
	Arg1[3] = BTVO

	Release (^BATM)
	Return (Arg1)
}

Device (BAT0)
{
	Name (_HID, EISAID ("PNP0C0A"))
	Name (_UID, 1)
	Name (_PCL, Package () { \_SB })

	Name (PBIF, Package () {
		0x00000001,  // 0x00: Power Unit: mAh
		0xFFFFFFFF,  // 0x01: Design Capacity
		0xFFFFFFFF,  // 0x02: Last Full Charge Capacity
		0x00000001,  // 0x03: Battery Technology: Rechargeable
		0xFFFFFFFF,  // 0x04: Design Voltage
		0x00000003,  // 0x05: Design Capacity of Warning
		0xFFFFFFFF,  // 0x06: Design Capacity of Low
		0x00000001,  // 0x07: Capacity Granularity 1
		0x00000001,  // 0x08: Capacity Granularity 2
		"",          // 0x09: Model Number
		"",          // 0x0a: Serial Number
		"LION",      // 0x0b: Battery Type
		""           // 0x0c: OEM Information
	})

	Name (PBIX, Package () {
		0x00000000,  // 0x00: Revision
		0x00000001,  // 0x01: Power Unit: mAh
		0xFFFFFFFF,  // 0x02: Design Capacity
		0xFFFFFFFF,  // 0x03: Last Full Charge Capacity
		0x00000001,  // 0x04: Battery Technology: Rechargeable
		0xFFFFFFFF,  // 0x05: Design Voltage
		0x00000003,  // 0x06: Design Capacity of Warning
		0xFFFFFFFF,  // 0x07: Design Capacity of Low
		0x00000000,  // 0x08: Cycle Count
		0x00018000,  // 0x09: Measurement Accuracy (98.3%?)
		0x000001F4,  // 0x0a: Max Sampling Time (500ms)
		0x0000000a,  // 0x0b: Min Sampling Time (10ms)
		0xFFFFFFFF,  // 0x0c: Max Averaging Interval
		0xFFFFFFFF,  // 0x0d: Min Averaging Interval
		0x00000001,  // 0x0e: Capacity Granularity 1
		0x00000001,  // 0x0f: Capacity Granularity 2
		"",          // 0x10 Model Number
		"",          // 0x11: Serial Number
		"LION",      // 0x12: Battery Type
		""           // 0x13: OEM Information
	})

	Name (PBST, Package () {
		0x00000000,  // 0x00: Battery State
		0xFFFFFFFF,  // 0x01: Battery Present Rate
		0xFFFFFFFF,  // 0x02: Battery Remaining Capacity
		0xFFFFFFFF,  // 0x03: Battery Present Voltage
	})
	Name (BSTP, 0)

	// Workaround for full battery status, disabled by default
	Name (BFWK, 0)

	// Method to enable full battery workaround
	Method (BFWE)
	{
		BFWK = 1
	}

	// Method to disable full battery workaround
	Method (BFWD)
	{
		BFWK = 0
	}

	Method (_STA, 0, Serialized)
	{
		Return (BSTA (0))
	}

	Method (_BIF, 0, Serialized)
	{
		Return (BBIF (0, PBIF))
	}

	Method (_BIX, 0, Serialized)
	{
		Return (BBIX (0, PBIX))
	}

	Method (_BST, 0, Serialized)
	{
		Return (BBST (0, PBST, RefOf (BSTP), BFWK))
	}
}

#ifdef EC_ENABLE_SECOND_BATTERY_DEVICE
Device (BAT1)
{
	Name (_HID, EISAID ("PNP0C0A"))
	Name (_UID, 1)
	Name (_PCL, Package () { \_SB })

	Name (PBIF, Package () {
		0x00000001,  // 0x00: Power Unit: mAh
		0xFFFFFFFF,  // 0x01: Design Capacity
		0xFFFFFFFF,  // 0x02: Last Full Charge Capacity
		0x00000001,  // 0x03: Battery Technology: Rechargeable
		0xFFFFFFFF,  // 0x04: Design Voltage
		0x00000003,  // 0x05: Design Capacity of Warning
		0xFFFFFFFF,  // 0x06: Design Capacity of Low
		0x00000001,  // 0x07: Capacity Granularity 1
		0x00000001,  // 0x08: Capacity Granularity 2
		"",          // 0x09: Model Number
		"",          // 0x0a: Serial Number
		"LION",      // 0x0b: Battery Type
		""           // 0x0c: OEM Information
	})

	Name (PBIX, Package () {
		0x00000000,  // 0x00: Revision
		0x00000001,  // 0x01: Power Unit: mAh
		0xFFFFFFFF,  // 0x02: Design Capacity
		0xFFFFFFFF,  // 0x03: Last Full Charge Capacity
		0x00000001,  // 0x04: Battery Technology: Rechargeable
		0xFFFFFFFF,  // 0x05: Design Voltage
		0x00000003,  // 0x06: Design Capacity of Warning
		0xFFFFFFFF,  // 0x07: Design Capacity of Low
		0x00000000,  // 0x08: Cycle Count
		0x00018000,  // 0x09: Measurement Accuracy (98.3%?)
		0x000001F4,  // 0x0a: Max Sampling Time (500ms)
		0x0000000a,  // 0x0b: Min Sampling Time (10ms)
		0xFFFFFFFF,  // 0x0c: Max Averaging Interval
		0xFFFFFFFF,  // 0x0d: Min Averaging Interval
		0x00000001,  // 0x0e: Capacity Granularity 1
		0x00000001,  // 0x0f: Capacity Granularity 2
		"",          // 0x10 Model Number
		"",          // 0x11: Serial Number
		"LION",      // 0x12: Battery Type
		""           // 0x13: OEM Information
	})

	Name (PBST, Package () {
		0x00000000,  // 0x00: Battery State
		0xFFFFFFFF,  // 0x01: Battery Present Rate
		0xFFFFFFFF,  // 0x02: Battery Remaining Capacity
		0xFFFFFFFF,  // 0x03: Battery Present Voltage
	})
	Name (BSTP, 0)

	// Workaround for full battery status, disabled by default
	Name (BFWK, 0)

	// Method to enable full battery workaround
	Method (BFWE)
	{
		BFWK = 1
	}

	// Method to disable full battery workaround
	Method (BFWD)
	{
		BFWK = 0
	}

	Method (_STA, 0, Serialized)
	{
		Return (BSTA (1))
	}

	Method (_BIF, 0, Serialized)
	{
		Return (BBIF (1, PBIF))
	}

	Method (_BIX, 0, Serialized)
	{
		Return (BBIX (1, PBIX))
	}

	Method (_BST, 0, Serialized)
	{
		Return (BBST (1, PBST, RefOf (BSTP), BFWK))
	}
}
#endif