示例#1
0
static int bq27541_resume(struct i2c_client *client)
{
    struct bq27541_info *di = i2c_get_clientdata(client);
    int err = 0;
    int new_value=0;

    //Low battery protection
//	printk(KERN_INFO "at %s\n", __FUNCTION__);
    err=bq27x00_battery_voltage(di,&new_value);
    if (err){
        di->err_count++;
    }else{
        di->voltage=new_value;
    }
    err=bq27x00_battery_rsoc(di,&new_value);
    if (err){
        di->err_count++;
    }else{
            di->capacity=new_value;
    }
    power_supply_changed(&di->bat);  
    queue_delayed_work(bat_work_queue,&di->bat_monitor_work,
            msecs_to_jiffies(2500 * 1));
    return 0;
}
示例#2
0
static int bq27x00_battery_get_property(struct power_supply *psy,
					enum power_supply_property psp,
					union power_supply_propval *val)
{
	int ret = 0;
	struct bq27x00_device_info *di = power_supply_get_drvdata(psy);

	mutex_lock(&di->lock);
	if (time_is_before_jiffies(di->last_update + 5 * HZ)) {
		cancel_delayed_work_sync(&di->work);
		bq27x00_battery_poll(&di->work.work);
	}
	mutex_unlock(&di->lock);

	if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0)
		return -ENODEV;

	switch (psp) {
	case POWER_SUPPLY_PROP_STATUS:
		ret = bq27x00_battery_status(di, val);
		break;
	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
		ret = bq27x00_battery_voltage(di, val);
		break;
	case POWER_SUPPLY_PROP_PRESENT:
		val->intval = di->cache.flags < 0 ? 0 : 1;
		break;
	case POWER_SUPPLY_PROP_CURRENT_NOW:
		ret = bq27x00_battery_current(di, val);
		break;
	case POWER_SUPPLY_PROP_CAPACITY:
		ret = bq27x00_simple_value(di->cache.capacity, val);
		break;
	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
		ret = bq27x00_battery_capacity_level(di, val);
		break;
	case POWER_SUPPLY_PROP_TEMP:
		ret = bq27x00_simple_value(di->cache.temperature, val);
		if (ret == 0)
			val->intval -= 2731;
		break;
	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
		ret = bq27x00_simple_value(di->cache.time_to_empty, val);
		break;
	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
		ret = bq27x00_simple_value(di->cache.time_to_empty_avg, val);
		break;
	case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
		ret = bq27x00_simple_value(di->cache.time_to_full, val);
		break;
	case POWER_SUPPLY_PROP_TECHNOLOGY:
		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
		break;
	case POWER_SUPPLY_PROP_CHARGE_NOW:
		ret = bq27x00_simple_value(bq27x00_battery_read_nac(di), val);
		break;
	case POWER_SUPPLY_PROP_CHARGE_FULL:
		ret = bq27x00_simple_value(di->cache.charge_full, val);
		break;
	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
		ret = bq27x00_simple_value(di->charge_design_full, val);
		break;
	case POWER_SUPPLY_PROP_CYCLE_COUNT:
		ret = bq27x00_simple_value(di->cache.cycle_count, val);
		break;
	case POWER_SUPPLY_PROP_ENERGY_NOW:
		ret = bq27x00_simple_value(di->cache.energy, val);
		break;
	case POWER_SUPPLY_PROP_POWER_AVG:
		ret = bq27x00_simple_value(di->cache.power_avg, val);
		break;
	case POWER_SUPPLY_PROP_HEALTH:
		ret = bq27x00_simple_value(di->cache.health, val);
		break;
	case POWER_SUPPLY_PROP_MANUFACTURER:
		val->strval = BQ27XXX_MANUFACTURER;
		break;
	default:
		return -EINVAL;
	}

	return ret;
}
示例#3
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));
    }
}