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 /drivers | |
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/power/nvec_battery.c | 172 |
1 files changed, 135 insertions, 37 deletions
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); |