From: David Dajun Chen on
Dear sir/madam,

The attached is the POWER (Battery Charger) part of the device drivers newly developed for DA9052 Power Management IC from Dialog Semiconductor.

Should you have any queries or comments please feel free to contact me.

Regards

Dr. David Dajun Chen
Dialog Semiconductor Ltd.
Delta 200, Welton Road
Delta Business Park
Swindon
Wiltshire SN5 7XB
UK
Telephone: (+44) 01793-757714
Mobile:         (+44) 07917015477
Fax:               (+44) 01793-758000
===========================================================================

diff -Naur linux-2.6.33.2_bk/drivers/mfd/Kconfig linux-2.6.33.2_patch/drivers/mfd/Kconfig
--- linux-2.6.33.2_bk/drivers/mfd/Kconfig 2010-05-18 17:54:30.000000000 +0500
+++ linux-2.6.33.2_patch/drivers/mfd/Kconfig 2010-05-18 18:20:23.000000000 +0500
@@ -377,6 +377,14 @@
help
Say Y to enable the ADC driver for the DA9052 chip

+config DA9052_BAT_ENABLE
+ bool "Dialog Semiconductor DA9052 Battery Driver"
+ depends on MFD_DA9052
+ select DA9052_ADC_ENABLE
+ help
+ Depends on DA9052 ADC driver
+ Say Y to enable the BAT driver for the DA9052 chip
+
endmenu

menu "Multimedia Capabilities Port drivers"
diff -Naur linux-2.6.33.2_bk/drivers/power/da9052_bat.c linux-2.6.33.2_patch/drivers/power/da9052_bat.c
--- linux-2.6.33.2_bk/drivers/power/da9052_bat.c 1970-01-01 05:00:00.000000000 +0500
+++ linux-2.6.33.2_patch/drivers/power/da9052_bat.c 2010-05-18 18:20:23.000000000 +0500
@@ -0,0 +1,2633 @@
+/*
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * da9052_bat.c: BAT driver file for DA9052
+ *
+ * Authors:
+ *
+ * History:
+ *
+ * (08/05/2009): Draft version
+ * (19/05/2009): Unit tested code version
+ *
+ * (27/04/2010): Created initial draft for Linux community release
+ *
+ * Best Viewed with TabSize=8 and ColumnWidth=80
+ */
+
+/*--------------------------------------------------------------------------*/
+/* System wide include files */
+/*--------------------------------------------------------------------------*/
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/uaccess.h>
+#include <linux/jiffies.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <linux/freezer.h>
+
+/*--------------------------------------------------------------------------*/
+/* Module specific include files */
+/*--------------------------------------------------------------------------*/
+#include <linux/mfd/da9052/da9052_reg.h>
+#include <linux/mfd/da9052/da9052_lib.h>
+#include <linux/mfd/da9052/da9052_eh.h>
+#include <linux/mfd/da9052/da9052_bat.h>
+
+//void start_monitoring(struct work_struct *);
+/*--------------------------------------------------------------------------*/
+/* Local Type Definitions */
+/*--------------------------------------------------------------------------*/
+
+/*--------------------------------------------------------------------------*/
+/* Local Constant Definitions */
+/*--------------------------------------------------------------------------*/
+static const char __initdata banner[] = KERN_INFO "DA9052 BAT, (c) \
+2009 Dialog semiconductor Ltd.\n";
+/*--------------------------------------------------------------------------*/
+/* Local Macro Definitions */
+/*--------------------------------------------------------------------------*/
+
+/*--------------------------------------------------------------------------*/
+/* Global Variables */
+/*--------------------------------------------------------------------------*/
+
+/*Power Supply and Power supply info instance */
+struct power_supply psy;
+struct power_supply_info battery_info;
+
+/**
+* da9052_bat_get_property : Called by power supply to get the status of
+* the battery. It get the property of the battery
+* defined by the da902_bat_props array.
+*/
+static int da9052_bat_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val);
+
+/**
+ * da902_bat_props - Array that define the power supply properties supported
+ by DA9052_BAT Driver
+ */
+static enum power_supply_property da902_bat_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CAPACITY,
+ /* Not supported by Linux version 2.6.28
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+ */
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static u8 bat_device_open = 0;
+static s32 bat_major_number = 0;
+static struct platform_device *da9052_bat_platform_device;
+static struct fasync_struct *bat_fasync_queue;
+
+/* Create structure used throughout the BAT */
+static da9052_charger_device *chg_device;
+static da9052_bat_device bat_info;
+static da9052_bat_status bat_status;
+static da9052_bat_hysteresis bat_hysteresis;
+
+/* Create a handler for the scheduling start_monitoring function */
+s32 monitoring_thread_pid = 0;
+u8 monitoring_thread_state = ACTIVE;
+struct completion monitoring_thread_notifier;
+
+/* Lookup table for the battery capacity for all battery temperature */
+static u16 array_hys_batvoltage[2];
+static u16 bat_volt_arr[3];
+static u8 hys_flag = FALSE;
+
+/* Global varaiable to store the bat event and event notifier*/
+u8 user_space_chg_det_dcin;
+u8 user_space_chg_rem_dcin;
+u8 user_space_chg_det_vbus;
+u8 user_space_chg_rem_vbus;
+u8 user_space_chg_chgend;
+u8 montoring_func_reg;
+u32 bat_event;
+da9052_bat_event_regestration event_status;
+da9052_eh_nb vddlow_eh_data;
+da9052_eh_nb tbat_eh_data;
+da9052_eh_nb chgend_eh_data;
+da9052_eh_nb chgdet_dcin_eh_data;
+da9052_eh_nb chgrem_dcin_eh_data;
+da9052_eh_nb chgdet_vbus_eh_data;
+da9052_eh_nb chgrem_vbus_eh_data;
+
+u8 tbat_event_occur;
+/* Lock for battery event notifier to library */
+struct semaphore event_lock;
+
+/* instance to store the monitoring status */
+static monitoring_state monitoring_status;
+
+/* Workqueue for the charger update function. */
+void da9052_chager_status_update(void);
+/*--------------------------------------------------------------------------*/
+/* Local Functions */
+/*--------------------------------------------------------------------------*/
+
+/**
+ * da9052_battery_setup_psy : Called by init function. It initialise the
+ * power supply instance for DA9052_BAT.
+ *
+ * @param : void
+ * @return void
+ */
+static void da9052_battery_setup_psy(void)
+{
+ battery_info.name = DA9052_BAT_DEVICE_NAME;
+ battery_info.technology = BAT_TYPE;
+ battery_info.voltage_max_design = (chg_device->bat_target_voltage * 1000);
+ battery_info.voltage_min_design = (BAT_VOLT_CUTOFF * 1000);
+ battery_info.energy_full_design = BAT_CAPACITY_FULL;
+ battery_info.energy_empty_design = BAT_CAPACITY_LIMIT_LOW;
+ battery_info.use_for_apm = 1;
+
+ psy.name = DA9052_BAT_DEVICE_NAME;
+ psy.use_for_apm = 1;
+ psy.type = POWER_SUPPLY_TYPE_BATTERY;
+ psy.get_property = da9052_bat_get_property;
+
+ psy.properties = da902_bat_props;
+ psy.num_properties = ARRAY_SIZE(da902_bat_props);
+
+ DA9052_DEBUG("Array_Size = %d\n",psy.num_properties);
+};
+
+/**
+ * da9052_bat_get_property : Called by power supply to get the status of
+ * the battery. It get the property of the battery
+ * defined by the da902_bat_props array.
+ *
+ * @param : psy power supply structure pointer
+ * @param : psp power supply properties requested
+ * @param : val pointer to power_supply_propval in which
+ * requested property need to be returned
+ * @return int Error status 0:SUCCESS, Non Zero: Error
+ */
+static int da9052_bat_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ int ret = 0;
+
+ DA9052_DEBUG("In BAT driver =%d \n",psp);
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ if (bat_status.status == CHARGING)
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+
+ else if (bat_status.status == DISCHARGING_WITH_CHARGER)
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+
+ else if (bat_status.status == DISCHARGING_WITHOUT_CHARGER)
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+
+ else if (bat_status.status == CHARGEEND)
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ if (bat_status.charger_type == NOCHARGER)
+ val->intval = FALSE;
+ else
+ val->intval = TRUE;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ if (bat_status.illegalbattery)
+ val->intval = FALSE;
+ else
+ val->intval = TRUE;
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ if(bat_status.health != POWER_SUPPLY_HEALTH_OVERHEAT) {
+ if(bat_status.illegalbattery)
+ bat_status.health = POWER_SUPPLY_HEALTH_UNKNOWN;
+
+ else if (bat_status.cal_capacity < BAT_CAPACITY_LIMIT_LOW)
+ bat_status.health = POWER_SUPPLY_HEALTH_DEAD;
+
+ else
+ bat_status.health = POWER_SUPPLY_HEALTH_GOOD;
+ }
+ val->intval = bat_status.health;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+ val->intval = (chg_device->bat_target_voltage * 1000);
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+ val->intval = ( BAT_VOLT_CUTOFF * 1000 );
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+ val->intval = (bat_info.bat_voltage * 1000);
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_AVG:
+ val->intval = (bat_info.chg_current * 1000);
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = bat_status.cal_capacity;
+ break;
+ /* Not supported by Linux version 2.6.28
+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+ if(bat_status.illegalbattery)
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
+
+ else if (bat_status.cal_capacity < BAT_CAPACITY_LIMIT_LOW)
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+
+ else if(bat_status.cal_capacity < BAT_CAPACITY_LIMIT_HIGH)
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+
+ else if(bat_status.cal_capacity == BAT_CAPACITY_FULL)
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+
+ else if(bat_status.cal_capacity > BAT_CAPACITY_LIMIT_HIGH)
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
+
+ else
+ val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+ break;
+ */
+ case POWER_SUPPLY_PROP_TEMP:
+ val->intval = bat_temp_reg_to_C(bat_info.bat_temp);
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = BAT_MANUFACTURER;
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = BAT_TYPE;
+ break;
+ default:
+ ret = (-EINVAL);
+ break;
+ }
+ DA9052_DEBUG("Return Value = %d\n",val->intval);
+ return ret;
+}
+
+
+#if (DA9052_ILLEGAL_BATTERY_DETECT)
+/**
+* detect_illegal_battery : Called by Battery Driver PDD init function to
+* detect whether battery connected to the DA9052
+* is legal. Here legal battery represent battery
+* with NTC resisitor.
+*
+* @param : void
+* @return s32 Error status 0:SUCCESS, Non Zero: Error
+*/
+static s32 detect_illegal_battery(void)
+{
+ u16 buffer = 0;
+ s32 ret = 0;
+
+ //Measure battery temeperature
+ ret = da9052_bat_get_battery_temperature(&buffer);
+ if(ret) {
+ DA9052_DEBUG("%s: Battery temperature measurement failed \n",__FUNCTION__);
+ return (ret);
+ }
+
+ if(buffer > BAT_WITH_NO_RESISTOR) {
+ bat_status.illegalbattery = TRUE;
+ }
+ else
+ {
+ bat_status.illegalbattery = FALSE;
+ }
+
+ /* suspend charging of battery if illegal battey is detected */
+ if(bat_status.illegalbattery) {
+ da9052_bat_suspend_charging();
+ }
+
+ return (SUCCESS);
+}
+#endif
+
+/*
+ * da9052_bat_current_lim: Set the ICHG_BAT and ISET_BUCK Current limit
+ *
+ * @param u8 bat_cur_lim current limit in mA
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+ s32 da9052_bat_current_lim(u16 bat_cur_lim)
+{
+ da9052_ssc_msg msg;
+
+ msg.addr = DA9052_BATCHG_REG;
+
+ /* Read BAT_CHG register */
+ if(da9052_ssc_read(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+
+
+ /* write value of the battery current limit */
+ msg.data = clear_bits(msg.data,DA9052_BATCHG_ICHGBAT);
+ msg.data = set_bits(msg.data,(bat_cur_lim/20));
+
+ /* Write BAT_CHG register */
+ if(da9052_ssc_write(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+
+ msg.addr = DA9052_CHGBUCK_REG;
+
+ /* Read CHGBUCK register */
+ if(da9052_ssc_read(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+
+ /* write value of the buck current limit */
+ msg.data = clear_bits(msg.data,DA9052_CHGBUCK_ISETBUCK);
+ if(iset_mA_to_reg(bat_cur_lim)) {
+ msg.data = set_bits(msg.data,iset_mA_to_reg(bat_cur_lim));
+ }
+
+ /* Write CHGBUCK register */
+ if(da9052_ssc_write(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+
+ return (SUCCESS);
+}
+
+
+/*
+ * da9052_charger_detect_irq: detect the charger type and decide current limit
+ *
+ * @param void
+ * @return void
+ */
+ void da9052_chager_status_update(void)
+{
+ da9052_ssc_msg msg;
+ u16 current_value = 0;
+ u8 regvalue=0;
+
+ DA9052_DEBUG("FUNCTION = %s \n",__FUNCTION__);
+
+ // Read STATUS_A register
+ msg.addr = DA9052_STATUSA_REG;
+ /* Read STATUS_B register */
+ if(da9052_ssc_read(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return;
+ }
+ regvalue = msg.data;
+
+ // Read STATUS_B register
+ msg.addr = DA9052_STATUSB_REG;
+ /* Read STATUS_B register */
+ if(da9052_ssc_read(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return;
+ }
+
+ /* If DCINDET and DCINSEL are set then connected charger is
+ WALL Charger unit */
+ if( (regvalue & DA9052_STATUSA_DCINSEL)
+ && (regvalue & DA9052_STATUSA_DCINDET) ) {
+
+ /* if Charging end flag is set and Charging current is greater
+ than charging end limit then battery is charging */
+ if ((msg.data & DA9052_STATUSB_CHGEND) != 0) {
+
+ if(da9052_bat_get_chg_current(&current_value)) {
+ return;
+ }
+
+ if( current_value >= chg_device->chg_end_current ) {
+ bat_status.status = CHARGING;
+ bat_status.charger_type = WALL_CHARGER;
+ }
+ else {
+ bat_status.charger_type = WALL_CHARGER;
+ bat_status.status = DISCHARGING_WITH_CHARGER;
+ }
+ }
+ /* if Charging end flag is clered then battery is charging */
+ else {
+ bat_status.status = CHARGING;
+ bat_status.charger_type = WALL_CHARGER;
+ }
+ }
+ /* If VBUS_DET and VBUSEL are set then connected charger is
+ USB Type */
+ else if((regvalue & DA9052_STATUSA_VBUSSEL)
+ && (regvalue & DA9052_STATUSA_VBUSDET)) {
+
+ if (regvalue & DA9052_STATUSA_VDATDET) {
+ bat_status.charger_type = USB_CHARGER;
+ }
+ else {
+ /* Else it has to be USB Host charger */
+ bat_status.charger_type = USB_HUB;
+ }
+
+ /* if Charging end flag is set and Charging current is greater
+ than charging end limit then battery is charging */
+ if ((msg.data & DA9052_STATUSB_CHGEND) != 0) {
+
+ if(da9052_bat_get_chg_current(&current_value)) {
+ return;
+ }
+
+ if (current_value >= chg_device->chg_end_current) {
+ bat_status.status = CHARGING;
+ }
+ else {
+ bat_status.status = DISCHARGING_WITH_CHARGER;
+ }
+
+ }
+ /* if Charging end flag is clered then battery is charging */
+ else {
+ bat_status.status = CHARGING;
+ }
+ }
+ else if(regvalue & DA9052_STATUSA_DCINDET)
+ {
+ bat_status.charger_type = WALL_CHARGER;
+ bat_status.status = DISCHARGING_WITH_CHARGER;
+ }
+ else if(regvalue & DA9052_STATUSA_VBUSDET)
+ {
+ if(regvalue & DA9052_STATUSA_VDATDET) {
+ bat_status.charger_type = USB_CHARGER;
+ bat_status.status = DISCHARGING_WITH_CHARGER;
+ }
+ else {
+ bat_status.charger_type = USB_HUB;
+ bat_status.status = DISCHARGING_WITH_CHARGER;
+ }
+ }
+ else
+ {
+ bat_status.charger_type = NOCHARGER;
+ bat_status.status = DISCHARGING_WITHOUT_CHARGER;
+ }
+ return;
+}
+
+/**
+ * da9052_bat_signal_to_user;
+ * This function signal to the lib which call the call back function.
+ *
+ * @param event
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_bat_signal_to_user(u32 event)
+{
+ if (down_interruptible(&event_lock))
+ return (FAILURE);
+ bat_event = set_bits(bat_event,event);
+ up(&event_lock);
+
+ DA9052_DEBUG("%s: event : %d \n", __FUNCTION__, event);
+ kill_fasync (&bat_fasync_queue, SIGIO, POLL_IN);
+
+ return(SUCCESS);
+}
+
+/**
+ * da9052_charger_dcin_detect_handler : DCIN charger detect event callback
+ * function
+ *
+ * @param u8 event event status
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+ void da9052_charger_dcin_detect_handler(u32 event)
+{
+
+ /* Signal to the library for the charger detection event */
+ if(user_space_chg_det_dcin)
+ {
+ da9052_bat_signal_to_user(CHDET_DCIN);
+ }
+}
+
+/**
+ * da9052_charger_vbus_detect_handler : VBUS charger detect event callback
+ * function
+ *
+ * @param u8 event event status
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+ void da9052_charger_vbus_detect_handler(u32 event)
+{
+ /* Signal to the library for the charger detection event */
+ if(user_space_chg_det_vbus) {
+ da9052_bat_signal_to_user(CHDET_VBUS);
+ }
+}
+
+/**
+ * da9052_charger_dcin_removal_handler : DCIN charger removal event callback
+ * function
+ *
+ * @param u8 event event status
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+ void da9052_charger_dcin_removal_handler(u32 event)
+{
+
+ /* Signal to the library for the charger removal event */
+ if(user_space_chg_rem_dcin) {
+ da9052_bat_signal_to_user(CHREM_DCIN);
+ }
+}
+
+/**
+ * da9052_charger_vbus_removal_handler : VBUS charger removal event callback
+ * function
+ *
+ * @param u8 event event status
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+ void da9052_charger_vbus_removal_handler(u32 event)
+{
+
+ /* Signal to the library for the charger removal event */
+ if(user_space_chg_rem_vbus) {
+ da9052_bat_signal_to_user(CHREM_VBUS);
+ }
+}
+
+
+/**
+ * da9052_bat_vddlow_handler : VDDOUT LOW event callback function
+ *
+ * @param u8 event event status
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+void da9052_bat_vddlow_handler(u32 event)
+{ u16 buffer =0;
+ if(!monitoring_status.vddout_status) {
+ // Measure VDDOUT to update the Monitoring status
+ monitoring_status.vddout_status = TRUE;
+ if(da9052_bat_get_charger_vddout(&buffer)){
+ DA9052_DEBUG("%s : VDDOUT Measurement Fails.\n",__FUNCTION__);
+ }
+ monitoring_status.vddout_value = buffer;
+
+ /* Signal to the library for the VDDLOW event */
+ da9052_bat_signal_to_user(VDDLOW);
+ }
+}
+
+/**
+ * da9052_bat_tbat_handler : TABT event callback function
+ *
+ * @param u8 event event status
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+void da9052_bat_tbat_handler(u32 event)
+{
+ if(!tbat_event_occur) {
+ bat_status.health = POWER_SUPPLY_HEALTH_OVERHEAT;
+ tbat_event_occur = TRUE;
+ // update the TBAt value
+ monitoring_status.bat_temp_status = TRUE;
+ monitoring_status.bat_temp_value = bat_info.bat_temp;
+
+ /* Signal to the library for the VDDLOW event */
+ da9052_bat_signal_to_user(TBAT);
+ }
+}
+
+/**
+ * da9052_charging_end_handler : charging end event callback function
+ *
+ * @param u8 event event status
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+ void da9052_charging_end_handler(u32 event)
+{
+
+ /* Signal to the library for the Charging End event */
+ if(user_space_chg_chgend) {
+ da9052_bat_signal_to_user(CHGEND);
+ }
+
+ power_supply_changed(&psy);
+}
+
+
+/*
+ * charger_buck: Enable/Disable the charger buck
+ *
+ * @param u8 flag should be a enable/disable
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 charger_buck(u8 flag)
+{
+ da9052_ssc_msg msg;
+
+ /* Read Charger buck register */
+ msg.addr = DA9052_CHGBUCK_REG;
+ if(da9052_ssc_read(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+
+ msg.data = flag ?
+ set_bits(msg.data,DA9052_CHGBUCK_CHGBUCKEN):
+ clear_bits(msg.data,DA9052_CHGBUCK_CHGBUCKEN);
+
+ /* Write charger buck register*/
+ if(da9052_ssc_write(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+
+ return (SUCCESS);
+}
+
+
+
+/*
+ * monitor_current: Monitor the surge in charging current
+ *
+ * @param void
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+ static s32 monitor_current(void)
+{
+ static u8 flag1 =FALSE;
+ u8 count = 0;
+ u16 current_value=0;
+ u16 tempvalue=0;
+ u16 avg_value=0;
+
+ /* Read the charger current value from the current measurement function */
+ if(da9052_bat_get_chg_current(&current_value)){
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (CHG_MEASUREMENT_FAIL);
+ }
+
+ /* If montoring function is called first time then set the window */
+ if(flag1 == FALSE){
+ for(count=0;count<NUMBER_OF_STORE_CURENT_READING;count++) {
+ bat_info.chg_current_raw[count] = 0;
+ }
+
+ tempvalue= (CURRENT_MONITORING_WINDOW *current_value)/100;
+ chg_device->threshold.ichg_av_thr_min = current_value-tempvalue;
+ chg_device->threshold.ichg_av_thr_max = current_value+tempvalue;
+ flag1=TRUE;
+ }
+
+ for(count=(NUMBER_OF_STORE_CURENT_READING-1);count > 0 ;count--)
+ bat_info.chg_current_raw[count] =
+ bat_info.chg_current_raw[count-1];
+ bat_info.chg_current_raw[0] = current_value;
+
+ /* Form last stored value of the charger current get the
+ average value */
+ for(count=0;count<NUMBER_OF_STORE_CURENT_READING;count++) {
+ if(bat_info.chg_current_raw[count] == 0)
+ break;
+ avg_value=avg_value + bat_info.chg_current_raw[count];
+ }
+ if(count != 0)
+ avg_value = avg_value/count;
+ else
+ avg_value = current_value;
+
+ // DA9052_DEBUG("Average_Current = %d\n",avg_value);
+ /* Window is reallign with 10% of the average measur1e value*/
+ tempvalue= (CURRENT_MONITORING_WINDOW *avg_value)/100;
+
+ /* Check measured value with surge window */
+ if(((current_value < chg_device->threshold.ichg_av_thr_min)
+ || (current_value > chg_device->threshold.ichg_av_thr_max))) {
+
+ monitoring_status.current_status = TRUE;
+ monitoring_status.current_value = current_value;
+
+#if DA9052_BAT_FILTER_HYS
+ printk( KERN_CRIT "\nBAT_LOG: Current Monitoring Failed = %d mA\n",
+ current_value);
+#endif
+
+ /* If there is a surge then signal to the user */
+ if(montoring_func_reg) {
+ da9052_bat_signal_to_user(MONITORING);
+ }
+
+ // if average value read is less than window lower limit re-arrange
+ // the window to lower value
+ chg_device->threshold.ichg_av_thr_min = avg_value - tempvalue;
+ chg_device->threshold.ichg_av_thr_max = avg_value + tempvalue;
+ return (CHG_MONITORING_FAIL);
+ }
+ else {
+ monitoring_status.current_status = FALSE;
+ monitoring_status.current_value = current_value;
+ }
+
+ // if average value read is less than window lower limit re-arrange
+ // the window to lower value
+ chg_device->threshold.ichg_av_thr_min = avg_value - tempvalue;
+ chg_device->threshold.ichg_av_thr_max = avg_value + tempvalue;
+ return (SUCCESS);
+
+}
+
+
+/*
+ * monitor_bat_temperature: Monitor battery temperature threshold limit
+ *
+ * @param void
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+static s32 monitor_bat_temperature(void)
+{
+ u16 buffer;
+ u8 ret =0;
+
+ /* Measure the BAT temperature using BAT internal function */
+ ret=da9052_bat_get_battery_temperature(&buffer);
+ if(ret)
+ return (ret);
+
+ if(buffer > chg_device->threshold.tbat_thr_limit) {
+ /* If software monitoring is enabled then suspend charging */
+ if(chg_device->sw_temp_cntr ==1)
+ da9052_bat_suspend_charging();
+
+ monitoring_status.bat_temp_status = TRUE;
+ monitoring_status.bat_temp_value = buffer;
+
+ /* If User has registered the monitoring event, signal to
+ the user for the event */
+ if(montoring_func_reg) {
+ da9052_bat_signal_to_user(MONITORING);
+ }
+ return (CHG_MONITORING_FAIL);
+ }
+ else {
+ monitoring_status.bat_temp_status = FALSE;
+ monitoring_status.bat_temp_value = buffer;
+ }
+
+ return (SUCCESS);
+}
+
+/*
+ * monitor_junc_temperature: Monitor the junction temperature
+ *
+ * @param void
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+static s32 monitor_junc_temperature(void)
+{
+ u16 buffer;
+ u8 ret =0;
+
+ /* Measure the Junction temperature using BAT internal function */
+ ret=da9052_bat_get_chg_junc_temperature(&buffer);
+ if(ret)
+ return (ret);
+
+ if(buffer > chg_device->threshold.tjunc_thr_limit) {
+ /* If software monitoring is enabled then suspend charging */
+ if(chg_device->sw_temp_cntr ==1)
+ da9052_bat_suspend_charging();
+
+ monitoring_status.junc_temp_status = TRUE;
+ monitoring_status.junc_temp_value = buffer;
+
+ /* If User has registered the monitoring event, signal to
+ the user for the event */
+ if(montoring_func_reg) {
+ da9052_bat_signal_to_user(MONITORING);
+ }
+ return (CHG_MONITORING_FAIL);
+ }
+ else {
+ monitoring_status.junc_temp_status = FALSE;
+ monitoring_status.junc_temp_value = buffer;
+ }
+ return (SUCCESS);
+}
+
+/*
+ * interpolated: Find the battery level for the bat_voltage, given
+ * Voltage and time at 2 other place using the piecewise
+ * interpolation method
+ *
+ * @param u32 vbat_upper
+ * @param u32 vbat_lower
+ * @param u32 level_upper
+ * @param u32 level_lower
+ * @param u32 bat_voltage
+ * @return u32 time at bat_voltage
+ */
+u32 interpolated( u32 vbat_lower, u32 vbat_upper, u32 level_lower,
+ u32 level_upper, u32 bat_voltage)
+{
+ s32 temp;
+
+ /*apply formula y= yk + (x ?xk) * (yk+1 ?yk)/(xk+1 杧k) */
+ temp = ((level_upper - level_lower) * 1000)/(vbat_upper - vbat_lower);
+ temp = level_lower + (((bat_voltage -vbat_lower) * temp)/1000);
+
+ return (temp);
+}
+
+/*
+ * capture_first_correct_vbat_sample: When hysteresis function is called
+ * first time, this function helps to get first correct
+ * value of battery voltage
+ *
+ * @param battery_voltage : captured sample of battery voltage
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 capture_first_correct_vbat_sample( u16* battery_voltage)
+{
+ static u8 count = 0;
+ s32 ret =0;
+ u32 temp_data = 0;
+
+ ret =da9052_bat_get_battery_voltage(&bat_volt_arr[count]);
+ if(ret)
+ return (ret);
+ count++;
+ //DA9052_DEBUG("Count = %d\n",count);
+ if(count < VBAT_FIRST_VALID_DETECT_ITERATION )
+ return (FAILURE);
+ for (count =0; count < (VBAT_FIRST_VALID_DETECT_ITERATION - 1) ; count++) {
+ temp_data = ( bat_volt_arr[count] *
+ HYSTERESIS_WINDOW_SIZE)/100;
+ bat_hysteresis.upper_limit = bat_volt_arr[count] + temp_data;
+ bat_hysteresis.lower_limit = bat_volt_arr[count] - temp_data;
+
+ if( (bat_volt_arr[count + 1] < bat_hysteresis.upper_limit ) &&
+ (bat_volt_arr[count + 1] > bat_hysteresis.lower_limit )){
+
+ *battery_voltage = (bat_volt_arr[count] +
+ bat_volt_arr[count+1])/ 2;
+ hys_flag = TRUE;
+ return (SUCCESS);
+ }
+ }
+
+ for(count=0;count < (VBAT_FIRST_VALID_DETECT_ITERATION - 1);count++)
+ bat_volt_arr[count] = bat_volt_arr[count + 1];
+
+ return (FAILURE);
+}
+/*
+ * check_hystersis: Check the hystersis effect for the measured
+ * bat_voltage value
+ *
+ * @param u16 *bat_voltage :bat voltage value to be returned
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 check_hystersis( u16 *bat_voltage)
+{
+ u8 ret=0;
+ u32 offset=0;
+
+ /* Measure battery voltage using BAT internal function*/
+ if(hys_flag == FALSE) {
+ ret = capture_first_correct_vbat_sample(&array_hys_batvoltage[0]);
+ if(ret)
+ return (ret);
+ }
+
+ ret =da9052_bat_get_battery_voltage(&array_hys_batvoltage[1]);
+ if(ret)
+ return (ret);
+ *bat_voltage = array_hys_batvoltage[1];
+
+#if DA9052_BAT_FILTER_HYS
+ printk( KERN_CRIT "\nBAT_LOG: Previous Battery Voltage = %d mV\n",
+ array_hys_batvoltage[0]);
+ printk( KERN_CRIT "\nBAT_LOG:Battery Voltage Before Filter = %d mV\n",
+ array_hys_batvoltage[1]);
+#endif
+ /* Check if measured battery voltage value is within the hysteresis
+ window limit using measured battey votlage value */
+ if((bat_hysteresis.upper_limit < *bat_voltage) ||
+ (bat_hysteresis.lower_limit > *bat_voltage)) {
+
+ bat_hysteresis.index++;
+
+ if(bat_hysteresis.index == HYSTERESIS_NO_OF_READING) {
+ /* Hysteresis Window is set to +- of HYSTERESIS_WINDOW_SIZE
+ percentage of current VBAT */
+ bat_hysteresis.index =0;
+ offset = ((*bat_voltage) * HYSTERESIS_WINDOW_SIZE)/100;
+ bat_hysteresis.upper_limit = (*bat_voltage) + offset;
+ bat_hysteresis.lower_limit = (*bat_voltage) - offset;
+
+ }
+ else
+ {
+#if DA9052_BAT_FILTER_HYS
+ printk( KERN_CRIT "CheckHystersis: Failed\n");
+#endif
+ return (CHG_HYSTERSIS_CHECK_FAILED);
+ }
+ }
+ else {
+
+ /* Hysteresis Window is set to +- of HYSTERESIS_WINDOW_SIZE
+ percentage of current VBAT */
+ bat_hysteresis.index =0;
+ offset = ((*bat_voltage) * HYSTERESIS_WINDOW_SIZE)/100;
+ bat_hysteresis.upper_limit = (*bat_voltage) + offset;
+ bat_hysteresis.lower_limit = (*bat_voltage) - offset;
+ }
+
+
+ /* Digital C Filter, formula Yn = k Yn-1 + (1-k) Xn */
+ *bat_voltage = ((CHG_HYSTERESIS_CONST * array_hys_batvoltage[0])/100) +
+ (((100 - CHG_HYSTERESIS_CONST) * array_hys_batvoltage[1])/100);
+
+ if( (bat_status.status == DISCHARGING_WITHOUT_CHARGER) &&
+ (*bat_voltage > array_hys_batvoltage[0]) ) {
+ *bat_voltage = array_hys_batvoltage[0];
+ }
+
+ //DA9052_DEBUG("Voltage Final =%d \n",*bat_voltage);
+ array_hys_batvoltage[0] = *bat_voltage;
+
+#if DA9052_BAT_FILTER_HYS
+ printk( KERN_CRIT "\nBAT_LOG:Battery Voltage After Filter = %d mV\n",*bat_voltage);
+#endif
+ return (SUCCESS);
+}
+
+/*
+* Function Name : select_temperature()
+*
+* Description : Function select the temperature index btween 2 conscutive
+ temperature
+*
+* Arguments :
+* temp_index : index of the temperature in the temperature lookup table
+* bat_temperature : Current temperature of the battery
+*
+* Return : The lookup table index which need to be consider for the battey level
+ detemination.
+*/
+u8 select_temperature(u8 temp_index,u16 bat_temperature)
+{
+ u16 temp_temperature = 0;
+ temp_temperature = (temperature_lookup_ref[temp_index] +
+ temperature_lookup_ref[temp_index+1]) / 2;
+
+ if(bat_temperature >= temp_temperature)
+ return (temp_index+1);
+ else
+ return (temp_index);
+}
+
+/*
+ * da9052_get_bat_level: Measure the battery level in terms of %
+ *
+ * @param void
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_get_bat_level(void)
+{
+ u16 bat_temperature;
+ u16 bat_voltage;
+ u32 vbat_lower, vbat_upper, level_upper, level_lower,level;
+ u8 access_index=0;
+ u8 index=0,ret;
+ u8 flag =FALSE;
+
+ ret = 0;
+ vbat_lower =0;
+ vbat_upper =0;
+ level_upper=0;
+ level_lower=0;
+
+ //DA9052_DEBUG("STEP 0 \n");
+ /* Function call the hysteresis function. Function measure battery
+ voltage and check for hysteresis */
+ ret = check_hystersis(&bat_voltage);
+ if(ret)
+ return (ret);
+
+ //DA9052_DEBUG("STEP 1 \n");
+ /* measure battery temperature using BAT function */
+ ret= da9052_bat_get_battery_temperature(&bat_temperature);
+ if(ret)
+ return (ret);
+ /* According to the read battery temperature choose corresponding
+ lookup table */
+ //DA9052_DEBUG("STEP 2 \n");
+ for (index=0;index<(NO_OF_LOOKUP_TABLE-1);index++) {
+ if(bat_temperature <= temperature_lookup_ref[0]) {
+ access_index=0;
+ break;
+ }
+ else if(bat_temperature >
+ temperature_lookup_ref[NO_OF_LOOKUP_TABLE]){
+ access_index=NO_OF_LOOKUP_TABLE -1;
+ break;
+ }
+ else if((bat_temperature >= temperature_lookup_ref[index])
+ && (bat_temperature >= temperature_lookup_ref[index+1])){
+ access_index = select_temperature(index,bat_temperature);
+ break;
+ }
+ }
+ //DA9052_DEBUG("STEP 3 = %d \n",bat_voltage);
+ //DA9052_DEBUG("Access Index = %d \n",access_index);
+ /* Base on lookup table selected and measured battery voltage value read
+ * dwVbatLower = lookup table VBAT value immediately lower than
+ * measured VBAT value
+ * dwVbatUpper = lookup table VBAT value immediately upper than
+ * measured VBAT value s
+ * dwLevelLower = lookup table level for dwVbatLower value
+ * dwLevelUpper = lookup table level for dwVbatUpper value
+ */
+ if(bat_voltage >= vbat_vs_capacity_look_up[access_index][0][0]) {
+ bat_status.cal_capacity =100;
+ //DA9052_DEBUG("V100 = %d \n",vbat_vs_capacity_look_up[access_index][0][0]);
+ return(SUCCESS);
+ }
+ if(bat_voltage <=
+ vbat_vs_capacity_look_up[access_index][LOOK_UP_TABLE_SIZE-1][0]){
+ //DA9052_DEBUG("V0 = %d \n",vbat_vs_capacity_look_up[access_index][LOOK_UP_TABLE_SIZE-1][0]);
+ bat_status.cal_capacity =0;
+ return(SUCCESS);
+ }
+
+ flag=FALSE;
+
+ for (index=0;index<(LOOK_UP_TABLE_SIZE-1);index++) {
+ if((bat_voltage <= vbat_vs_capacity_look_up[access_index][index][0]) &&
+ (bat_voltage >= vbat_vs_capacity_look_up[access_index][index+1][0])) {
+
+ //DA9052_DEBUG("Vaa = %d \n",vbat_vs_capacity_look_up[access_index][index][0]);
+ //DA9052_DEBUG("Vbb = %d \n",vbat_vs_capacity_look_up[access_index][index+1][0]);
+
+ vbat_upper = vbat_vs_capacity_look_up[access_index][index][0];
+ vbat_lower = vbat_vs_capacity_look_up[access_index][index+1][0];
+ level_upper = vbat_vs_capacity_look_up[access_index][index][1];
+ level_lower = vbat_vs_capacity_look_up[access_index][index+1][1];
+ flag =TRUE;
+ break;
+ }
+ }
+ //DA9052_DEBUG("STEP 4 \n");
+ if(!flag)
+ return (INVALID_VBAT_VALUE);
+
+ // Call interpolation function to get time at bat_voltage value */
+ level = interpolated(vbat_lower,vbat_upper,level_lower,
+ level_upper,bat_voltage);
+ bat_status.cal_capacity = level;
+ DA9052_DEBUG(" TOTAl_BAT_CAPACITY : %d\n", bat_status.cal_capacity);
+ return (SUCCESS);
+}
+
+/**
+ * eh_thread:
+ * @param data pointer to device specific data
+ * @return int status
+ */
+static s32 monitoring_thread(void* data){
+ u8 mon_count = 0;
+ s32 ret = 0;
+#if DA9052_BAT_PROFILE
+ u8 mon_times = 0;
+ u32 jiffies_count = 0;
+ u32 msec_time_bat_Level = 0;
+#endif
+ //DA9052_DEBUG("Starting BAT Thread...\n");
+
+ set_freezable();
+
+ while(monitoring_thread_state == ACTIVE){
+
+ /* Make this thread friendly to system suspend and resume */
+ try_to_freeze();
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(chg_device->monitoring_interval);
+#if DA9052_BAT_PROFILE
+ jiffies_count = jiffies;
+#endif
+ da9052_chager_status_update();
+ /**
+ * Each parameter monitoring is schdule in sequence. "mon_count" decide
+ * the sequence of operation.
+ * Current Sequence is
+ * --charger current
+ * --junction temperature
+ * --BAT capacity
+ * --BAT temperature
+ */
+
+ /* check if battery is in charging mode */
+ if(bat_status.status==CHARGING) {
+ /* If battery is in charging mode then only call charger
+ current and bat temperature monitoring */
+ if(mon_count == 0){
+ if(CHG_MONITORING_FAIL == monitor_current()){
+ DA9052_DEBUG("charging Current Monitoring failed, %d\n",mon_count);
+ }
+ }
+
+ /* call junction temperature monitoring */
+ else if(mon_count == 1){
+ if(CHG_MONITORING_FAIL == monitor_junc_temperature()){
+ DA9052_DEBUG("Charger Junction Temperature Monitoring failed\n");
+ }
+ }
+ }
+
+ if(mon_count == 2){
+ ret = da9052_get_bat_level();
+ if(!ret) {
+ // BAT Capacity is low then update the monitoring status
+ if(bat_status.cal_capacity < BAT_CAPACITY_LIMIT_LOW) {
+ monitoring_status.bat_level_status = TRUE;
+ monitoring_status.bat_level = bat_status.cal_capacity;
+ }
+ else {
+ monitoring_status.bat_level_status = 0;
+ monitoring_status.bat_level = bat_status.cal_capacity;
+ }
+ }
+ else {
+ DA9052_DEBUG("Battery Measurement Fails = %d\n",ret);
+ }
+ }
+
+ if(mon_count == 3){
+ if(CHG_MONITORING_FAIL == monitor_bat_temperature()){
+ DA9052_DEBUG("BAT Temperature Monitoring failed\n");
+ }
+ }
+
+#if DA9052_BAT_PROFILE
+ jiffies_count = jiffies - jiffies_count;
+
+ if(mon_count ==2) {
+ mon_times++;
+ msec_time_bat_Level = msec_time_bat_Level +
+ jiffies_to_msecs(jiffies_count);
+
+ if(mon_times == 5) {
+ printk( KERN_CRIT "\n\nBAT_LOG:5 BAT Level Monitoring cycle time = %d msec\n",
+ msec_time_bat_Level);
+ printk( KERN_CRIT "BAT_LOG:BAT Level Value: %d percent\n",monitoring_status.bat_level);
+ mon_times = 0;
+ msec_time_bat_Level = 0;
+ }
+ }
+#endif
+ mon_count++;
+ if(mon_count == 4){
+ mon_count = 0;
+ }
+
+ /* modify and reschedule timer with same time interval */
+ //DA9052_DEBUG("Monitoring interval = %d\n",chg_device->monitoring_interval);
+ }
+
+ complete_and_exit(&monitoring_thread_notifier, 0);
+
+ return (SUCCESS);
+}
+
+/*
+ * filter_sample: Perform the average filtering
+ *
+ * @param u16 *buffer Parameter buffer pointer
+ * @return u16 Filtered value
+ */
+ u16 filter_sample(u16 *buffer)
+{
+ u8 count;
+ u16 tempvalue=0;
+
+ if(buffer == NULL)
+ return(FAILURE);
+
+ for(count=0;count<FILTER_SIZE;count++){
+ tempvalue=tempvalue + *(buffer + count);
+ }
+
+ return (tempvalue/FILTER_SIZE);
+}
+
+/*--------------------------------------------------------------------------*/
+/* Global Functions */
+/*--------------------------------------------------------------------------*/
+
+
+/*
+ * da9052_remaining_charging_time: Read charging time and convert it
+ * in terms of minutes
+ *
+ * @param u8 *buffer (buffer pointer)
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_bat_get_remaining_charging_time(u16 *buffer)
+{
+ da9052_ssc_msg msg;
+
+ msg.addr = DA9052_CHGTIME_REG;
+ /* Read charging time register */
+ if(da9052_ssc_read(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+
+ /* Convert register value in terms of minutes*/
+ *buffer = msg.data * 2;
+ return (SUCCESS);
+}
+
+
+/*
+ * da9052_bat_get_chg_current: Measure the charger current and convert
+ * raw current value in terms of mA
+ *
+ * @param u16 *buffer (buffer pointer)
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_bat_get_chg_current(u16 *buffer)
+{
+
+ if(bat_status.status == DISCHARGING_WITHOUT_CHARGER)
+ return (BAT_NOT_CHARGING);
+
+ /* Measure the Charger current using ADC function */
+ if(da9052_adc_read_ich(buffer)){
+ return (CHG_MEASUREMENT_FAIL);
+ }
+
+ /* Convert the raw value in terms of mA */
+ bat_info.chg_current = ichg_reg_to_mA(*buffer);
+ *buffer=bat_info.chg_current;
+
+ return (SUCCESS);
+}
+
+/*
+ * da9052_bat_get_chg_junc_temperature: Measure the junction temperature and
+ * convert value in terms of C
+ *
+ * @param u16 *buffer (buffer pointer)
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_bat_get_chg_junc_temperature(u16 *buffer)
+{
+ u8 count;
+ u16 filterqueue[FILTER_SIZE];
+
+ if(bat_status.status != CHARGING)
+ return (BAT_NOT_CHARGING);
+
+ /* Measure the junciton temperature using ADC function. Number
+ of read equal to average filter size*/
+ for(count=0;count<FILTER_SIZE;count++){
+ if(da9052_adc_read_tjunc(&filterqueue[count])){
+ return (CHG_MEASUREMENT_FAIL);
+ }
+ }
+
+ /* Apply average filter */
+ filterqueue[0]=filter_sample(filterqueue);
+
+ /* Convert the junction temperature raw value in terms of C */
+ bat_info.chg_junc_temp = (((1708 *
+ filterqueue[0])/1000) - 106);
+ *buffer=bat_info.chg_junc_temp;
+
+ return (SUCCESS);
+}
+
+/*
+ * da9052_bat_get_battery_voltage: Measure the battery voltage and convert
+ * value in terms of mV
+ *
+ * @param u16 *buffer (buffer pointer)
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_bat_get_battery_voltage(u16 *buffer)
+{
+ u8 count;
+ u16 filterqueue[FILTER_SIZE];
+
+ /* Measure the battery voltage using ADC function. Number
+ of read equal to average filter size*/
+ for(count=0;count<FILTER_SIZE;count++){
+ if(da9052_adc_read_vbat(&filterqueue[count])){
+ return (CHG_MEASUREMENT_FAIL);
+ }
+ }
+ /* Apply average filter */
+ filterqueue[0]=filter_sample(filterqueue);
+
+ /* Convert battery voltage raw value in terms of mV */
+ bat_info.bat_voltage = volt_reg_to_mV(filterqueue[0]);
+ *buffer=bat_info.bat_voltage;
+ return (SUCCESS);
+}
+
+/*
+ * da9052_bat_get_backup_battery_voltage: Measure the backup battery voltage and
+ * convert value in terms of mV
+ *
+ * @param u16 *buffer (buffer pointer)
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_bat_get_backup_battery_voltage(u16 *buffer)
+{
+ u8 count;
+ u16 filterqueue[FILTER_SIZE];
+
+ /* Measure the backup battery voltage using ADC function. Number
+ of read equal to average filter size*/
+ for(count=0;count<FILTER_SIZE;count++){
+ if(da9052_adc_read_vbbat(&filterqueue[count])){
+ return (CHG_MEASUREMENT_FAIL);
+ }
+ }
+
+ /* Apply average filter */
+ filterqueue[0]=filter_sample(filterqueue);
+
+ /* Convert backup battey voltage raw value in terms of mV */
+ bat_info.backup_bat_voltage =
+ volt_reg_to_mV(filterqueue[0]);
+ *buffer=bat_info.backup_bat_voltage;
+
+ return (SUCCESS);
+}
+
+/*
+ * da9052_bat_get_battery_temperature: Measure the bat temperature and
+ * return raw value
+ *
+ * @param u16 *buffer (buffer pointer)
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_bat_get_battery_temperature(u16 *buffer)
+{
+ u8 count;
+ u16 filterqueue[FILTER_SIZE];
+
+ /* Measure the battery temperature using ADC function. Number
+ of read equal to average filter size*/
+ for(count=0;count<FILTER_SIZE;count++){
+ if(da9052_adc_read_tbat(&filterqueue[count])){
+ return (CHG_MEASUREMENT_FAIL);
+ }
+ }
+
+ /* Apply Average filter */
+ filterqueue[0]=filter_sample(filterqueue);
+
+ bat_info.bat_temp = filterqueue[0];
+ *buffer=bat_info.bat_temp;
+
+ return (SUCCESS);
+}
+
+/*
+ * da9052_bat_get_charger_vddout: Measure the charger output voltage and
+ * convert it in mV
+ *
+ * @param u16 *buffer (buffer pointer)
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_bat_get_charger_vddout(u16 *buffer)
+{
+ u8 count;
+ u16 filterqueue[FILTER_SIZE];
+
+ if(bat_status.status != CHARGING)
+ return (BAT_NOT_CHARGING);
+
+ /* Measure the charger voltage using ADC function. Number
+ of read equal to average filter size*/
+ for(count=0;count<FILTER_SIZE;count++){
+ if(da9052_adc_read_vddout(&filterqueue[count])){
+ return (CHG_MEASUREMENT_FAIL);
+ }
+ }
+
+ /*Apply average filter */
+ filterqueue[0]=filter_sample(filterqueue);
+
+ /* Convert the charger voltage in terms of mV */
+ bat_info.vddout = vddout_reg_to_mV(filterqueue[0]);
+ *buffer=bat_info.vddout;
+
+ return (SUCCESS);
+}
+
+
+/*
+ * da9052_get_bat_status: Function check the status of the battery
+ *
+ * @param da9052_bat_status *buffer: function will put status in this buffer
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_get_bat_status( da9052_bat_status *status_buffer)
+{
+ da9052_ssc_msg msg;
+ u16 buffer;
+
+ /* If battery is in discharging mode then set charging
+ mode and return */
+ if(bat_status.status == DISCHARGING_WITHOUT_CHARGER){
+ bat_status.charging_mode=NONE;
+ }
+
+ if(bat_status.status == DISCHARGING_WITH_CHARGER){
+ bat_status.charging_mode=NONE;
+ }
+ else
+ {
+ msg.addr = DA9052_STATUSB_REG;
+ /* Read STATUS_B register */
+ if(da9052_ssc_read(&msg))
+ return (SSC_FAIL);
+
+ /* Check if the battery is in Pre-charging mode */
+ if(msg.data & DA9052_STATUSB_CHGPRE) {
+ /* If battery is in Pre-charging mode. set Pre-charging
+ status and return */
+ bat_status.charging_mode=PRECHARGING;
+ bat_status.status=CHARGING;
+ }
+ else {
+ /* Measure battery voltag. if battery voltage is less than
+ (VCHG_BAT - VCHG_DROP) battery is in linear
+ charging mode*/
+ if(da9052_bat_get_battery_voltage(&buffer)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (CHG_MEASUREMENT_FAIL);
+ }
+ if((buffer < (chg_device->bat_target_voltage -
+ chg_device->charger_voltage_drop)) &&
+ (buffer > BAT_VOLT_CUTOFF)){
+ /* Set linear charging status and return */
+ bat_status.charging_mode=LINEARCHARGING;
+ }
+ /* Else battey is in charge termintation mode. Set Charge end
+ status and return */
+ else if(buffer > (chg_device->bat_target_voltage -
+ chg_device->charger_voltage_drop)){
+ bat_status.charging_mode=CHARGEEND;
+ }
+ }
+ }
+
+ status_buffer->cal_capacity = bat_status.cal_capacity;
+ status_buffer->charging_mode = bat_status.charging_mode;
+ status_buffer->charger_type = bat_status.charger_type;
+ status_buffer->status = bat_status.status;
+ status_buffer->illegalbattery = bat_status.illegalbattery;
+
+ return (SUCCESS);
+}
+
+
+
+/*
+ * da9052_bat_suspend_charging: Suspend the charging for the battery
+ *
+ * @param void
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_bat_suspend_charging()
+{
+ da9052_ssc_msg msg;
+
+ if( (bat_status.status == DISCHARGING_WITHOUT_CHARGER) ||
+ (bat_status.status == DISCHARGING_WITH_CHARGER) )
+ return (SUCCESS);
+
+ msg.addr = DA9052_INPUTCONT_REG;
+ /* Read Input condition register */
+ if(da9052_ssc_read(&msg))
+ return (SSC_FAIL);
+
+ /* set both Wall charger and USB charger suspend bit */
+ msg.data = set_bits(msg.data,DA9052_INPUTCONT_DCINSUSP);
+ msg.data = set_bits(msg.data,DA9052_INPUTCONT_VBUSSUSP);
+
+ /* Write to Input control register */
+ if(da9052_ssc_write(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+
+ power_supply_changed(&psy);
+
+ DA9052_DEBUG("%s : Sucess\n",__FUNCTION__);
+ return (SUCCESS);
+}
+
+/*
+ * da9052_bat_resume_charging: Resume the charging for the battery
+ *
+ * @param void
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_bat_resume_charging()
+{
+ da9052_ssc_msg msg;
+
+ if( bat_status.illegalbattery)
+ return (FAILURE);
+
+ if( (bat_status.status == CHARGING) )
+ return (SUCCESS);
+
+ msg.addr = DA9052_INPUTCONT_REG;
+ /* Read Input condition register */
+ if(da9052_ssc_read(&msg))
+ return (SSC_FAIL);
+
+ /* Reset both Wall charger and USB charger suspend bit */
+ msg.data = clear_bits(msg.data,DA9052_INPUTCONT_DCINSUSP);
+ msg.data = clear_bits(msg.data,DA9052_INPUTCONT_VBUSSUSP);
+
+ /* Write to Input control register */
+ if(da9052_ssc_write(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+
+ power_supply_changed(&psy);
+
+ DA9052_DEBUG("%s : Sucess\n",__FUNCTION__);
+ return (SUCCESS);
+}
+
+/*
+ * da9052_bat_configure_thresholds: configure the threshold for the battery
+ *
+ * @param da9052_bat_threshold thresholds
+ * (structure containing threshold settings)
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_bat_configure_thresholds(da9052_bat_threshold thresholds)
+{
+ da9052_ssc_msg msg;
+
+ /* check VDDOUTLOW range */
+ if((VDDOUT_MON_LOWER > thresholds.vddout_mon) &&
+ (VDDOUT_MON_UPPER < thresholds.vddout_mon)){
+ return (INVALID_VDDOUT_MON_VALUE);
+ }
+
+ /* Convert user configuration in term of bit field value */
+ msg.data = vddout_mon_mV_to_reg(thresholds.vddout_mon);
+
+ /* Write to VDDMON register */
+ msg.addr = DA9052_VDDMON_REG;
+ if(da9052_ssc_write(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+
+
+ /* Check th cahrger current threshold range */
+ if(ICHG_THRESHOLD_UPPER < thresholds.ichg_thr){
+ return (INVALID_ICHG_THRESHOLD_VALUE);
+ }
+
+ /* Convert the charger curent in term of bit field value */
+ msg.data = ichg_mA_to_reg(thresholds.ichg_thr);
+
+ /* Write to ICHGTHD register */
+ msg.addr = DA9052_ICHGTHD_REG;
+ if(da9052_ssc_write(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+
+ /* Check the TBAT max theshold range */
+ if(TBAT_MAX_THRESHOLD_LIMIT < thresholds.tbat_thr_max){
+ return (INVALID_BAT_TEMP_HIGH);
+ }
+
+ msg.data = thresholds.tbat_thr_max;
+
+ /* Write to the TBATHIGHP register*/
+ msg.addr = DA9052_TBATHIGHP_REG;
+ if(da9052_ssc_write(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+
+ /* Check the TBAT min theshold range */
+ if(TBAT_MIN_THRESHOLD_LIMIT < thresholds.tbat_thr_min){
+ return (INVALID_BAT_TEMP_LOW);
+ }
+
+ msg.data = thresholds.tbat_thr_min;
+
+ /* Write to the TBATLOW register*/
+ msg.addr = DA9052_TBATLOW_REG;
+ if(da9052_ssc_write(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+
+ /* Check the TBAT charging resume value range */
+ if(TBAT_HIGHNS_THRESHOLD_LIMIT < thresholds.tbat_thr_highns){
+ return (INVALID_BAT_TEMP_HIGHN);
+ }
+
+ msg.data = thresholds.tbat_thr_highns;
+
+ /* Write to TBATHIGHIN register */
+ msg.addr = DA9052_TBATHIGHIN_REG;
+ if(da9052_ssc_write(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+ chg_device->threshold = thresholds;
+ return (SUCCESS);
+}
+/*
+ * da9052_bat_configure_charger: Configure the battery charger according to
+ * user configuration
+ *
+ * @param da9052_charger_device charger
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_bat_configure_charger(da9052_charger_device charger)
+{
+ da9052_ssc_msg msg;
+
+ /* Configure buck_low_power, chg_usb_ilim and chg_temp_cntr */
+ DA9052_DEBUG("FUNCTION: %s\n",__FUNCTION__);
+
+ /* charger BAT_CHG register */
+ msg.addr = DA9052_CHGBUCK_REG;
+ if(da9052_ssc_read(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+ msg.data = charger.chager_buck_lp ?
+ set_bits(msg.data,DA9052_CHGBUCK_CHGBUCKLP):
+ clear_bits(msg.data,DA9052_CHGBUCK_CHGBUCKLP);
+
+ msg.data = charger.usb_charger_det ?
+ set_bits(msg.data,DA9052_CHGBUCK_CHGUSBILIM):
+ clear_bits(msg.data,DA9052_CHGBUCK_CHGUSBILIM);
+
+ msg.data = charger.auto_temp_cntr ?
+ set_bits(msg.data,DA9052_CHGBUCK_CHGTEMP):
+ clear_bits(msg.data,DA9052_CHGBUCK_CHGTEMP);
+
+ if(da9052_ssc_write(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+
+ /* Configure ISET_VBUS and ISET_DCIN */
+ msg.data = 0x0;
+
+ if( (ISET_LOW > charger.dcin_current) &&
+ (charger.dcin_current > ISET_HIGH)) {
+ return (INVALID_DCIN_CURRENT_LIMIT_VALUE);
+ }
+
+ if( (ISET_LOW > charger.vbus_current) &&
+ (charger.vbus_current > ISET_HIGH)) {
+ return (INVALID_VBUS_CURRENT_LIMIT_VALUE);
+ }
+ if( (ISET_LOW > charger.usb_charger_current) &&
+ (charger.usb_charger_current > ISET_HIGH)) {
+ return (INVALID_USB_CHARGER_CURRENT_LIMIT_VALUE);
+ }
+ chg_device->dcin_current = charger.dcin_current;
+ chg_device->vbus_current = charger.vbus_current;
+ chg_device->usb_charger_current = charger.usb_charger_current;
+
+ if((iset_mA_to_reg(charger.vbus_current) &&
+ iset_mA_to_reg(charger.dcin_current)) == 0)
+ return (FAILURE);
+ msg.data = iset_mA_to_reg(charger.vbus_current) |
+ (iset_mA_to_reg(charger.dcin_current) << 4);
+
+ msg.addr = DA9052_ISET_REG;
+ if(da9052_ssc_write(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+ /* Configure Precharing current limit */
+ /* charger BAT_CHG register */
+ msg.addr = DA9052_BATCHG_REG;
+ if(da9052_ssc_read(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+ if( (PRE_CHARGE_0MA != charger.precharging_current) &&
+ (PRE_CHARGE_20MA != charger.precharging_current) &&
+ (PRE_CHARGE_40MA != charger.precharging_current) &&
+ (PRE_CHARGE_60MA != charger.precharging_current)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (INVALID_PRECHARGE_CURRENT_VALUE);
+ }
+
+ msg.data = clear_bits(msg.data,DA9052_BATCHG_ICHGPRE);
+ msg.data = set_bits(msg.data,
+ precharge_mA_to_reg(charger.precharging_current));
+
+ if(da9052_ssc_write(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+ /* Configure charging_time, battery_target_volt and charger_volt_drop */
+ msg.data = 0;
+
+ if(charger.charging_time > MAX_BAT_CHARGING_TIME) {
+ return (INVALID_CHARGING_TIME);
+ }
+
+ if((BAT_TARGET_VOLTAGE_LOWER_LIMIT > charger.bat_target_voltage) &&
+ (charger.bat_target_voltage > BAT_TARGET_VOLTAGE_UPPER_LIMIT) ){
+ return (INVALID_CHG_BAT_VOLTAGE);
+ }
+
+ if((CHARGER_VOLTAGE_DROP_LOWER_LIMIT > charger.charger_voltage_drop) &&
+ (charger.charger_voltage_drop > CHARGER_VOLTAGE_DROP_UPPER_LIMIT)) {
+ return (INVALID_CHG_VOLTAGE_DROP);
+ }
+ msg.data = (charger.charging_time/CHARGING_TIME_INTERVAL) |
+ bat_mV_to_reg(charger.bat_target_voltage) |
+ bat_drop_mV_to_reg(charger.charger_voltage_drop);
+ msg.addr = DA9052_CHGCONT_REG;
+ if(da9052_ssc_write(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+
+ /* Configure chg_volt_thr, ichg_low and timermode */
+ msg.data = 0;
+
+ if((BAT_VOLTAGE_THRESHOLD_LOWER_LIMIT > charger.voltage_threshold) &&
+ (charger.voltage_threshold > BAT_VOLTAGE_THRESHOLD_UPPER_LIMIT) ){
+ return (INVALID_CHG_VOLTAGE_THRESHOLD);
+ }
+
+ msg.data = vch_thr_mV_to_reg(charger.voltage_threshold) |
+ (charger.ichg_low_cntr ? DA9052_INPUTCONT_ICHGLOW : 0) |
+ (charger.timer_mode ? DA9052_INPUTCONT_TCTRMODE : 0);
+
+ msg.addr = DA9052_INPUTCONT_REG;
+ if(da9052_ssc_write(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+ /* configure charger charging end current */
+
+ msg.data =0;
+ msg.data = (charger.chg_end_current / 4);
+
+ msg.addr = DA9052_ICHGEND_REG;
+ if(da9052_ssc_write(&msg)) {
+ DA9052_DEBUG("%s : failed\n",__FUNCTION__);
+ return (SSC_FAIL);
+ }
+
+ /* Configure charger monitoring frequency and temperature_soft_cntr */
+ chg_device->sw_temp_cntr = charger.sw_temp_cntr;
+ chg_device->monitoring_interval=
+ msecs_to_jiffies(charger.monitoring_interval);
+
+ power_supply_changed(&psy);
+
+ DA9052_DEBUG("FINISHED FUNCTION: %s\n",__FUNCTION__);
+ return (SUCCESS);
+}
+
+/**
+ * da9052_bat_register_event : register the event
+ *
+ * @param u8 event_type event type
+ * @param u8 flag call from user space or kernel space
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_bat_register_event(u8 event_type,u8 flag)
+{
+
+ /* check the event type and according set the event status and
+ callback function pointer*/
+ switch(event_type) {
+ case VDD_LOW_EVE:
+ if (event_status.da9052_event_vddlow == FALSE) {
+ vddlow_eh_data.eve_type = event_type;
+ vddlow_eh_data.call_back =da9052_bat_vddlow_handler;
+ DA9052_DEBUG("events = %d\n",event_type);
+ if(da9052_eh_register_nb(&vddlow_eh_data))
+ return (IRQ_REGISTER_FAILED);
+ event_status.da9052_event_vddlow =TRUE;
+ }
+ break;
+ case TBAT_EVE:
+ if (event_status.da9052_event_tbat == FALSE) {
+ tbat_eh_data.eve_type = event_type;
+ tbat_eh_data.call_back =da9052_bat_tbat_handler;
+ DA9052_DEBUG("events = %d\n",event_type);
+ if(da9052_eh_register_nb(&tbat_eh_data))
+ return (IRQ_REGISTER_FAILED);
+ event_status.da9052_event_tbat =TRUE;
+ }
+ break;
+ case CHG_END_EVE:
+ if(flag) {
+ if (event_status.da9052_event_chgend == FALSE) {
+ chgend_eh_data.eve_type = event_type;
+ chgend_eh_data.call_back =da9052_charging_end_handler;
+ if(da9052_eh_register_nb(&chgend_eh_data))
+ return (IRQ_REGISTER_FAILED);
+ event_status.da9052_event_chgend =TRUE;
+ }
+ }
+ else
+ {
+ user_space_chg_chgend = TRUE;
+ }
+ break;
+ case VBUS_DET_EVE:
+ if(flag){
+ if (event_status.da9052_event_chdet_vbus == FALSE){
+ chgdet_vbus_eh_data.eve_type = event_type;
+ chgdet_vbus_eh_data.call_back =
+ da9052_charger_vbus_detect_handler;
+ if(da9052_eh_register_nb(&chgdet_vbus_eh_data))
+ return (IRQ_REGISTER_FAILED);
+ event_status.da9052_event_chdet_vbus=TRUE;
+ }
+ }
+ else
+ {
+ DA9052_DEBUG("VBUS_DETECT\n");
+ user_space_chg_det_vbus =TRUE;
+ }
+ break;
+ case VBUS_REM_EVE:
+ if(flag) {
+ if (event_status.da9052_event_chrem_vbus == FALSE){
+ chgrem_vbus_eh_data.eve_type = event_type;
+ chgrem_vbus_eh_data.call_back =
+ da9052_charger_vbus_removal_handler;
+ if(da9052_eh_register_nb(&chgrem_vbus_eh_data))
+ return (IRQ_REGISTER_FAILED);
+ event_status.da9052_event_chrem_vbus=TRUE;
+ }
+ }
+ else {
+ user_space_chg_rem_vbus =TRUE;
+ }
+ break;
+ case DCIN_DET_EVE:
+ if(flag){
+ if (event_status.da9052_event_chdet_dcin == FALSE){
+ chgdet_dcin_eh_data.eve_type = event_type;
+ chgdet_dcin_eh_data.call_back =
+ da9052_charger_dcin_detect_handler;
+ if(da9052_eh_register_nb(&chgdet_dcin_eh_data))
+ return (IRQ_REGISTER_FAILED);
+ event_status.da9052_event_chdet_dcin=TRUE;
+ }
+ }
+ else
+ {
+ user_space_chg_det_dcin =TRUE;
+ }
+ break;
+ case DCIN_REM_EVE:
+ if(flag) {
+ if (event_status.da9052_event_chrem_dcin == FALSE){
+ chgrem_dcin_eh_data.eve_type = event_type;
+ chgrem_dcin_eh_data.call_back =
+ da9052_charger_dcin_removal_handler;
+ if(da9052_eh_register_nb(&chgrem_dcin_eh_data))
+ return (IRQ_REGISTER_FAILED);
+ event_status.da9052_event_chrem_dcin=TRUE;
+ }
+ }
+ else {
+ user_space_chg_rem_dcin =TRUE;
+ }
+ break;
+ case DA9030_EVENT_MONITORING_FAIL:
+ montoring_func_reg = TRUE;
+ break;
+ default:
+ return(BAT_INVALID_EVENT);
+ }
+
+ return (SUCCESS);
+}
+
+/**
+ * da9052_bat_unregister_event : register the event
+ *
+ * @param u8 event_type event type
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_bat_unregister_event(u8 event_type,u8 flag)
+{
+ /* check the event type and according clear the event status and set
+ callback function pointer*/
+ DA9052_DEBUG("EVENT = %d\n",event_type);
+ switch(event_type) {
+ case VDD_LOW_EVE:
+ if (event_status.da9052_event_vddlow) {
+ if(da9052_eh_unregister_nb(&vddlow_eh_data))
+ return (IRQ_UNREGISTER_FAILED);
+ event_status.da9052_event_vddlow =FALSE;
+ }
+ break;
+ case TBAT_EVE:
+ if (event_status.da9052_event_tbat) {
+ if(da9052_eh_unregister_nb(&tbat_eh_data))
+ return (IRQ_UNREGISTER_FAILED);
+ event_status.da9052_event_tbat =FALSE;
+ }
+ break;
+ case CHG_END_EVE:
+ if(flag) {
+ if (event_status.da9052_event_chgend) {
+ if(da9052_eh_unregister_nb(&chgend_eh_data))
+ return (IRQ_UNREGISTER_FAILED);
+ event_status.da9052_event_chgend =FALSE;
+ }
+ }
+ else
+ {
+ user_space_chg_chgend = FALSE;
+ }
+ break;
+ case VBUS_DET_EVE:
+ if(flag) {
+ if (event_status.da9052_event_chdet_vbus){
+ if(da9052_eh_unregister_nb(
+ &chgdet_vbus_eh_data))
+ return (IRQ_UNREGISTER_FAILED);
+ event_status.da9052_event_chdet_vbus=FALSE;
+ }
+ }
+ else {
+ user_space_chg_det_vbus =FALSE;
+ }
+ break;
+ case VBUS_REM_EVE:
+ if(flag) {
+ if (event_status.da9052_event_chrem_vbus){
+ if(da9052_eh_unregister_nb(
+ &chgrem_vbus_eh_data))
+ return (IRQ_UNREGISTER_FAILED);
+ event_status.da9052_event_chrem_vbus=FALSE;
+ }
+ }
+ else {
+ user_space_chg_rem_vbus =FALSE;
+ }
+ break;
+ case DCIN_DET_EVE:
+ if(flag) {
+ if (event_status.da9052_event_chdet_dcin){
+ if(da9052_eh_unregister_nb(
+ &chgdet_dcin_eh_data))
+ return (IRQ_UNREGISTER_FAILED);
+ event_status.da9052_event_chdet_dcin=FALSE;
+ }
+ }
+ else {
+ user_space_chg_det_dcin =FALSE;
+ }
+ break;
+ case DCIN_REM_EVE:
+ if(flag) {
+ if (event_status.da9052_event_chrem_dcin){
+ if(da9052_eh_unregister_nb(
+ &chgrem_dcin_eh_data))
+ return (IRQ_UNREGISTER_FAILED);
+ event_status.da9052_event_chrem_dcin=FALSE;
+ }
+ }
+ else {
+ user_space_chg_rem_dcin =FALSE;
+ }
+ break;
+ case DA9030_EVENT_MONITORING_FAIL:
+ montoring_func_reg = FALSE;
+ break;
+ default:
+ return(BAT_INVALID_EVENT);
+ }
+
+
+
+ return (SUCCESS);
+}
+
+/*--------------------------------------------------------------------------*/
+/* Infrastructure Functions */
+/*--------------------------------------------------------------------------*/
+
+/*
+ * da9052_bat_sw_init: Allocate memory and Initialise global sturcture
+ *
+ * @param dev platofrm device structure
+ * @return s32 Error status 0:SUCCESS, Non Zero: Error
+ */
+s32 da9052_bat_sw_init(struct platform_device *pdev)
+{
+ da9052_ssc_msg msg;
+
+ DA9052_DEBUG(" FUNCTION : %s\n",__FUNCTION__);
+
+ chg_device = (da9052_charger_device*) kmalloc(
+ sizeof(da9052_charger_device),GFP_KERNEL);
+ if(chg_device == NULL) {
+ DA9052_DEBUG("Memory Allocation Failed for chg_device \
+ structure in %s\n",__FUNCTION__);
+ return (ENOMEM);
+ }
+
+ /* Global Varaiable initialization */
+ bat_hysteresis.upper_limit = 0;
+ bat_hysteresis.lower_limit = 0;
+
+ event_status.da9052_event_vddlow = FALSE;
+ event_status.da9052_event_tbat = FALSE;
+ event_status.da9052_event_chgend = FALSE;
+ event_status.da9052_event_chdet_dcin = FALSE;
+ event_status.da9052_event_chrem_dcin = FALSE;
+ event_status.da9052_event_chdet_vbus = FALSE;
+ event_status.da9052_event_chrem_vbus = FALSE;
+ user_space_chg_det_dcin = FALSE;
+ user_space_chg_rem_dcin = FALSE;
+ user_space_chg_det_vbus = FALSE;
+ user_space_chg_rem_vbus = FALSE;
+ user_space_chg_chgend = FALSE;
+
+ /*Static configuration for the Battery charger*/
+ chg_device->monitoring_interval = msecs_to_jiffies(MONITORING_INTERVAL);
+ chg_device->sw_temp_cntr = SW_TEMP_CONTROL_EN;
+ chg_device->usb_charger_current = 0;
+
+ bat_status.charger_type = NOCHARGER;
+ b