Beispiel #1
0
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);
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
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);
    }
}
Beispiel #6
0
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(&notifier_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(&notifier_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(&notifier_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(&notifier_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(&notifier_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(&notifier_list, EVENT_BATTERY_NTC_NORMAL, NULL);
            di->ntc_temp=new_value;
            if(di->ntc_temp==0)
                blocking_notifier_call_chain(&notifier_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(&notifier_list,
					EVENT_RECOGNIZE_BATTERY, NULL);

			if (di->manufacturer == NOT_RECOGNIZE)
				blocking_notifier_call_chain(&notifier_list,
					EVENT_NOT_RECOGNIZE_BATTERY, NULL);
            
			if (di->manufacturer == UNKNOW)
				blocking_notifier_call_chain(&notifier_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));
    }
}