Added a worker function to monitor status if any fault conditions like
Over Voltage, Over Temperature, etc.. happens.
And removed most of the code from threaded IRQ function and improved exception 
handling code.


Signed-off-by: Ramakrishna Pallala <[email protected]>

--- drivers/power/intel_mdf_battery-Emrg-Chrg.c 2010-11-27 04:49:49.885435111 
+0530
+++ drivers/power/intel_mdf_battery.c   2010-11-27 04:55:35.951194000 +0530
@@ -190,6 +190,27 @@
 #define MSIC_BATT_ADC_CHRGNG_MASK      (1 << 31)
 #define MSIC_BATT_ADC_ACCCHRGVAL_MASK   0x7FFFFFFF
 
+#define CHR_STATUS_FLULT_REG   0x37D
+#define CHR_STATUS_TMR_RST     (1 << 7)
+#define CHR_STATUS_VOTG_ENBL   (1 << 7)
+#define CHR_STATUS_STAT_ENBL   (1 << 6)
+
+#define CHR_STATUS_BIT_MASK    0x30
+#define CHR_STATUS_BIT_READY   0x0
+#define CHR_STATUS_BIT_PROGRESS        0x1
+#define CHR_STATUS_BIT_CYCLE   0x2
+#define CHR_STATUS_BIT_FAULT   0x3
+
+#define CHR_FAULT_BIT_MASK     0x7
+#define CHR_FAULT_BIT_NORMAL   0x0
+#define CHR_FAULT_BIT_VBUS_OVP 0x1
+#define CHR_FAULT_BIT_SLEEP    0x2
+#define CHR_FAULT_BIT_LOW_VBUS 0x3
+#define CHR_FAULT_BIT_BATT_OVP 0x4
+#define CHR_FAULT_BIT_THRM     0x5
+#define CHR_FAULT_BIT_TIMER    0x6
+#define CHR_FAULT_BIT_NO_BATT  0x7
+
 /*
  * Convert the voltage form decimal to
  * Register writable format
@@ -214,6 +235,7 @@
 #define IPCMSG_BATTERY         0xEF
 
 #define TEMP_CHARGE_DELAY_JIFFIES      (HZ * 30)       /*30 sec */
+#define CHARGE_STATUS_DELAY_JIFFIES    (HZ * 10)       /*10 sec */
 
 #define IRQ_FIFO_MAX           16
 #define THERM_CURVE_MAX_SAMPLES 7
@@ -231,6 +253,9 @@ enum msic_event {
        MSIC_EVENT_ADPOVP_EXCPT,
        MSIC_EVENT_CHROTP_EXCPT,
        MSIC_EVENT_USBOVP_EXCPT,
+       MSIC_EVENT_USB_VINREG_EXCPT,
+       MSIC_EVENT_WEAKVIN_EXCPT,
+       MSIC_EVENT_TIMEEXP_EXCPT,
 };
 
 /* Valid Charging modes */
@@ -401,6 +426,9 @@ struct msic_power_module_info {
        int charging_mode;
        int emrg_chrg_enbl;     /* Emergency call charge enable */
 
+       /* Worker to monitor status and faluts */
+       struct delayed_work chr_status_monitor;
+
        /* lock to avoid concurrent  access to HW Registers.
         * As some chargeer control and parameter registers
         * can be read or write at same time, ipc_rw_lock lock
@@ -810,6 +838,7 @@ static unsigned int msic_read_coloumb_ct
        err = intel_scu_ipc_command(IPCMSG_BATTERY, 0x01, NULL, 0, &cvalue, 1);
        if (err)
                dev_warn(msic_dev, "IPC Command Failed %s\n", __func__);
+
        return cvalue;
 }
 static unsigned int cc_to_coloumbs(unsigned int cc_val)
@@ -1060,6 +1089,18 @@ static void msic_log_exception_event(enu
        case MSIC_EVENT_USBOVP_EXCPT:
                dev_warn(msic_dev, "USB over voltage condition detected\n");
                break;
+       case MSIC_EVENT_USB_VINREG_EXCPT:
+               dev_warn(msic_dev, "USB Input voltage regulation "
+                                               "condition detected\n");
+               break;
+       case MSIC_EVENT_WEAKVIN_EXCPT:
+               dev_warn(msic_dev, "USB Weak VBUS volatge "
+                                               "condition detected\n");
+               break;
+       case MSIC_EVENT_TIMEEXP_EXCPT:
+               dev_warn(msic_dev, "Charger Total Time Expiration "
+                                               "condition detected\n");
+               break;
        default:
                dev_warn(msic_dev, "unknown error %u detected\n", event);
                break;
@@ -1077,52 +1118,40 @@ static void msic_handle_exception(struct
                uint8_t CHRINT_reg_value, uint8_t CHRINT1_reg_value)
 {
        enum msic_event exception;
-       uint8_t chrint_reg_value, chrint1_reg_value;
 
-       chrint_reg_value = CHRINT_reg_value;
-       chrint1_reg_value = CHRINT1_reg_value;
-
-       /* Battery Exceptions */
+       /* Battery Events */
        mutex_lock(&mbi->batt_lock);
-       if (chrint_reg_value & MSIC_BATT_CHR_BATTOCP_MASK) {
+       if (CHRINT_reg_value & MSIC_BATT_CHR_BATTOCP_MASK) {
                exception = MSIC_EVENT_BATTOCP_EXCPT;
-               mbi->batt_props.status = POWER_SUPPLY_STATUS_NOT_CHARGING;
                msic_log_exception_event(exception);
        }
 
-       if (chrint1_reg_value & MSIC_BATT_CHR_BATTOTP_MASK) {
-               mbi->batt_props.status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+       if (CHRINT_reg_value & MSIC_BATT_CHR_BATTOTP_MASK) {
                mbi->batt_props.health = POWER_SUPPLY_HEALTH_OVERHEAT;
-
                exception = MSIC_EVENT_BATTOTP_EXCPT;
                msic_log_exception_event(exception);
        }
 
        if (CHRINT_reg_value & MSIC_BATT_CHR_LOWBATT_MASK) {
+               mbi->batt_props.health = POWER_SUPPLY_HEALTH_DEAD;
                exception = MSIC_EVENT_LOWBATT_EXCPT;
                msic_log_exception_event(exception);
        }
+       if (CHRINT_reg_value & MSIC_BATT_CHR_TIMEEXP_MASK) {
+               exception = MSIC_EVENT_TIMEEXP_EXCPT;
+               msic_log_exception_event(exception);
+       }
 
        if (CHRINT1_reg_value & MSIC_BATT_CHR_BATTOVP_MASK) {
-               mbi->batt_props.status = POWER_SUPPLY_STATUS_NOT_CHARGING;
                mbi->batt_props.health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
-
                exception = MSIC_EVENT_BATTOVP_EXCPT;
                msic_log_exception_event(exception);
        }
        mutex_unlock(&mbi->batt_lock);
 
-
+       /* Charger Events */
        mutex_lock(&mbi->usb_chrg_lock);
-       /* Charger exceptions */
        if (CHRINT1_reg_value & MSIC_BATT_CHR_CHROTP_MASK) {
-               mbi->usb_chrg_props.charger_health =
-                                               POWER_SUPPLY_HEALTH_OVERHEAT;
-
-               mutex_lock(&mbi->batt_lock);
-               mbi->batt_props.status = POWER_SUPPLY_STATUS_NOT_CHARGING;
-               mutex_unlock(&mbi->batt_lock);
-
                exception = MSIC_EVENT_CHROTP_EXCPT;
                msic_log_exception_event(exception);
        }
@@ -1130,16 +1159,32 @@ static void msic_handle_exception(struct
        if (CHRINT1_reg_value & MSIC_BATT_CHR_USBOVP_MASK) {
                mbi->usb_chrg_props.charger_health =
                                                POWER_SUPPLY_HEALTH_OVERVOLTAGE;
-
-               mutex_lock(&mbi->batt_lock);
-               mbi->batt_props.status = POWER_SUPPLY_STATUS_NOT_CHARGING;
-               mutex_unlock(&mbi->batt_lock);
-
                exception = MSIC_EVENT_USBOVP_EXCPT;
                msic_log_exception_event(exception);
        }
+       if (CHRINT1_reg_value & MSIC_BATT_CHR_WKVINDET_MASK) {
+               mbi->usb_chrg_props.charger_health =
+                                               POWER_SUPPLY_HEALTH_DEAD;
+               exception = MSIC_EVENT_WEAKVIN_EXCPT;
+               msic_log_exception_event(exception);
+       }
+       if (CHRINT1_reg_value & MSIC_BATT_CHR_VINREGMINT_MASK) {
+               mbi->usb_chrg_props.charger_health =
+                                               POWER_SUPPLY_HEALTH_DEAD;
+               exception = MSIC_EVENT_USB_VINREG_EXCPT;
+               msic_log_exception_event(exception);
+       }
        mutex_unlock(&mbi->usb_chrg_lock);
 
+       if (CHRINT1_reg_value || (CHRINT_reg_value &
+                               ~(MSIC_BATT_CHR_LOWBATT_MASK))) {
+               mutex_lock(&mbi->batt_lock);
+               if ((mbi->batt_props.status == POWER_SUPPLY_STATUS_CHARGING) ||
+                       (mbi->batt_props.status == POWER_SUPPLY_STATUS_FULL))
+                       mbi->batt_props.status =
+                                       POWER_SUPPLY_STATUS_NOT_CHARGING;
+               mutex_unlock(&mbi->batt_lock);
+       }
 }
 
 /**
@@ -1599,6 +1644,86 @@ static int msic_charger_callback(void *a
 }
 
 /**
+ * msic_status_monitor - worker function to monitor status
+ * @work: delayed work handler structure
+ * Context: Can sleep
+ *
+ * Will be called from the threaded IRQ function.
+ * Monitors status of the charge register and temperature.
+ */
+static void msic_status_monitor(struct work_struct *work)
+{
+       uint8_t data;
+       int retval, val, volt, temp;
+       struct msic_power_module_info *mbi = container_of(work,
+                       struct msic_power_module_info, chr_status_monitor.work);
+
+       retval = intel_scu_ipc_ioread8(CHR_STATUS_FLULT_REG, &data);
+       if (retval) {
+               dev_warn(msic_dev, "%s:ipc read failed\n", __func__);
+               return ;
+       }
+
+       /* Check Fluts bits in Status Register */
+       val = (data & CHR_STATUS_BIT_MASK) >> 4;
+       if (val == CHR_STATUS_BIT_FAULT) {
+               dev_dbg(msic_dev, "chr status regisrer:%x\n", data);
+               schedule_delayed_work(&mbi->chr_status_monitor,
+                                       CHARGE_STATUS_DELAY_JIFFIES);
+               return ;
+       }
+
+       /* Compute Charger health */
+       mutex_lock(&mbi->usb_chrg_lock);
+       if (mbi->usb_chrg_props.charger_health != POWER_SUPPLY_HEALTH_GOOD)
+               mbi->usb_chrg_props.charger_health = POWER_SUPPLY_HEALTH_GOOD;
+       mutex_unlock(&mbi->usb_chrg_lock);
+
+       /* Compute Battery health */
+       mutex_lock(&mbi->batt_lock);
+       if (mbi->batt_props.health == POWER_SUPPLY_HEALTH_OVERHEAT) {
+               temp = mdf_read_adc_regs(MSIC_ADC_TEMP_IDX, mbi);
+               dev_dbg(msic_dev, "temp in millC :%d\n", temp);
+               /*
+                * Valid temperature window is 0 to 60 Degrees
+                * and thermister has 2 drgee hysteris and considering
+                * 2 degree adc error, fault revert temperature will
+                * be 4 to 56 degrees. These vaules will be fine tuned later.
+                */
+               if (temp >= (MSIC_BATT_TEMP_MAX - MSIC_TEMP_HYST_ERR) ||
+                       temp <= (MSIC_BATT_TEMP_MIN + MSIC_TEMP_HYST_ERR)) {
+                       schedule_delayed_work(&mbi->chr_status_monitor,
+                                               CHARGE_STATUS_DELAY_JIFFIES);
+                       mutex_unlock(&mbi->batt_lock);
+                       return ;
+               }
+       }
+
+       spin_lock(&mbi->event_lock);
+       if (mbi->charging_mode == BATT_CHARGING_MODE_MAINTAINENCE)
+               mbi->batt_props.status = POWER_SUPPLY_STATUS_FULL;
+       else if (mbi->charging_mode == BATT_CHARGING_MODE_NORMAL)
+               mbi->batt_props.status = POWER_SUPPLY_STATUS_CHARGING;
+       else if (mbi->batt_event == USBCHRG_EVENT_SUSPEND)
+               mbi->batt_props.status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+       else
+               mbi->batt_props.status = POWER_SUPPLY_STATUS_DISCHARGING;
+       spin_unlock(&mbi->event_lock);
+
+       if (mbi->batt_props.health == POWER_SUPPLY_HEALTH_DEAD) {
+               volt = mdf_read_adc_regs(MSIC_ADC_VOL_IDX, mbi);
+               dev_dbg(msic_dev, "low vol in mV :%d\n", volt);
+               if (volt < BATT_LOWBATT_CUTOFF_VOLT) {
+                       schedule_delayed_work(&mbi->chr_status_monitor,
+                                               CHARGE_STATUS_DELAY_JIFFIES);
+                       mutex_unlock(&mbi->batt_lock);
+                       return ;
+               }
+       }
+       mbi->batt_props.health = POWER_SUPPLY_HEALTH_GOOD;
+       mutex_unlock(&mbi->batt_lock);
+}
+/**
  * msic_battery_interrupt_handler - msic battery interrupt handler
  * Context: interrupt context
  *
@@ -1638,8 +1763,7 @@ static irqreturn_t msic_battery_interrup
  */
 static irqreturn_t msic_battery_thread_handler(int id, void *dev)
 {
-       int err, ret;
-       uint32_t batt_charge_val;
+       int ret;
        unsigned char data[2];
        struct msic_power_module_info *mbi = dev;
        u32 tmp;
@@ -1668,67 +1792,14 @@ static irqreturn_t msic_battery_thread_h
        dev_dbg(msic_dev, "CHR Int %x %x\n", data[0], data[1]);
 
        /* Check if charge complete */
-       if (data[1] & MSIC_BATT_CHR_CHRCMPLT_MASK) {
+       if (data[1] & MSIC_BATT_CHR_CHRCMPLT_MASK)
                dev_dbg(msic_dev, "CHRG COMPLT\n");
-               /* Disable Charging */
-               msic_batt_stop_charging(mbi);
-
-               spin_lock(&mbi->event_lock);
-               mbi->charging_mode = BATT_CHARGING_MODE_MAINTAINENCE;
-               spin_unlock(&mbi->event_lock);
-
-
-               err = intel_scu_ipc_command(IPCMSG_BATTERY, 0x01, NULL,
-                                                0, &batt_charge_val, 1);
-               mutex_lock(&mbi->batt_lock);
-               if (!err)
-                       mbi->batt_props.charge_full = batt_charge_val;
-               mbi->batt_props.status = POWER_SUPPLY_STATUS_FULL;
-               mutex_unlock(&mbi->batt_lock);
-
-       }
-
-       if ((data[1] & MSIC_BATT_CHR_WKVINDET_MASK) ||
-               (data[1] & MSIC_BATT_CHR_VINREGMINT_MASK)) {
-
-               dev_dbg(msic_dev, "WEAK VIN or VINREGMINT DETCTED\n");
-
-               spin_lock(&mbi->event_lock);
-               /* Sometimes we may get weakVIN because of VBUS voltage
-                * drops even though there is no charger connected.
-                * So before we suspend the device check for the
-                * battery connection.
-                */
-               if (mbi->batt_event != USBCHRG_EVENT_SUSPEND ||
-                       mbi->batt_event != USBCHRG_EVENT_DISCONN) {
-                       spin_unlock(&mbi->event_lock);
-                       /* In case of weakVIN the device can not recover from
-                        * low voltage level.So its better to disconnect the
-                        * charger and reconnect it again. From driver point
-                        * of view we will just suspend the device.
-                        */
-                       msic_charger_callback(mbi, USBCHRG_EVENT_SUSPEND, NULL);
-               } else {
-                       spin_unlock(&mbi->event_lock);
-                       dev_dbg(msic_dev, "WeakVIN when No charger preset\n");
-               }
-       }
-
-       /* Check if total charge time expired */
-       if (data[0] & MSIC_BATT_CHR_TIMEEXP_MASK) {
-               dev_dbg(msic_dev, "CHR TIMER EXP\n");
-               mutex_lock(&mbi->batt_lock);
-               mbi->batt_props.status = POWER_SUPPLY_STATUS_NOT_CHARGING;
-               mutex_unlock(&mbi->batt_lock);
-       }
 
        /* Check if an exception occured */
-       if ((data[0] & ~MSIC_BATT_CHR_TIMEEXP_MASK) ||
-               (data[1] & ~(MSIC_BATT_CHR_CHRCMPLT_MASK |
-                       MSIC_BATT_CHR_WKVINDET_MASK |
-                       MSIC_BATT_CHR_VINREGMINT_MASK))) {
-
+       if (data[0] || (data[1] & ~(MSIC_BATT_CHR_CHRCMPLT_MASK))) {
                msic_handle_exception(mbi, data[0], data[1]);
+               schedule_delayed_work(&mbi->chr_status_monitor,
+                                       CHARGE_STATUS_DELAY_JIFFIES);
        }
 
        return IRQ_HANDLED;
@@ -1878,6 +1949,12 @@ static void init_batt_props(struct msic_
        else
                mbi->batt_props.present = MSIC_BATT_NOT_PRESENT;
 
+       /* Enable Status Register */
+       retval = intel_scu_ipc_iowrite8(CHR_STATUS_FLULT_REG,
+                               CHR_STATUS_TMR_RST | CHR_STATUS_STAT_ENBL);
+       if (retval)
+               dev_warn(&mbi->pdev->dev, "%s:ipc r/w failed\n", __func__);
+
 }
 
 /**
@@ -1974,6 +2051,7 @@ static int msic_battery_probe(struct pla
         */
        INIT_DELAYED_WORK(&mbi->disconn_handler, msic_batt_disconn);
        INIT_DELAYED_WORK(&mbi->connect_handler, msic_batt_temp_charging);
+       INIT_DELAYED_WORK(&mbi->chr_status_monitor, msic_status_monitor);
 
 
        /* Initialize the spin locks */


Attachment: 003-Intel-MFLD-Battery-Driver-Status-Monitoring.patch
Description: 003-Intel-MFLD-Battery-Driver-Status-Monitoring.patch

_______________________________________________
MeeGo-kernel mailing list
[email protected]
http://lists.meego.com/listinfo/meego-kernel

Reply via email to