static void pwrbutton_work_func(struct work_struct *work) { u8 value = 0; /* Switch off LED if it's not connected to USB */ if (!twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &value, 0x03) && !(value & (1 << 2))) { omap4430_orange_led_set(NULL, 0); omap4430_green_led_set(NULL, 0); } // wake_unlock(&pwrbutton_wakelock); }
static ssize_t disable_led_store(struct device *dev, struct device_attribute *attr, const char *buffer, size_t size) { struct bq27541_info *di = i2c_get_clientdata(to_i2c_client(dev)); unsigned long value = simple_strtoul(buffer, NULL, 0); if (value == 0) { di->disable_led = 0; } else if (value == 1) { di->disable_led = 1; omap4430_green_led_set(NULL, 0); omap4430_orange_led_set(NULL, 0); } return size; }
static int twl4030_pwrbutton_resume(struct platform_device *pdev) { int err; u8 value; int press; struct input_dev *pwr = platform_get_drvdata(pdev); g_in_suspend=0; err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value,REG_STS_HW_CONDITIONS); press = (value & PWR_PWRON_IRQ) ? STATE_RELEASE : STATE_PRESS; if(press) { prev_press = STATE_PRESS; input_report_key(pwr, KEY_POWER, 1); input_report_key(pwr, KEY_POWER, 0); input_sync(pwr); //Turn green LED on immediately at full intensity and keep on for 2 seconds and then turn off if (!twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &value, 0x03) && !(value & (1 << 2))) { /* If it's not connected to USB, blink */ omap4430_orange_led_set(NULL, 0); omap4430_green_led_set(NULL, 255); } } return 0; }
static irqreturn_t powerbutton_irq(int irq, void *_pwr) { struct input_dev *pwr = _pwr; int err; u8 value; err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value,REG_STS_HW_CONDITIONS); if (!err) { char buf[128]; int press = (value & PWR_PWRON_IRQ) ? STATE_RELEASE : STATE_PRESS; char *action = press ? "press" : "release"; input_report_key(pwr, KEY_POWER, press); input_sync(pwr); sprintf(buf, "%s:powi%c:action=%s:", __func__, action[0], action); log_to_metrics(ANDROID_LOG_INFO, "PowerKeyEvent", buf); strcat(buf, "\n"); printk(buf); if(press != prev_press) { if(press) { prev_press = STATE_PRESS; } else { prev_press = STATE_RELEASE; /* Check if we are connected to USB */ if (!twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &value, 0x03) && !(value & (1 << 2))) { /* * No USB, hold a partial wakelock, * scheduled a work 2 seconds later * to switch off the LED */ wake_lock_timeout(&pwrbutton_wakelock, 3*HZ); cancel_delayed_work_sync(&pwrbutton_work); omap4430_orange_led_set(NULL, 0); omap4430_green_led_set(NULL, 255); schedule_delayed_work(&pwrbutton_work, HZ*2); } } }else{ if(g_in_suspend==1){ wake_lock(&pwrbutton_wakelock); input_report_key(pwr, KEY_POWER, 1); input_report_key(pwr, KEY_POWER, 0); input_sync(pwr); omap4430_orange_led_set(NULL, 0); omap4430_green_led_set(NULL, 255); schedule_delayed_work(&pwrbutton_work, msecs_to_jiffies(2000)); } } } else { dev_err(pwr->dev.parent, "twl4030: i2c error %d while reading" " TWL4030 PM_MASTER STS_HW_CONDITIONS register\n", err); /* If an error occurs we don't want to display the SysReq the next time user will * push and release power button. */ prev_press = STATE_UNKNOWN; } return IRQ_HANDLED; }
void summit_fsm_doAction(struct summit_smb347_info *di,int event) { int state=di->current_state; int temp=0; u32 value; int config,command=0; u8 pre_protect_event=0; switch (state){ case STATE_SUSPEND: if(event==USB_EVENT_NONE){ di->usb_online=0; di->ac_online=0; power_supply_changed(&di->usb); power_supply_changed(&di->ac); summit_charge_reset(di); /* * Turn off LEDs when USB is unplugged, * this is safe when the battery is already * discharging or full. There's no way * the battery is being charged when USB * is not connected. */ omap4430_green_led_set(NULL, 0); omap4430_orange_led_set(NULL, 0); CLEAR_BAT_FULL(di->protect_event); //enable low battery interrupt summit_enable_stat_interrupt(di,LOW_BATTERY_TRIGGER_IRQ); /* * Hold the wake lock, and schedule a delayed work * to release it in 1 second */ wake_lock(&di->chrg_lock); schedule_delayed_work(&di->disconnect_work, msecs_to_jiffies(1000)); } break; break; case STATE_INIT: if(event==USB_EVENT_DETECT_SOURCE){ /* * Cancel the scheduled delayed work that * releases the wakelock */ cancel_delayed_work_sync(&di->disconnect_work); di->fake_disconnect=0; if(di->mbid!=0){ temp=-1; config=i2c_smbus_read_byte_data(di->client,SUMMIT_SMB347_STAT_TIMERS); if(IS_BIT_CLEAR(config,5)){//The detect need to be redo again. dev_info(di->dev,"Redo apsd\n"); //disable stat summit_write_config(di,1); config=i2c_smbus_read_byte_data(di->client,SUMMIT_SMB347_STAT_TIMERS); SET_BIT(config,5); i2c_smbus_write_byte_data(di->client,SUMMIT_SMB347_STAT_TIMERS,config); summit_write_config(di,0); summit_config_apsd(di,0); summit_config_apsd(di,1); queue_delayed_work_on(0,summit_work_queue,&di->summit_check_work,msecs_to_jiffies(2000)); }else{//The detect has already done in u-boot dev_info(di->dev,"The detect has already done in u-boot\n"); temp=summit_get_apsd_result(di); writeIntoCBuffer(&di->events,temp); queue_delayed_work_on(0,summit_work_queue,&di->summit_monitor_work,0); } } summit_charger_reconfig(di); summit_config_time_protect(di,1); //reload the protection setting if(IS_ADJUST_CURRENT_VOLTAGE_ENABLE(di->protect_enable) && di->mbid>=4){ summit_adjust_charge_current(di,event); } if(pre_protect_event!=di->protect_event && di->mbid>=4){ summit_protection(di); } } if(event==EVENT_APSD_COMPLETE){ writeIntoCBuffer(&di->events,summit_get_apsd_result(di)); queue_delayed_work_on(0,summit_work_queue,&di->summit_monitor_work,0); } break; case STATE_ONDEMAND: summit_charge_reset(di); break; case STATE_PC: if(event==EVENT_DETECT_PC){ blocking_notifier_call_chain(&di->xceiv->notifier,USB_EVENT_VBUS, di->xceiv->gadget); di->usb_online=1; di->ac_online=0; power_supply_changed(&di->usb); power_supply_changed(&di->ac); } break; case STATE_CD: if(event==USB_EVENT_HOST_CHARGER){ if(di->mbid==0){ summit_switch_mode(di,HC_MODE); } di->usb_online=1; di->ac_online=0; power_supply_changed(&di->usb); power_supply_changed(&di->ac); blocking_notifier_call_chain(&di->xceiv->notifier,USB_EVENT_VBUS, di->xceiv->gadget); } break; case STATE_PC_100: summit_switch_mode(di,USB1_OR_15_MODE); di->usb_online=1; di->ac_online=0; power_supply_changed(&di->usb); power_supply_changed(&di->ac); break; //summit bug: if enable charge,then vbus always exits. case STATE_PC_500: if(event==USB_EVENT_LIMIT_500){ summit_switch_mode(di,USB5_OR_9_MODE); if(di->mbid==0){//summit bug: if enable charge,then vbus always exits. if((di->protect_enable==1 && di->protect_event==0) || di->protect_enable==0) summit_charge_enable(di,1); } di->usb_online=1; di->ac_online=0; power_supply_changed(&di->usb); power_supply_changed(&di->ac); } break; case STATE_OTHER://It will switch to usb5 mode,so need to switch hc mode. if(event==EVENT_DETECT_OTHER){ if(di->mbid==0){ summit_switch_mode(di,HC_MODE); if((di->protect_enable==1 && di->protect_event==0) || di->protect_enable==0) summit_charge_enable(di,1); }else{ summit_write_config(di,1); config=i2c_smbus_read_byte_data(di->client,SUMMIT_SMB347_ENABLE_CONTROL); command&=~(0x1<<(4)); i2c_smbus_write_byte_data(di->client,SUMMIT_SMB347_ENABLE_CONTROL,config); summit_write_config(di,0); summit_switch_mode(di,HC_MODE); } di->usb_online=0; di->ac_online=1; power_supply_changed(&di->usb); power_supply_changed(&di->ac); } //Some PC get a usb port that was detected by Other charger //if(event==EVENT_AICL_COMPLETE) // blocking_notifier_call_chain(&di->xceiv->notifier,USB_EVENT_VBUS, di->xceiv->gadget); break; case STATE_DC: if(event==USB_EVENT_CHARGER){ if(di->mbid==0){ summit_switch_mode(di,HC_MODE); } di->usb_online=0; di->ac_online=1; power_supply_changed(&di->usb); power_supply_changed(&di->ac); } break; case STATE_UC: if(event==EVENT_DETECT_TBD){ if(di->mbid==0){ summit_switch_mode(di,HC_MODE); if((di->protect_enable==1 && di->protect_event==0) || di->protect_enable==0) summit_charge_enable(di,1); } di->usb_online=0; di->ac_online=1; power_supply_changed(&di->usb); power_supply_changed(&di->ac); } break; } pre_protect_event=di->protect_event; switch(event){ case EVENT_FULL_BATTERY: SET_BAT_FULL(di->protect_event); break; case EVENT_RECHARGE_BATTERY: CLEAR_BAT_FULL(di->protect_event); break; case EVENT_BATTERY_I2C_ERROR: SET_BAT_I2C_FAIL(di->protect_event); break; case EVENT_BATTERY_I2C_NORMAL: CLEAR_BAT_I2C_FAIL(di->protect_event); break; case EVENT_NOT_RECOGNIZE_BATTERY: SET_BAT_NOT_RECOGNIZE(di->protect_event); break; case EVENT_RECOGNIZE_BATTERY: CLEAR_BAT_NOT_RECOGNIZE(di->protect_event); break; case EVENT_BATTERY_NTC_ZERO: SET_BAT_NTC_ERR(di->protect_event); break; case EVENT_BATTERY_NTC_NORMAL: CLEAR_BAT_NTC_ERR(di->protect_event); break; case EVENT_WEAK_BATTERY: SET_BAT_TOO_WEAK(di->protect_event); break; case EVENT_TEMP_PROTECT_STEP_2:// -20 < temp < 0 Stop Charge SET_BAT_TOO_COLD_FOR_CHARGE(di->protect_event); break; case EVENT_TEMP_PROTECT_STEP_1:// temp < -20 Stop Discharge SET_BAT_TOO_COLD_FOR_DISCHARGE(di->protect_event); break; case EVENT_TEMP_PROTECT_STEP_8:// 60 > temp SET_BAT_TOO_HOT_FOR_CHARGE(di->protect_event); break; case EVENT_TEMP_PROTECT_STEP_3: case EVENT_TEMP_PROTECT_STEP_4: case EVENT_TEMP_PROTECT_STEP_5: case EVENT_TEMP_PROTECT_STEP_6: case EVENT_TEMP_PROTECT_STEP_7: CLEAR_BAT_TOO_COLD_FOR_CHARGE(di->protect_event); CLEAR_BAT_TOO_COLD_FOR_DISCHARGE(di->protect_event); CLEAR_BAT_TOO_HOT_FOR_CHARGE(di->protect_event); di->bat_thermal_step=event; if(IS_ADJUST_CURRENT_VOLTAGE_ENABLE(di->protect_enable) && di->mbid>=4){ summit_adjust_charge_current(di,event); } break; } if( (pre_protect_event!=di->protect_event && di->mbid>=4 ) || (event==EVENT_RECHECK_PROTECTION)){ if(event==EVENT_RECHECK_PROTECTION) summit_adjust_charge_current(di,di->bat_thermal_step); summit_protection(di); }else if(di->mbid<4){ summit_charge_enable(di,1); } }
void bat_monitor_work_func(struct work_struct *work) { struct bq27541_info *di = container_of(work, struct bq27541_info, bat_monitor_work.work); int err = 0; int new_value=0; int change=0; //For dead battery if(di->err_count>=15){ printk("bat:%s get i2c error\n",__func__); err=bq27x00_battery_voltage(di,&new_value); if (err){ queue_delayed_work(bat_work_queue,&di->bat_monitor_work, msecs_to_jiffies(10000 * 1)); blocking_notifier_call_chain(¬ifier_list, EVENT_BATTERY_I2C_ERROR, NULL); di->health = POWER_SUPPLY_HEALTH_UNKNOWN; power_supply_changed(&di->bat); }else{//dead battery is wake up printk("bat:%s dead battery is wake up\n",__func__); di->err_count=0; queue_delayed_work(bat_work_queue,&di->bat_monitor_work,0); blocking_notifier_call_chain(¬ifier_list, EVENT_BATTERY_I2C_NORMAL, NULL); di->health = POWER_SUPPLY_HEALTH_GOOD; power_supply_changed(&di->bat); } }else{ /* * We query the four most important variables frequently: * * temperature, voltage, capacity, status * * These four are used by various code in upper layers for * power management. The rest of the variables are not that * important or do not change much over time so we do not * need to query them too often */ if (bq27x00_battery_temperature(di, &new_value)) { di->err_count++; } else { if (new_value != di->temp) { di->temp = new_value; change = 1; bat_temp_charge_protect(di); } } if (bq27x00_battery_voltage(di, &new_value)) { di->err_count++; } else { if (new_value != di->voltage) { di->voltage = new_value; change = 1; //Low battery protection //If android with weak battery has some problem and not be shutdown then driver need to turn off the system. if((di->voltage <= HARD_LOW_VOLTAGE_THRESHOLD) && (di->status==POWER_SUPPLY_STATUS_DISCHARGING)) blocking_notifier_call_chain(¬ifier_list, EVENT_WEAK_BATTERY, NULL); } } if (bq27x00_battery_rsoc(di, &new_value)) { di->err_count++; } else { if (new_value != di->capacity) { di->capacity = new_value; change = 1; //Recharge event if((di->status==POWER_SUPPLY_STATUS_NOT_CHARGING) && (di->capacity<=RECHARGE_THRESHOLD)) blocking_notifier_call_chain(¬ifier_list, EVENT_RECHARGE_BATTERY, NULL); } } if (bq27x00_battery_status(di, &new_value)) { di->err_count++; } else { if (new_value!=di->status) { di->status = new_value; change = 1; //Full charge protectition event if (di->status == POWER_SUPPLY_STATUS_FULL) blocking_notifier_call_chain(¬ifier_list, EVENT_FULL_BATTERY, NULL); } } /* * Average current is also required to be * queried frequently for factory testing */ if (bq27x00_battery_current(di, &new_value)){ di->err_count++; } else { if (new_value != di->current_avg) { di->current_avg=new_value; change = 1; } } if (++di->long_count != BQ27541_LONG_COUNT) { /* Done with the important ones, skip the rest for now */ goto update_status; } else { di->long_count = 0; } new_value=twl_get_batntc(); if(new_value!=di->ntc_temp){ if((di->ntc_temp==0) && (new_value>0)) blocking_notifier_call_chain(¬ifier_list, EVENT_BATTERY_NTC_NORMAL, NULL); di->ntc_temp=new_value; if(di->ntc_temp==0) blocking_notifier_call_chain(¬ifier_list, EVENT_BATTERY_NTC_ZERO, NULL); } bq27x00_read(REG_FULL_AVAILABLE_CHARGE, &g_full_available_capacity, 0, di); if (bq27x00_battery_health(di, &new_value)) { di->err_count++; } else { if (new_value != di->health) { di->health = new_value; change = 1; } } /* Query TimeToEmpty() register */ if (bq27x00_battery_time_to_empty(di, &new_value)) { di->err_count++; } else if (new_value != di->time_to_empty) { di->time_to_empty = new_value; change = 1; } /* Query TimeToFull() register */ if (bq27x00_battery_time_to_full(di, &new_value)) { di->err_count++; } else if (new_value != di->time_to_full) { di->time_to_full = new_value; change = 1; } /* Query CycleCount() register */ if (bq27x00_battery_cycle_count(di, &new_value)) { di->err_count++; } else if (new_value != di->cycle_count) { di->cycle_count = new_value; change = 1; } /* Query AveragePower() register */ if (bq27x00_battery_average_power(di, &new_value)) { di->err_count++; } else if (new_value != di->average_power) { di->average_power = new_value; change = 1; } /* Query AvailableEnergy() register */ if (bq27x00_battery_available_energy(di, &new_value)) { di->err_count++; } else if (new_value != di->available_energy) { di->available_energy = new_value; change = 1; } /* Query RemainingCapacity() register */ if (bq27x00_battery_remaining_charge(di, &new_value)) { di->err_count++; } else if (new_value != di->remaining_charge) { di->remaining_charge = new_value; change = 1; } /* Query FullChargeCapacity() register */ if (bq27x00_battery_full_charge(di, &new_value)) { di->err_count++; } else if (new_value != di->full_charge) { di->full_charge = new_value; change = 1; } /* Query FullAvailableCapacity() register */ if (bq27x00_battery_full_charge_uncompensated(di, &new_value)) { di->err_count++; } else if (new_value != di->full_charge_uncompensated) { di->full_charge_uncompensated = new_value; change = 1; } if (++di->manufacturer_id_read_count != 2) { goto update_status; } else { di->manufacturer_id_read_count = 0; } /* Check for manufacturer ID every minute */ new_value = check_manufacturer(di); if (new_value != di->manufacturer){ di->manufacturer = new_value; change = 1; if (di->manufacturer >= 0) blocking_notifier_call_chain(¬ifier_list, EVENT_RECOGNIZE_BATTERY, NULL); if (di->manufacturer == NOT_RECOGNIZE) blocking_notifier_call_chain(¬ifier_list, EVENT_NOT_RECOGNIZE_BATTERY, NULL); if (di->manufacturer == UNKNOW) blocking_notifier_call_chain(¬ifier_list, EVENT_UNKNOW_BATTERY, NULL); } update_status: if (change) { power_supply_changed(&di->bat); // LED function u8 value = 0; if ((di->disable_led == 0) && !twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &value, 0x03)) { if ((di->status == POWER_SUPPLY_STATUS_CHARGING) && (value & (1 << 2))) { if(di->capacity < 90) { /* * Battery being charged, capacity < 90%: Amber LED */ omap4430_green_led_set(NULL, 0); omap4430_orange_led_set(NULL, 255); } else { /* * Battery being charged, capacity >= 90%: Green LED */ omap4430_orange_led_set(NULL, 0); omap4430_green_led_set(NULL, 255); } } else if (di->status == POWER_SUPPLY_STATUS_FULL) { if (value & (1 << 2)) { /* Set to green if connected to USB */ omap4430_orange_led_set(NULL, 0); omap4430_green_led_set(NULL, 255); } else { omap4430_green_led_set(NULL, 0); omap4430_orange_led_set(NULL, 0); } } } } if(di->err_count>=15){ printk("bat:%s get i2c error\n",__func__); queue_delayed_work(bat_work_queue,&di->bat_monitor_work, msecs_to_jiffies(10000 * 1)); }else queue_delayed_work(bat_work_queue,&di->bat_monitor_work, msecs_to_jiffies(5000 * 1)); } }