diff options
author | Sachin Nikam <snikam@nvidia.com> | 2010-03-19 12:39:06 +0530 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-03-29 08:41:34 -0800 |
commit | a3644ba3a01c41f789432bbb75c9dbba004d3664 (patch) | |
tree | 4c7bbb3610e77145157b66f75548d49b71b27598 | |
parent | 5054b24952cdcef10819fe6137de46450d440bbe (diff) |
nvec_battery:registering battery as wakeup source and battery events.
1. Making Battery and AC present as a wakeup source
2. Registering battery events:present, charging, remaining capacity
3. Handling battery odm flags and events in nvec_battery.c
Change-Id: I814960ab5f065e6aaad72ea1c403ad9c8d6a1af8
Reviewed-on: http://git-master/r/907
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
Tested-by: Sachin Nikam <snikam@nvidia.com>
Reviewed-by: Gary King <gking@nvidia.com>
-rw-r--r-- | arch/arm/mach-tegra/include/nvodm_battery.h | 54 | ||||
-rw-r--r-- | arch/arm/mach-tegra/odm_kit/platform/battery/nvodm_battery.c | 226 | ||||
-rw-r--r-- | arch/arm/mach-tegra/odm_kit/platform/battery/nvodm_battery_int.h | 36 | ||||
-rw-r--r-- | drivers/power/nvec_battery.c | 172 |
4 files changed, 356 insertions, 132 deletions
diff --git a/arch/arm/mach-tegra/include/nvodm_battery.h b/arch/arm/mach-tegra/include/nvodm_battery.h index ae4567169b05..4dba0edc1c48 100644 --- a/arch/arm/mach-tegra/include/nvodm_battery.h +++ b/arch/arm/mach-tegra/include/nvodm_battery.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 NVIDIA Corporation. + * Copyright (c) 2009-2010 NVIDIA Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,8 +35,12 @@ * <b>NVIDIA Tegra ODM Kit: * Battery Interface</b> * - * @b Description: Defines the ODM adaptation interface for battery. - * + * @b Description: Defines the ODM adaptation interface for + * Embedded Controller (EC) based battery interface. + * Note that this doesn't use PMU interface. + * EC Interface is used to get battery and power supply + * information and configure for events. + * Battery charging is taken care by EC firmware itself. */ #ifndef INCLUDED_NVODM_BATTERY_H @@ -82,20 +86,27 @@ typedef enum }NvOdmBatteryAcLineStatus; /** - * Defines the Battery events. + * Defines the battery events. */ typedef enum { - /// Specifies Battery Present State. - NvOdmBatteryEventType_Present, + /// Indicates battery present state. + NvOdmBatteryEventType_Present = 0x01, + + /// Indicates idle state. + NvOdmBatteryEventType_Idle = 0x02, + + /// Indicates charging state. + NvOdmBatteryEventType_Charging = 0x04, + + /// Indicates disharging state. + NvOdmBatteryEventType_Disharging = 0x08, - /// Specifies Charging State. - NvOdmBatteryEventType_Charging, + /// Indicates remaining capacity alarm set. + NvOdmBatteryEventType_RemainingCapacityAlarm = 0x10, - /// Specifies Remaining Capacity Alarm. - NvOdmBatteryEventType_RemainingCapacityAlarm, + NvOdmBatteryEventType_Num = 0x20, - NvOdmBatteryEventType_Num, /// Ignore -- Forces compilers to make 32-bit enums. NvOdmBatteryEventType_Force32 = 0x7FFFFFFF }NvOdmBatteryEventType; @@ -107,6 +118,9 @@ typedef enum #define NVODM_BATTERY_STATUS_LOW 0x02 #define NVODM_BATTERY_STATUS_CRITICAL 0x04 #define NVODM_BATTERY_STATUS_CHARGING 0x08 +#define NVODM_BATTERY_STATUS_DISCHARGING 0x10 +#define NVODM_BATTERY_STATUS_IDLE 0x20 +#define NVODM_BATTERY_STATUS_VERY_CRITICAL 0x40 #define NVODM_BATTERY_STATUS_NO_BATTERY 0x80 #define NVODM_BATTERY_STATUS_UNKNOWN 0xFF @@ -162,13 +176,13 @@ typedef struct NvOdmBatteryDataRec /// Specifies battery temperature. NvU32 BatteryTemperature; - /// Specifies battery Remaining Capacity. + /// Specifies battery remaining capacity. NvU32 BatteryRemainingCapacity; - /// Specifies battery Last Charge Full Capacity. + /// Specifies battery last charge full capacity. NvU32 BatteryLastChargeFullCapacity; - /// Specifies battery Critical Capacity. + /// Specifies battery critical capacity. NvU32 BatteryCriticalCapacity; }NvOdmBatteryData; @@ -205,7 +219,7 @@ typedef enum * Opens the handle for battery ODM. * * @param hDevice A pointer to the handle to the battery ODM. - * @param hOdmSemaphore Battery events signals this registered semaphore. + * @param hOdmSemaphore Battery events signal this registered semaphore. * Can Pass NULL if events are not needed by client. * @return NV_TRUE if successful, or NV_FALSE otherwise. */ @@ -296,7 +310,7 @@ void NvOdmBatteryGetBatteryChemistry( * Gets the battery event. * * @param hDevice A handle to the EC. - * @param pBatteryEvent Battery events + * @param pBatteryEvent A pointer to the battery events. * */ void NvOdmBatteryGetEvent( @@ -305,11 +319,11 @@ void NvOdmBatteryGetEvent( /** - * Gets the Battery Manufacturer. + * Gets the battery manufacturer. * * @param hDevice [IN] A handle to the EC. * @param BatteryInst [IN] The battery type. - * @param pBatteryManufacturer [OUT] A pointer to the battery Manufacturer + * @param pBatteryManufacturer [OUT] A pointer to the battery manufacturer. */ NvBool NvOdmBatteryGetManufacturer( NvOdmBatteryDeviceHandle hDevice, @@ -317,11 +331,11 @@ NvBool NvOdmBatteryGetManufacturer( NvU8 *pBatteryManufacturer); /** - * Gets the Battery Model. + * Gets the battery model. * * @param hDevice [IN] A handle to the EC. * @param BatteryInst [IN] The battery type. - * @param pBatteryModel [OUT] A pointer to the battery model + * @param pBatteryModel [OUT] A pointer to the battery model. */ NvBool NvOdmBatteryGetModel( NvOdmBatteryDeviceHandle hDevice, diff --git a/arch/arm/mach-tegra/odm_kit/platform/battery/nvodm_battery.c b/arch/arm/mach-tegra/odm_kit/platform/battery/nvodm_battery.c index 14908b21cf91..b8919573ddeb 100644 --- a/arch/arm/mach-tegra/odm_kit/platform/battery/nvodm_battery.c +++ b/arch/arm/mach-tegra/odm_kit/platform/battery/nvodm_battery.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 NVIDIA Corporation. + * Copyright (c) 2009-2010 NVIDIA Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,6 +48,10 @@ */ #define BATTERY_EXTRA_INFO 0 +/* Enable to wakeup the AP from suspend */ +#define NVODM_WAKEUP_FROM_BATTERY_EVENT 1 +#define NVODM_WAKEUP_FROM_AC_EVENT 1 + NvBool NvOdmBatteryPrivGetSlotStatusAndCapacityGuage( NvOdmBatteryDevice *pBattContext, NvOdmBatteryInstance BatteryInst, @@ -144,13 +148,16 @@ static void NvOdmBatteryEventHandler(void *args) NvOdmBatteryDevice *pBattContext = args; NvError NvStatus = NvError_Success; NvEcEvent EcEvent = {0}; + NvU8 BattEvent = 0, ChargingState = 0; for (;;) { NvOdmOsSemaphoreWait(pBattContext->hBattEventSem); - NVODMBATTERY_PRINTF(("NvOdmBatteryEventHandler:hBattEventSem \ - signaled\n")); + if (pBattContext->ExitThread == NV_TRUE) + break; + + NVODMBATTERY_PRINTF(("NvOdmBatteryEventHandler:hBattEventSem signaled\n")); if (pBattContext->hEcEventReg) { @@ -168,11 +175,33 @@ static void NvOdmBatteryEventHandler(void *args) continue; } - pBattContext->BatteryEvent = EcEvent.Payload[0]; - - /* Signal the Battery Client for arrival of the event */ - if (pBattContext->hClientBattEventSem) - NvOdmOsSemaphoreSignal(pBattContext->hClientBattEventSem); + /* EcEvent.Payload[0] is Slot number */ + + /* EcEvent.Payload[1] has 4 lsb bits for battery events */ + BattEvent = EcEvent.Payload[1] & NVODM_BATTERY_EVENT_MASK; + + pBattContext->BatteryEvent = 0; + /* Read the Battery Slot status to set the proper event */ + if (BattEvent & NVODM_BATTERY_PRESENT_IN_SLOT) + pBattContext->BatteryEvent |= NvOdmBatteryEventType_Present; + + ChargingState = BattEvent >> NVODM_BATTERY_CHARGING_STATE_SHIFT; + ChargingState &= NVODM_BATTERY_CHARGING_STATE_MASK; + if (ChargingState == NVODM_BATTERY_CHARGING_STATE_IDLE) + pBattContext->BatteryEvent |= NvOdmBatteryEventType_Idle; + else if (ChargingState == NVODM_BATTERY_CHARGING_STATE_CHARGING) + pBattContext->BatteryEvent |= NvOdmBatteryEventType_Charging; + else if (ChargingState == NVODM_BATTERY_CHARGING_STATE_DISCHARGING) + pBattContext->BatteryEvent |= NvOdmBatteryEventType_Disharging; + + ChargingState = BattEvent >> NVODM_BATTERY_REM_CAP_ALARM_SHIFT; + if (ChargingState == NVODM_BATTERY_REM_CAP_ALARM_IS_SET) + pBattContext->BatteryEvent |= NvOdmBatteryEventType_RemainingCapacityAlarm; + + /* Signal the Battery Client for arrival of the valid event */ + if ((pBattContext->hClientBattEventSem != 0) && + (pBattContext->BatteryEvent != 0)) + NvOdmOsSemaphoreSignal(pBattContext->hClientBattEventSem); } } } @@ -895,6 +924,8 @@ NvBool NvOdmBatteryDeviceOpen(NvOdmBatteryDeviceHandle *hDevice, NvError NvStatus = NvError_Success; NvEcEventType EventTypes[] = {NvEcEventType_Battery}; NvS32 MajorVersion = 0, MinorVersion = 0; + NvEcRequest EcRequest = {0}; + NvEcResponse EcResponse = {0}; NVODMBATTERY_PRINTF(("[ENTER] NvOdmBatteryDeviceOpen. \n")); @@ -903,7 +934,7 @@ NvBool NvOdmBatteryDeviceOpen(NvOdmBatteryDeviceHandle *hDevice, if (!pBattContext) { NVODMBATTERY_PRINTF(("NvOdmOsAlloc failed to allocate pBattContext.")); - goto Cleanup; + return NV_FALSE; } NvOdmOsMemset(pBattContext, 0, sizeof(NvOdmBatteryDevice)); @@ -916,6 +947,27 @@ NvBool NvOdmBatteryDeviceOpen(NvOdmBatteryDeviceHandle *hDevice, goto Cleanup; } + /* Get the EC Firmware version */ + NvStatus = NvOdmBatteryPrivEcGetFirmwareVersion(pBattContext, + &MajorVersion, + &MinorVersion); + if (NvStatus != NvError_Success) + { + goto Cleanup; + } + + /* Minor Version 2 is R01 */ + if (MinorVersion == NVODM_BATTERY_EC_FIRMWARE_VER_R01) + { + pBattContext->FirmwareVersionR01 = NV_TRUE; + NVODMBATTERY_PRINTF(("EC Firmware Version is R01\n")); + } + else + { + pBattContext->FirmwareVersionR01 = NV_FALSE; + NVODMBATTERY_PRINTF(("EC Firmware Version is beyond R01\n")); + } + if (hOdmSemaphore != NULL && *hOdmSemaphore != NULL) { pBattContext->hClientBattEventSem = *hOdmSemaphore; @@ -927,6 +979,77 @@ NvBool NvOdmBatteryDeviceOpen(NvOdmBatteryDeviceHandle *hDevice, goto Cleanup; } + /* Thread to handle Battery events */ + pBattContext->hBattEventThread = NvOdmOsThreadCreate( + (NvOdmOsThreadFunction)NvOdmBatteryEventHandler, + (void *)pBattContext); + if (!pBattContext->hBattEventThread) + { + goto Cleanup; + } + + if (MinorVersion >= NVODM_BATTERY_EC_FIRMWARE_VER_R04) + { +#if NVODM_WAKEUP_FROM_BATTERY_EVENT + /* Configure the Batter present event as a wakeup */ + EcRequest.PacketType = NvEcPacketType_Request; + EcRequest.RequestType = NvEcRequestResponseType_Battery; + EcRequest.RequestSubtype = (NvEcRequestResponseSubtype) + NvEcBatterySubtype_ConfigureWake; + EcRequest.NumPayloadBytes = 2; + EcRequest.Payload[0] = NVEC_BATTERY_REPORT_ENABLE_0_ACTION_ENABLE; + EcRequest.Payload[1] = NVODM_BATTERY_SET_PRESENT_EVENT; + + NvStatus = NvEcSendRequest(pBattContext->hEc, &EcRequest, &EcResponse, + sizeof(EcRequest), sizeof(EcResponse)); + if (NvStatus != NvSuccess) + goto Cleanup; + + if (EcResponse.Status != NvEcStatus_Success) + goto Cleanup; +#endif + +#if NVODM_WAKEUP_FROM_AC_EVENT + /* Configure the AC present event as a wakeup */ + EcRequest.PacketType = NvEcPacketType_Request; + EcRequest.RequestType = NvEcRequestResponseType_System; + EcRequest.RequestSubtype = (NvEcRequestResponseSubtype) + NvEcSystemSubtype_ConfigureWake; + EcRequest.NumPayloadBytes = 2; + EcRequest.Payload[0] = NVEC_SYSTEM_REPORT_ENABLE_0_ACTION_ENABLE; + EcRequest.Payload[1] = NVEC_SYSTEM_STATE1_0_AC_PRESENT; + + NvStatus = NvEcSendRequest(pBattContext->hEc, &EcRequest, &EcResponse, + sizeof(EcRequest), sizeof(EcResponse)); + if (NvStatus != NvSuccess) + goto Cleanup; + + if (EcResponse.Status != NvEcStatus_Success) + goto Cleanup; +#endif + /* Configure the Battery events */ + EcRequest.PacketType = NvEcPacketType_Request; + EcRequest.RequestType = NvEcRequestResponseType_Battery; + EcRequest.RequestSubtype = (NvEcRequestResponseSubtype) + NvEcBatterySubtype_ConfigureEventReporting; + EcRequest.NumPayloadBytes = 2; + EcRequest.Payload[0] = NVEC_BATTERY_REPORT_ENABLE_0_ACTION_ENABLE; + /* Bit 0 = Present State event */ + /* Bit 1 = Charging State event */ + /* Bit 2 = Remaining Capacity Alaram event */ + EcRequest.Payload[1] = NVODM_BATTERY_SET_PRESENT_EVENT | + NVODM_BATTERY_SET_CHARGING_EVENT| + NVODM_BATTERY_SET_REM_CAP_ALARM_EVENT; + + NvStatus = NvEcSendRequest(pBattContext->hEc, &EcRequest, &EcResponse, + sizeof(EcRequest), sizeof(EcResponse)); + if (NvStatus != NvSuccess) + goto Cleanup; + + if (EcResponse.Status != NvEcStatus_Success) + goto Cleanup; + } + /* Register for Battery events */ NvStatus = NvEcRegisterForEvents( pBattContext->hEc, @@ -940,35 +1063,6 @@ NvBool NvOdmBatteryDeviceOpen(NvOdmBatteryDeviceHandle *hDevice, { goto Cleanup; } - - /* Thread to handle Battery events */ - pBattContext->hBattEventThread = \ - NvOdmOsThreadCreate((NvOdmOsThreadFunction)NvOdmBatteryEventHandler, - (void *)pBattContext); - if (!pBattContext->hBattEventThread) - { - goto Cleanup; - } - } - - /* Get the EC Firmware version */ - NvStatus = NvOdmBatteryPrivEcGetFirmwareVersion(pBattContext, &MajorVersion, - &MinorVersion); - if (NvStatus != NvError_Success) - { - goto Cleanup; - } - - /* Minor Version 2 is R01 */ - if (MinorVersion == 2) - { - pBattContext->FirmwareVersionR01 = NV_TRUE; - NVODMBATTERY_PRINTF(("EC Firmware Version is R01\n")); - } - else - { - pBattContext->FirmwareVersionR01 = NV_FALSE; - NVODMBATTERY_PRINTF(("EC Firmware Version is beyond R01\n")); } *hDevice = pBattContext; @@ -976,27 +1070,7 @@ NvBool NvOdmBatteryDeviceOpen(NvOdmBatteryDeviceHandle *hDevice, return NV_TRUE; Cleanup: - - if (pBattContext->hBattEventSem) - { - NvOdmOsSemaphoreDestroy(pBattContext->hBattEventSem); - pBattContext->hBattEventSem = NULL; - } - - if (pBattContext->hEc) - { - if (pBattContext->hEcEventReg) - { - NvEcUnregisterForEvents(pBattContext->hEcEventReg); - pBattContext->hEcEventReg = NULL; - } - - NvEcClose(pBattContext->hEc); - pBattContext->hEc = NULL; - } - - if (pBattContext) - NvOdmOsFree(pBattContext); + NvOdmBatteryDeviceClose(pBattContext); return NV_FALSE; } @@ -1005,7 +1079,7 @@ Cleanup: * Closes the battery device * * @param hDevice [IN] handle to Battery Device. - * + * * @return void. */ void NvOdmBatteryDeviceClose(NvOdmBatteryDeviceHandle hDevice) @@ -1016,10 +1090,18 @@ void NvOdmBatteryDeviceClose(NvOdmBatteryDeviceHandle hDevice) if (pBattContext->hBattEventSem) { + pBattContext->ExitThread = NV_TRUE; + NvOdmOsSemaphoreSignal(pBattContext->hBattEventSem); NvOdmOsSemaphoreDestroy(pBattContext->hBattEventSem); pBattContext->hBattEventSem = NULL; } + if (pBattContext->hBattEventThread) + { + NvOdmOsThreadJoin(pBattContext->hBattEventThread); + pBattContext->hBattEventThread = NULL; + } + if (pBattContext->hEc) { if (pBattContext->hEcEventReg) @@ -1028,12 +1110,6 @@ void NvOdmBatteryDeviceClose(NvOdmBatteryDeviceHandle hDevice) pBattContext->hEcEventReg = NULL; } - if (pBattContext->hBattEventThread) - { - NvOdmOsThreadJoin(pBattContext->hBattEventThread); - pBattContext->hBattEventThread = NULL; - } - NvEcClose(pBattContext->hEc); pBattContext->hEc = NULL; } @@ -1166,10 +1242,14 @@ NvBool NvOdmBatteryGetBatteryStatus( BattPresentState = BatterySlotStatus & NVODM_BATTERY_PRESENT_IN_SLOT; if (BattPresentState == NVODM_BATTERY_PRESENT_IN_SLOT) { - BattChargingState = \ - BatterySlotStatus >> NVODM_BATTERY_CHARGING_STATE_SHIFT; + BattChargingState = BatterySlotStatus >> NVODM_BATTERY_CHARGING_STATE_SHIFT; + BattChargingState &= NVODM_BATTERY_CHARGING_STATE_MASK; if (BattChargingState == NVODM_BATTERY_CHARGING_STATE_CHARGING) - *pStatus |= NVODM_BATTERY_STATUS_CHARGING; + *pStatus |= NVODM_BATTERY_STATUS_CHARGING; + else if (BattChargingState == NVODM_BATTERY_CHARGING_STATE_DISCHARGING) + *pStatus |= NVODM_BATTERY_STATUS_DISCHARGING; + else if (BattChargingState == NVODM_BATTERY_CHARGING_STATE_IDLE) + *pStatus |= NVODM_BATTERY_STATUS_IDLE; } else { @@ -1192,7 +1272,15 @@ NvBool NvOdmBatteryGetBatteryStatus( else if (BatteryVoltage >= NVODM_BATTERY_LOW_VOLTAGE_MV) *pStatus |= NVODM_BATTERY_STATUS_LOW; else + { *pStatus |= NVODM_BATTERY_STATUS_CRITICAL; + /* + * Additional flag which tells battery is very critical + * and needs system shutdown. + */ + if (BatteryVoltage <= NVODM_BATTERY_CRITICAL_VOLTAGE_MV) + *pStatus |= NVODM_BATTERY_STATUS_VERY_CRITICAL; + } } else { diff --git a/arch/arm/mach-tegra/odm_kit/platform/battery/nvodm_battery_int.h b/arch/arm/mach-tegra/odm_kit/platform/battery/nvodm_battery_int.h index 88f7894a1a64..39fcb7a8eb3f 100644 --- a/arch/arm/mach-tegra/odm_kit/platform/battery/nvodm_battery_int.h +++ b/arch/arm/mach-tegra/odm_kit/platform/battery/nvodm_battery_int.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 NVIDIA Corporation. + * Copyright (c) 2009-2010 NVIDIA Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -69,11 +69,17 @@ extern "C" #define NVODM_BATTERY_PRESENT_IN_SLOT 0x01 #define NVODM_BATTERY_CHARGING_STATE_SHIFT 1 +#define NVODM_BATTERY_CHARGING_STATE_MASK 0x03 + /* Battery Slot Status : Bits 1-2 = Charging state */ #define NVODM_BATTERY_CHARGING_STATE_IDLE 0x00 #define NVODM_BATTERY_CHARGING_STATE_CHARGING 0x01 -#define NVODM_BATTERY_CHARGING_STATE_DISCHARGING 0x10 -#define NVODM_BATTERY_CHARGING_STATE_RESERVED 0x11 +#define NVODM_BATTERY_CHARGING_STATE_DISCHARGING 0x02 +#define NVODM_BATTERY_CHARGING_STATE_RESERVED 0x03 + +/* Remaining capacity alarm bit is 3rd in slot status */ +#define NVODM_BATTERY_REM_CAP_ALARM_SHIFT 3 +#define NVODM_BATTERY_REM_CAP_ALARM_IS_SET 1 /* Response System Status : Data Byte 3 System State Bits 7-0 */ #define NVODM_BATTERY_SYSTEM_STATE_DATA1 0 @@ -87,9 +93,26 @@ extern "C" /* Threshold for battery status.*/ #define NVODM_BATTERY_FULL_VOLTAGE_MV 12600 -#define NVODM_BATTERY_HIGH_VOLTAGE_MV 10000 -#define NVODM_BATTERY_LOW_VOLTAGE_MV 9000 -#define NVODM_BATTERY_CRITICAL_VOLTAGE_MV 8500 +#define NVODM_BATTERY_HIGH_VOLTAGE_MV 10200 +#define NVODM_BATTERY_LOW_VOLTAGE_MV 9400 +#define NVODM_BATTERY_CRITICAL_VOLTAGE_MV 8800 + +#define NVODM_BATTERY_EC_FIRMWARE_VER_R01 2 +#define NVODM_BATTERY_EC_FIRMWARE_VER_R04 8 + +/* Bit 0 = Present State event */ +/* Bit 1 = Charging State event */ +/* Bit 2 = Remaining Capacity Alaram event */ +#define NVODM_BATTERY_SET_PRESENT_EVENT 0x01 +#define NVODM_BATTERY_SET_CHARGING_EVENT 0x02 +#define NVODM_BATTERY_SET_REM_CAP_ALARM_EVENT 0x04 + +/* + * Bit 0 => 0=Not Present, 1=Present + * Bit 1:2 => 00=Idle, 01=Charging,10=Discharging, 11=Reserved + * Bit 3 => 1=Remaining Capacity Alaram set + */ +#define NVODM_BATTERY_EVENT_MASK 0x0F typedef enum { @@ -112,6 +135,7 @@ typedef struct NvOdmBatteryDeviceRec NvU8 BatteryEvent; NvU8 NumBatterySlots; NvBool FirmwareVersionR01; + NvBool ExitThread; } NvOdmBatteryDevice; #if defined(__cplusplus) diff --git a/drivers/power/nvec_battery.c b/drivers/power/nvec_battery.c index ff1ff6220dcd..42de876b9e63 100644 --- a/drivers/power/nvec_battery.c +++ b/drivers/power/nvec_battery.c @@ -30,6 +30,7 @@ #include <linux/power_supply.h> #include <linux/wakelock.h> #include <linux/tegra_devices.h> +#include <linux/pm.h> #include "nvcommon.h" #include "nvos.h" @@ -40,8 +41,6 @@ /* This defines the manufacturer name and model name length */ #define BATTERY_INFO_NAME_LEN 30 -#define GET_CHARGER_STATUS 1 - #define NVBATTERY_POLLING_INTERVAL 30000 /* 30 Seconds */ typedef enum @@ -74,17 +73,17 @@ static enum power_supply_property tegra_battery_properties[] = { POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_EMPTY, POWER_SUPPLY_PROP_TEMP, -// POWER_SUPPLY_PROP_MODEL_NAME, -// POWER_SUPPLY_PROP_MANUFACTURER, +/* POWER_SUPPLY_PROP_MODEL_NAME, */ +/* POWER_SUPPLY_PROP_MANUFACTURER, */ }; static enum power_supply_property tegra_power_properties[] = { - POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_ONLINE, }; static char *supply_list[] = { - "battery", + "battery", }; static int tegra_power_get_property(struct power_supply *psy, @@ -125,6 +124,8 @@ static struct power_supply tegra_power_supplies[] = { struct tegra_battery_dev { struct timer_list battery_poll_timer; NvOdmBatteryDeviceHandle hOdmBattDev; + NvOsSemaphoreHandle hOdmSemaphore; + NvOsThreadHandle hBattEventThread; NvU32 batt_id; NvU32 voltage; /* voltage */ NvU32 temp; /* Temperature */ @@ -141,6 +142,7 @@ struct tegra_battery_dev { NvU32 batt_status_poll_period; NvBool ac_status; NvBool present; + NvBool exitThread; }; static struct tegra_battery_dev *batt_dev; @@ -174,6 +176,42 @@ static struct device_attribute tegra_battery_attr = { .store = tegra_battery_store_property, }; +void NvBatteryEventHandlerThread(void) +{ + NvU8 BatteryState = 0, BatteryEvent = 0; + + for (;;) { + NvOsSemaphoreWait(batt_dev->hOdmSemaphore); + + if (batt_dev->exitThread) + break; + + NvOdmBatteryGetBatteryStatus(batt_dev->hOdmBattDev, + NvOdmBatteryInst_Main, + &BatteryState); + + NvOdmBatteryGetEvent(batt_dev->hOdmBattDev, &BatteryEvent); + + if ((BatteryState == NVODM_BATTERY_STATUS_UNKNOWN) || + (BatteryEvent == NvOdmBatteryEventType_Num)) { + /* Do nothing */ + } else { + if (BatteryEvent & NvOdmBatteryEventType_RemainingCapacityAlarm) { + if (BatteryState == (NVODM_BATTERY_STATUS_CRITICAL | + NVODM_BATTERY_STATUS_VERY_CRITICAL | + NVODM_BATTERY_STATUS_DISCHARGING)) { + /* device_power_down(PMSG_HIBERNATE); */ + } + } else { + /* Update the battery and power supply info for other events */ + power_supply_changed(&tegra_power_supplies[NvCharger_Type_Battery]); + power_supply_changed(&tegra_power_supplies[NvCharger_Type_USB]); + power_supply_changed(&tegra_power_supplies[NvCharger_Type_AC]); + } + } + } +} + static void tegra_get_battery_tech(int *val, NvOdmBatteryInstance inst) { NvOdmBatteryChemistry chemistry = NvOdmBatteryChemistry_Num; @@ -242,10 +280,11 @@ static void tegra_battery_convert(NvOdmBatteryData *data) static NvBool tegra_battery_data(NvOdmBatteryInstance NvBatteryInst) { NvOdmBatteryData data = {0}; + NvBool RetValue = NV_FALSE; - if (!NvOdmBatteryGetBatteryData(batt_dev->hOdmBattDev, + if (NvOdmBatteryGetBatteryData(batt_dev->hOdmBattDev, NvBatteryInst, &data)) - return NV_FALSE; + RetValue = NV_TRUE; tegra_battery_convert(&data); @@ -262,7 +301,7 @@ static NvBool tegra_battery_data(NvOdmBatteryInstance NvBatteryInst) batt_dev->capacity_remain = data.BatteryRemainingCapacity; } - return NV_TRUE; + return RetValue; } static int tegra_power_get_property(struct power_supply *psy, @@ -315,8 +354,6 @@ static int tegra_battery_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_STATUS: val->intval = POWER_SUPPLY_STATUS_UNKNOWN; - /* TODO:Get Charger status here */ -#if GET_CHARGER_STATUS if (!NvOdmBatteryGetBatteryStatus(batt_dev->hOdmBattDev, NvOdmBatteryInst_Main, &state)) return -ENODEV; @@ -330,18 +367,36 @@ static int tegra_battery_get_property(struct power_supply *psy, } else if (state & NVODM_BATTERY_STATUS_CHARGING) { batt_dev->present = NV_TRUE; val->intval = POWER_SUPPLY_STATUS_CHARGING; - /* TODO:Get Charger status here */ - } else if (state & NVODM_BATTERY_STATUS_HIGH) { + } else if (state & NVODM_BATTERY_STATUS_DISCHARGING) { batt_dev->present = NV_TRUE; - val->intval = POWER_SUPPLY_STATUS_FULL; - /* TODO:Get Charger status here */ - } else - val->intval = POWER_SUPPLY_STATUS_UNKNOWN; -#endif - /* Getting the battery info once here so for the other property - * requests there will not be lot of ec req */ - if (!tegra_battery_data(NvOdmBatteryInst_Main)) { - ; /* FIXME: return error? */ + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + } else if (state & NVODM_BATTERY_STATUS_IDLE) { + batt_dev->present = NV_TRUE; + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + } + + if (!batt_dev->present ) { + batt_dev->voltage = 0; + batt_dev->current_ma = 0; + batt_dev->current_avg = 0; + batt_dev->temp = 0; + batt_dev->percent_remain = 0; + batt_dev->lifetime = 0; + batt_dev->consumed = 0; + batt_dev->capacity = 0; + batt_dev->capacity_crit = 0; + batt_dev->capacity_remain = 0; + } + else { + /* + * Getting the battery info once here so for the other property + * requests there will not be lot of ec req + */ + if (tegra_battery_data(NvOdmBatteryInst_Main)) { + if (batt_dev->percent_remain == 100) { + val->intval = POWER_SUPPLY_STATUS_FULL; + } + } } break; @@ -350,7 +405,6 @@ static int tegra_battery_get_property(struct power_supply *psy, val->intval = POWER_SUPPLY_HEALTH_GOOD; else val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; - break; case POWER_SUPPLY_PROP_PRESENT: @@ -366,10 +420,13 @@ static int tegra_battery_get_property(struct power_supply *psy, batt_dev->present = NV_FALSE; val->intval = NV_FALSE; } + if (state & (NVODM_BATTERY_STATUS_HIGH | - NVODM_BATTERY_STATUS_LOW | - NVODM_BATTERY_STATUS_CRITICAL | - NVODM_BATTERY_STATUS_CHARGING)) { + NVODM_BATTERY_STATUS_LOW | + NVODM_BATTERY_STATUS_CRITICAL | + NVODM_BATTERY_STATUS_CHARGING | + NVODM_BATTERY_STATUS_DISCHARGING | + NVODM_BATTERY_STATUS_IDLE)) { batt_dev->present = NV_TRUE; val->intval = NV_TRUE; } @@ -450,6 +507,7 @@ static void tegra_battery_poll_timer_func(unsigned long unused) static int nvec_battery_probe(struct nvec_device *pdev) { int i, rc; + NvError ErrorStatus = NvSuccess; NvBool result = NV_FALSE; batt_dev = kzalloc(sizeof(struct tegra_battery_dev), GFP_KERNEL); @@ -458,12 +516,26 @@ static int nvec_battery_probe(struct nvec_device *pdev) return -ENOMEM; } - result = NvOdmBatteryDeviceOpen(&(batt_dev->hOdmBattDev), NULL); + ErrorStatus = NvOsSemaphoreCreate(&batt_dev->hOdmSemaphore, 0); + if (NvSuccess != ErrorStatus) { + pr_err("NvOsSemaphoreCreate Failed!\n"); + goto Cleanup; + } + + batt_dev->exitThread = NV_FALSE; + ErrorStatus = NvOsThreadCreate(NvBatteryEventHandlerThread, + batt_dev, + &(batt_dev->hBattEventThread)); + if (NvSuccess != ErrorStatus) { + pr_err("NvOsThreadCreate FAILED\n"); + goto Cleanup; + } + + result = NvOdmBatteryDeviceOpen(&(batt_dev->hOdmBattDev), + (NvOdmOsSemaphoreHandle *)&batt_dev->hOdmSemaphore); if (!result || !batt_dev->hOdmBattDev) { - kfree(batt_dev); - batt_dev = NULL; pr_err("NvOdmBatteryDeviceOpen FAILED\n"); - return -1; + goto Cleanup; } for (i = 0; i < ARRAY_SIZE(tegra_power_supplies); i++) { @@ -478,23 +550,38 @@ static int nvec_battery_probe(struct nvec_device *pdev) rc = device_create_file(&pdev->dev, &tegra_battery_attr); if (rc) { - NvOdmBatteryDeviceClose(batt_dev->hOdmBattDev); - batt_dev->hOdmBattDev = NULL; - for (i = 0; i < ARRAY_SIZE(tegra_power_supplies); i++) { power_supply_unregister(&tegra_power_supplies[i]); } del_timer_sync(&(batt_dev->battery_poll_timer)); - kfree(batt_dev); - batt_dev = NULL; - pr_err("nvec_battery_probe:device_create_file FAILED"); - return rc; + goto Cleanup; } return 0; + +Cleanup: + batt_dev->exitThread = NV_TRUE; + if (batt_dev->hOdmSemaphore) { + NvOsSemaphoreSignal(batt_dev->hOdmSemaphore); + NvOsSemaphoreDestroy(batt_dev->hOdmSemaphore); + batt_dev->hOdmSemaphore = NULL; + } + + if (batt_dev->hBattEventThread) { + NvOsThreadJoin(batt_dev->hBattEventThread); + } + + if (batt_dev->hOdmBattDev) { + NvOdmBatteryDeviceClose(batt_dev->hOdmBattDev); + batt_dev->hOdmBattDev = NULL; + } + + kfree(batt_dev); + batt_dev = NULL; + return -1; } static int nvec_battery_remove(struct nvec_device *pdev) @@ -502,6 +589,17 @@ static int nvec_battery_remove(struct nvec_device *pdev) unsigned int i = 0; if (batt_dev) { + batt_dev->exitThread = NV_TRUE; + if (batt_dev->hOdmSemaphore) { + NvOsSemaphoreSignal(batt_dev->hOdmSemaphore); + NvOsSemaphoreDestroy(batt_dev->hOdmSemaphore); + batt_dev->hOdmSemaphore = NULL; + } + + if (batt_dev->hBattEventThread) { + NvOsThreadJoin(batt_dev->hBattEventThread); + } + if (batt_dev->hOdmBattDev) { device_remove_file(&pdev->dev, &tegra_battery_attr); |