static void battery_error_work(struct work_struct *work)
{
	struct battery_info *info = container_of(work, struct battery_info,
						 error_work);
	int err_cnt;
	int old_vcell, new_vcell, vcell_diff;
	pr_info("%s\n", __func__);

	if (info->vf_state == true) {
		pr_info("%s: battery error state\n", __func__);
		old_vcell = info->battery_vcell;
		new_vcell = 0;
		for (err_cnt = 1; err_cnt <= VF_CHECK_COUNT; err_cnt++) {
#if defined(CONFIG_MACH_P11) || defined(CONFIG_MACH_P10)
			/* FIXME: fix P11 build error temporarily */
#else
			if (is_jig_attached == JIG_ON) {
				pr_info("%s: JIG detected, return\n", __func__);
				return;
			}
#endif
			info->battery_present =
				battery_get_info(info,
					POWER_SUPPLY_PROP_PRESENT);
			if (info->battery_present == 0) {
				pr_info("%s: battery still error(%d)\n",
						__func__, err_cnt);
				msleep(VF_CHECK_DELAY);
			} else {
				pr_info("%s: battery detect ok, "
						"check soc\n", __func__);
				new_vcell = battery_get_info(info,
					POWER_SUPPLY_PROP_VOLTAGE_NOW);
				vcell_diff = abs(old_vcell - new_vcell);
				pr_info("%s: check vcell: %d -> %d, diff: %d\n",
						__func__, info->battery_vcell,
							new_vcell, vcell_diff);
				if (vcell_diff > RESET_SOC_DIFF_TH) {
					pr_info("%s: reset soc\n", __func__);
					battery_control_info(info,
						POWER_SUPPLY_PROP_CAPACITY, 1);
				} else
					pr_info("%s: keep soc\n", __func__);
				break;
			}

			if (err_cnt == VF_CHECK_COUNT) {
				pr_info("%s: battery error, power off\n",
								__func__);
				battery_charge_control(info,
				       CHARGE_DISABLE, CHARGER_OFF_CURRENT);
			}
		}
	}

	return;
}
/* Setup init condition */
static void test_setup(int on_ac)
{
	const struct battery_info *bat_info = battery_get_info();

	reset_mocks();

	/* 50% of charge */
	sb_write(SB_RELATIVE_STATE_OF_CHARGE, 50);
	sb_write(SB_ABSOLUTE_STATE_OF_CHARGE, 50);
	/* full charge capacity in mAh */
	sb_write(SB_FULL_CHARGE_CAPACITY, 0xf000);
	/* 25 degree Celsius */
	sb_write(SB_TEMPERATURE, CELSIUS_TO_DECI_KELVIN(25));
	/* battery pack voltage */
	sb_write(SB_VOLTAGE, bat_info->voltage_normal);
	/* desired charging voltage/current */
	sb_write(SB_CHARGING_VOLTAGE, bat_info->voltage_max);
	sb_write(SB_CHARGING_CURRENT, 4000);

	/* battery pack current is positive when charging */
	if (on_ac) {
		sb_write(SB_CURRENT, 1000);
		gpio_set_level(GPIO_AC_PRESENT, 1);
	} else {
		sb_write(SB_CURRENT, -100);
		gpio_set_level(GPIO_AC_PRESENT, 0);
	}

	/* Reset the charger state to initial state */
	charge_control(CHARGE_CONTROL_NORMAL);

	/* Let things stabilize */
	wait_charging_state();
}
Пример #3
0
void protocol_transmitGroup(void)
{
	uint8_t packet[18];
	int16_t value, current, voltage, binfo;
	int8_t checksum=0, i;

	value   = battery_get_parameter_value(parameter);
	voltage = battery_get_parameter_value(TOTAL_SPANNUNG);
	current = battery_get_parameter_value(IST_STROM);
	binfo   = battery_get_info();
	
	packet[ 0] = FRAME;
	packet[ 1] = address;
	packet[ 2] = TRM_GROUP;
	packet[ 3] = binfo >> 8;
	packet[ 4] = binfo & 0xff;
	packet[ 5] = current >> 8;
	packet[ 6] = current & 0xff;
	packet[ 7] = voltage >> 8;
	packet[ 8] = voltage & 0xff;
	packet[ 9] = value >> 8;
	packet[10] = value & 0xff;
	
	for(i=2; i<=10; i++)
		checksum ^= packet[i];
	
	packet[11] = checksum;
	
	length = protocol_frame_stuffing(packet, 12);
	
	uart_send_twike( packet, length);
}
static bool battery_vf_cond(struct battery_info *info)
{
	pr_debug("%s\n", __func__);

#if defined(CONFIG_MACH_P11) || defined(CONFIG_MACH_P10)
	/* FIXME: fix P11 build error temporarily */
#else
	/* jig detect by MUIC */
	if (is_jig_attached == JIG_ON) {
		pr_info("%s: JIG ON, do not check\n", __func__);
		info->vf_state = false;
		return false;
	}
#endif

	/* TODO: Check VF from ADC */

	/* Now, battery present from charger */
	info->battery_present =
		battery_get_info(info, POWER_SUPPLY_PROP_PRESENT);
	if (info->battery_present == 0) {
		pr_info("%s: battery is not detected.\n", __func__);
		info->vf_state = true;
	} else {
		pr_debug("%s: battery is detected.\n", __func__);
		info->vf_state = false;
	}

	return info->vf_state;
}
Пример #5
0
/**
 * Init state handler
 *
 *	- check ac, charger, battery and temperature
 *	- initialize charger
 *	- new states: DISCHARGE, IDLE
 */
static enum charge_state state_init(struct charge_state_context *ctx)
{
	/* Stop charger, unconditionally */
	charge_request(0, 0);

	/* if battery was not detected initially, get battery info again */
	if (ctx->battery == NULL)
		ctx->battery = battery_get_info();

	/* Update static battery info */
	update_battery_info();

	/* Clear shutdown timer */
	ctx->shutdown_warning_time.val = 0;

	/* If AC is not present, switch to discharging state */
	if (!ctx->curr.ac)
		return PWR_STATE_DISCHARGE;

	/* Check general error conditions */
	if (ctx->curr.error)
		return PWR_STATE_ERROR;

	/* Send battery event to host */
	host_set_single_event(EC_HOST_EVENT_BATTERY);

	return PWR_STATE_IDLE0;
}
Пример #6
0
static void bd99995_init(void)
{
	int reg;
	const struct battery_info *bi = battery_get_info();

	/* Disable BC1.2 detection on VCC */
	if (ch_raw_read16(BD99955_CMD_VCC_UCD_SET, &reg,
			  BD99955_EXTENDED_COMMAND))
		return;
	reg &= ~BD99955_CMD_UCD_SET_USBDETEN;
	ch_raw_write16(BD99955_CMD_VCC_UCD_SET, reg,
		       BD99955_EXTENDED_COMMAND);

	/* Disable BC1.2 detection on VBUS */
	if (ch_raw_read16(BD99955_CMD_VBUS_UCD_SET, &reg,
			  BD99955_EXTENDED_COMMAND))
		return;
	reg &= ~BD99955_CMD_UCD_SET_USBDETEN;
	ch_raw_write16(BD99955_CMD_VBUS_UCD_SET, reg,
		       BD99955_EXTENDED_COMMAND);

	/* Disable BC1.2 charge enable trigger */
	if (ch_raw_read16(BD99955_CMD_CHGOP_SET1, &reg,
			  BD99955_EXTENDED_COMMAND))
		return;
	reg |= (BD99955_CMD_CHGOP_SET1_VCC_BC_DISEN |
		BD99955_CMD_CHGOP_SET1_VBUS_BC_DISEN);
	ch_raw_write16(BD99955_CMD_CHGOP_SET1, reg,
		       BD99955_EXTENDED_COMMAND);

	/* Set battery OVP to 500 + maximum battery voltage */
	ch_raw_write16(BD99955_CMD_VBATOVP_SET,
		       (bi->voltage_max + 500) & 0x7ff0,
		       BD99955_EXTENDED_COMMAND);
}
Пример #7
0
static int battery_discharging_range(int deci_k)
{
	int8_t temp_c = DECI_KELVIN_TO_CELSIUS(deci_k);
	const struct battery_info *info = battery_get_info();

	return (temp_c >= info->discharging_min_c &&
		temp_c < info->discharging_max_c);
}
Пример #8
0
int charger_profile_override(struct charge_state_data *curr)
{
	const struct battery_info *batt_info;
	/* battery temp in 0.1 deg C */
	int bat_temp_c = curr->batt.temperature - 2731;

	batt_info = battery_get_info();
	/* Don't charge if outside of allowable temperature range */
	if (bat_temp_c >= batt_info->charging_max_c * 10 ||
	    bat_temp_c < batt_info->charging_min_c * 10) {
		curr->requested_current = 0;
		curr->requested_voltage = 0;
		curr->batt.flags &= ~BATT_FLAG_WANT_CHARGE;
		curr->state = ST_IDLE;
	}
	return 0;
}
Пример #9
0
static void charge_init(void)
{
	struct charge_state_context *ctx = &task_ctx;

	ctx->prev.state = PWR_STATE_INIT;
	ctx->curr.state = PWR_STATE_INIT;
	ctx->trickle_charging_time.val = 0;
	ctx->battery = battery_get_info();
	ctx->charger = charger_get_info();
	/* Assume the battery is responsive until proven otherwise */
	ctx->battery_responsive = 1;

	/* Set up LPC direct memmap */
	ctx->memmap_batt_volt =
		(uint32_t *)host_get_memmap(EC_MEMMAP_BATT_VOLT);
	ctx->memmap_batt_rate =
		(uint32_t *)host_get_memmap(EC_MEMMAP_BATT_RATE);
	ctx->memmap_batt_cap =
		(uint32_t *)host_get_memmap(EC_MEMMAP_BATT_CAP);
	ctx->memmap_batt_flags = host_get_memmap(EC_MEMMAP_BATT_FLAG);
}
static ssize_t factory_show_property(struct device *dev,
				     struct device_attribute *attr, char *buf)
{
	struct battery_info *info = dev_get_drvdata(dev->parent);
	int i;
	int cnt, dat, d_max, d_min, d_total;
	int val;
	const ptrdiff_t off = attr - factory_attrs;
	pr_debug("%s: %s\n", __func__, factory_attrs[off].attr.name);

	i = 0;
	val = 0;
	switch (off) {
	case BATT_READ_RAW_SOC:
		battery_update_info(info);
		val = info->battery_raw_soc;
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val);
		break;
	case BATT_READ_ADJ_SOC:
		battery_get_info(info, POWER_SUPPLY_PROP_CAPACITY);
		val = info->battery_soc;
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val);
		break;
	case BATT_TYPE:
		i += scnprintf(buf + i, PAGE_SIZE - i, "SDI_SDI\n");
		break;
	case BATT_TEMP_ADC:
		battery_get_info(info, POWER_SUPPLY_PROP_TEMP);
		val = info->battery_temper_adc;
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val);
		break;
	case BATT_TEMP_AVER:
		val = 0;
		for (cnt = 0; cnt < CNT_TEMPER_AVG; cnt++) {
			msleep(100);
			battery_get_info(info, POWER_SUPPLY_PROP_TEMP);
			val += info->battery_temper_adc;
			info->battery_temper_adc_avg = val / (cnt + 1);
		}
#ifdef CONFIG_S3C_ADC
		info->battery_temper_avg = info->pdata->covert_adc(
						info->battery_temper_adc_avg,
						info->pdata->temper_ch);
#else
		info->battery_temper_avg = info->battery_temper;
#endif
		val = info->battery_temper_avg;
		pr_info("%s: temper avg(%d)\n", __func__, val);
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val);
		break;
	case BATT_TEMP_ADC_AVER:
		val = info->battery_temper_adc_avg;
		pr_info("%s: temper adc avg(%d)\n", __func__, val);
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val);
		break;
	case BATT_VOL_AVER:	/* not use POWER_SUPPLY_PROP_VOLTAGE_AVG */
		val = dat = d_max = d_min = d_total = 0;
		for (cnt = 0; cnt < CNT_VOLTAGE_AVG; cnt++) {
			msleep(200);
			dat = battery_get_info(info,
				POWER_SUPPLY_PROP_VOLTAGE_NOW);

			if (cnt != 0) {
				d_max = max(dat, d_max);
				d_min = min(dat, d_min);
			} else
				d_max = d_min = dat;

			d_total += dat;
		}
		val = (d_total - d_max - d_min) / (CNT_VOLTAGE_AVG - 2);
		pr_info("%s: voltage avg(%d)\n", __func__, val);
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val);
		break;
	case BATT_VFOCV:
		battery_update_info(info);
		val = info->battery_vfocv;
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val);
		break;
	case BATT_LP_CHARGING:
		val = info->lpm_state;
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val);
		break;
	case BATT_CHARGING_SOURCE:
		battery_get_info(info, POWER_SUPPLY_PROP_ONLINE);
		val = info->cable_type;
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val);
		break;
	case TEST_MODE:
		val = info->battery_test_mode;
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val);
		break;
	case BATT_ERROR_TEST:
		i += scnprintf(buf + i, PAGE_SIZE - i,
			"(%d): 0: normal, 1: full charged, 2: freezed, 3: overheated, 4: ovp, 5: vf\n",
			info->battery_error_test);
		break;
	case SIOP_ACTIVATED:
		val = info->siop_state;
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val);
		break;
	case WC_STATUS:
	case WPC_PIN_STATE:
#ifdef CONFIG_BATTERY_WPC_CHARGER
		val = !gpio_get_value(GPIO_WPC_INT);
#else
		val = false;
#endif
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val);
		break;
	case FACTORY_MODE:
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
						info->factory_mode);
		break;
	case BATT_VOL_ADC:
	case BATT_VOL_ADC_CAL:
	case BATT_VOL_ADC_AVER:
	case BATT_TEMP_ADC_CAL:
	case BATT_VF_ADC:
	case AUTH_BATTERY:
		i += scnprintf(buf + i, PAGE_SIZE - i, "N/A\n");
		break;
#if defined(CONFIG_TARGET_LOCALE_KOR) || defined(CONFIG_MACH_M0_CTC)
	case BATT_SYSREV:
		val = system_rev;
		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", val);
		break;
	case BATT_TEMP_ADC_SPEC:
		i += scnprintf(buf + i, PAGE_SIZE - i,
			"(HIGH: %d / %d,   LOW: %d / %d)\n",
			info->pdata->overheat_stop_temp,
			info->pdata->overheat_recovery_temp,
			info->pdata->freeze_stop_temp,
			info->pdata->freeze_recovery_temp);
		break;
#endif
	default:
		i = -EINVAL;
	}

	return i;
}
Пример #11
0
/* Main loop */
void charger_task(void)
{
	int sleep_usec;
	int need_static = 1;
	const struct charger_info * const info = charger_get_info();

	/* Get the battery-specific values */
	batt_info = battery_get_info();

	prev_ac = prev_charge = -1;
	chg_ctl_mode = CHARGE_CONTROL_NORMAL;
	shutdown_warning_time.val = 0UL;
	battery_seems_to_be_dead = 0;

	/*
	 * If system is not locked and we don't have a battery to live on,
	 * then use max input current limit so that we can pull as much power
	 * as needed.
	 */
	battery_get_params(&curr.batt);
	prev_bp = curr.batt.is_present;
	curr.desired_input_current = get_desired_input_current(prev_bp, info);

	while (1) {

#ifdef CONFIG_SB_FIRMWARE_UPDATE
		if (sb_fw_update_in_progress()) {
			task_wait_event(CHARGE_MAX_SLEEP_USEC);
			continue;
		}
#endif

		/* Let's see what's going on... */
		curr.ts = get_time();
		sleep_usec = 0;
		problems_exist = 0;
		curr.ac = extpower_is_present();
		if (curr.ac != prev_ac) {
			if (curr.ac) {
				/*
				 * Some chargers are unpowered when the AC is
				 * off, so we'll reinitialize it when AC
				 * comes back and set the input current limit.
				 * Try again if it fails.
				 */
				int rv = charger_post_init();
				if (rv != EC_SUCCESS) {
					problem(PR_POST_INIT, rv);
				} else {
					if (curr.desired_input_current !=
					    CHARGE_CURRENT_UNINITIALIZED)
						rv = charger_set_input_current(
						    curr.desired_input_current);
					if (rv != EC_SUCCESS)
						problem(PR_SET_INPUT_CURR, rv);
					else
						prev_ac = curr.ac;
				}
			} else {
				/* Some things are only meaningful on AC */
				chg_ctl_mode = CHARGE_CONTROL_NORMAL;
				battery_seems_to_be_dead = 0;
				prev_ac = curr.ac;
			}
		}
		charger_get_params(&curr.chg);
		battery_get_params(&curr.batt);

		if (prev_bp != curr.batt.is_present) {
			prev_bp = curr.batt.is_present;

			/* Update battery info due to change of battery */
			batt_info = battery_get_info();
			need_static = 1;

			curr.desired_input_current =
				get_desired_input_current(prev_bp, info);
			if (curr.desired_input_current !=
			    CHARGE_CURRENT_UNINITIALIZED)
				charger_set_input_current(
					curr.desired_input_current);
			hook_notify(HOOK_BATTERY_SOC_CHANGE);
		}

		/*
		 * TODO(crosbug.com/p/27527). Sometimes the battery thinks its
		 * temperature is 6280C, which seems a bit high. Let's ignore
		 * anything above the boiling point of tungsten until this bug
		 * is fixed. If the battery is really that warm, we probably
		 * have more urgent problems.
		 */
		if (curr.batt.temperature > CELSIUS_TO_DECI_KELVIN(5660)) {
			CPRINTS("ignoring ridiculous batt.temp of %dC",
				 DECI_KELVIN_TO_CELSIUS(curr.batt.temperature));
			curr.batt.flags |= BATT_FLAG_BAD_TEMPERATURE;
		}

		/* If the battery thinks it's above 100%, don't believe it */
		if (curr.batt.state_of_charge > 100) {
			CPRINTS("ignoring ridiculous batt.soc of %d%%",
				curr.batt.state_of_charge);
			curr.batt.flags |= BATT_FLAG_BAD_STATE_OF_CHARGE;
		}

		/*
		 * Now decide what we want to do about it. We'll normally just
		 * pass along whatever the battery wants to the charger. Note
		 * that if battery_get_params() can't get valid values from the
		 * battery it uses (0, 0), which is probably safer than blindly
		 * applying power to a battery we can't talk to.
		 */
		curr.requested_voltage = curr.batt.desired_voltage;
		curr.requested_current = curr.batt.desired_current;

		/* If we *know* there's no battery, wait for one to appear. */
		if (curr.batt.is_present == BP_NO) {
			ASSERT(curr.ac);	/* How are we running? */
			curr.state = ST_IDLE;
			curr.batt_is_charging = 0;
			battery_was_removed = 1;
			goto wait_for_it;
		}

		/*
		 * If we had trouble talking to the battery or the charger, we
		 * should probably do nothing for a bit, and if it doesn't get
		 * better then flag it as an error.
		 */
		if (curr.chg.flags & CHG_FLAG_BAD_ANY)
			problem(PR_CHG_FLAGS, curr.chg.flags);
		if (curr.batt.flags & BATT_FLAG_BAD_ANY)
			problem(PR_BATT_FLAGS, curr.batt.flags);

		/*
		 * If AC is present, check if input current is sufficient to
		 * actually charge battery.
		 */
		curr.batt_is_charging = curr.ac && (curr.batt.current >= 0);

		/* Don't let the battery hurt itself. */
		shutdown_on_critical_battery();

		if (!curr.ac) {
			curr.state = ST_DISCHARGE;
			goto wait_for_it;
		}

		/* Okay, we're on AC and we should have a battery. */

		/* Used for factory tests. */
		if (chg_ctl_mode != CHARGE_CONTROL_NORMAL) {
			curr.state = ST_IDLE;
			goto wait_for_it;
		}

		/* If the battery is not responsive, try to wake it up. */
		if (!(curr.batt.flags & BATT_FLAG_RESPONSIVE)) {
			if (battery_seems_to_be_dead || battery_is_cut_off()) {
				/* It's dead, do nothing */
				curr.state = ST_IDLE;
				curr.requested_voltage = 0;
				curr.requested_current = 0;
			} else if (curr.state == ST_PRECHARGE &&
				   (get_time().val > precharge_start_time.val +
				    PRECHARGE_TIMEOUT_US)) {
				/* We've tried long enough, give up */
				CPRINTS("battery seems to be dead");
				battery_seems_to_be_dead = 1;
				curr.state = ST_IDLE;
				curr.requested_voltage = 0;
				curr.requested_current = 0;
			} else {
				/* See if we can wake it up */
				if (curr.state != ST_PRECHARGE) {
					CPRINTS("try to wake battery");
					precharge_start_time = get_time();
					need_static = 1;
				}
				curr.state = ST_PRECHARGE;
				curr.requested_voltage =
					batt_info->voltage_max;
				curr.requested_current =
					batt_info->precharge_current;
			}
			goto wait_for_it;
		} else {
			/* The battery is responding. Yay. Try to use it. */
#ifdef CONFIG_BATTERY_REQUESTS_NIL_WHEN_DEAD
			/*
			 * TODO (crosbug.com/p/29467): remove this workaround
			 * for dead battery that requests no voltage/current
			 */
			if (curr.requested_voltage == 0 &&
			    curr.requested_current == 0 &&
			    curr.batt.state_of_charge == 0) {
				/* Battery is dead, give precharge current */
				curr.requested_voltage =
					batt_info->voltage_max;
				curr.requested_current =
					batt_info->precharge_current;
			} else
#endif
#ifdef CONFIG_BATTERY_REVIVE_DISCONNECT
			battery_seems_to_be_disconnected = 0;

			if (curr.requested_voltage == 0 &&
			    curr.requested_current == 0 &&
			    battery_get_disconnect_state() ==
			    BATTERY_DISCONNECTED) {
				/*
				 * Battery is in disconnect state. Apply a
				 * current to kick it out of this state.
				 */
				CPRINTS("found battery in disconnect state");
				curr.requested_voltage =
					batt_info->voltage_max;
				curr.requested_current =
					batt_info->precharge_current;
				battery_seems_to_be_disconnected = 1;
			} else
#endif
			if (curr.state == ST_PRECHARGE ||
			    battery_seems_to_be_dead ||
			    battery_was_removed) {
				CPRINTS("battery woke up");

				/* Update the battery-specific values */
				batt_info = battery_get_info();
				need_static = 1;
			    }

			battery_seems_to_be_dead = battery_was_removed = 0;
			curr.state = ST_CHARGE;
		}

		/*
		 * TODO(crosbug.com/p/27643): Quit trying if charging too long
		 * without getting full (CONFIG_CHARGER_TIMEOUT_HOURS).
		 */

wait_for_it:
#ifdef CONFIG_CHARGER_PROFILE_OVERRIDE
		sleep_usec = charger_profile_override(&curr);
		if (sleep_usec < 0)
			problem(PR_CUSTOM, sleep_usec);
#endif

		/* Keep the AP informed */
		if (need_static)
			need_static = update_static_battery_info();
		/* Wait on the dynamic info until the static info is good. */
		if (!need_static)
			update_dynamic_battery_info();
		notify_host_of_low_battery();

		/* And the EC console */
		is_full = calc_is_full();
		if ((!(curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) &&
		    curr.batt.state_of_charge != prev_charge) ||
		    (is_full != prev_full)) {
			show_charging_progress();
			prev_charge = curr.batt.state_of_charge;
			hook_notify(HOOK_BATTERY_SOC_CHANGE);
		}
		prev_full = is_full;

		/* Turn charger off if it's not needed */
		if (curr.state == ST_IDLE || curr.state == ST_DISCHARGE) {
			curr.requested_voltage = 0;
			curr.requested_current = 0;
		}

		/* Apply external limits */
		if (curr.requested_current > user_current_limit)
			curr.requested_current = user_current_limit;

		/* Round to valid values */
		curr.requested_voltage =
			charger_closest_voltage(curr.requested_voltage);
		curr.requested_current =
			charger_closest_current(curr.requested_current);

		/* Charger only accpets request when AC is on. */
		if (curr.ac) {
			/*
			 * Some batteries would wake up after cut-off if we keep
			 * charging it. Thus, we only charge when AC is on and
			 * battery is not cut off yet.
			 */
			if (battery_is_cut_off())
				charge_request(0, 0);
			/*
			 * As a safety feature, some chargers will stop
			 * charging if we don't communicate with it frequently
			 * enough. In manual mode, we'll just tell it what it
			 * knows.
			 */
			else if (manual_mode) {
				charge_request(curr.chg.voltage,
					       curr.chg.current);
			} else {
				charge_request(curr.requested_voltage,
					       curr.requested_current);
			}
		} else {
			charge_request(
				charger_closest_voltage(
				  curr.batt.voltage + info->voltage_step), -1);
		}

		/* How long to sleep? */
		if (problems_exist)
			/* If there are errors, don't wait very long. */
			sleep_usec = CHARGE_POLL_PERIOD_SHORT;
		else if (sleep_usec <= 0) {
			/* default values depend on the state */
			if (curr.state == ST_IDLE ||
			    curr.state == ST_DISCHARGE) {
				/* If AP is off, we can sleep a long time */
				if (chipset_in_state(CHIPSET_STATE_ANY_OFF |
						     CHIPSET_STATE_SUSPEND))
					sleep_usec =
						CHARGE_POLL_PERIOD_VERY_LONG;
				else
					/* Discharging, not too urgent */
					sleep_usec = CHARGE_POLL_PERIOD_LONG;
			} else {
				/* Charging, so pay closer attention */
				sleep_usec = CHARGE_POLL_PERIOD_CHARGE;
			}
		}

		/* Adjust for time spent in this loop */
		sleep_usec -= (int)(get_time().val - curr.ts.val);
		if (sleep_usec < CHARGE_MIN_SLEEP_USEC)
			sleep_usec = CHARGE_MIN_SLEEP_USEC;
		else if (sleep_usec > CHARGE_MAX_SLEEP_USEC)
			sleep_usec = CHARGE_MAX_SLEEP_USEC;

		task_wait_event(sleep_usec);
	}
}
Пример #12
0
/*
 * Ask the charger for some voltage and current. If either value is 0,
 * charging is disabled; otherwise it's enabled. Negative values are ignored.
 */
static int charge_request(int voltage, int current)
{
	int r1 = EC_SUCCESS, r2 = EC_SUCCESS, r3 = EC_SUCCESS;
	static int __bss_slow prev_volt, prev_curr;

	if (!voltage || !current) {
#ifdef CONFIG_CHARGER_NARROW_VDC
		current = 0;
		/* With NVDC charger, keep VSYS voltage higher than battery */
		voltage = charger_closest_voltage(
			curr.batt.voltage + charger_get_info()->voltage_step);
		/* If the battery is full, request the max voltage. */
		if (is_full)
			voltage = battery_get_info()->voltage_max;
		/* And handle dead battery case */
		voltage = MAX(voltage, battery_get_info()->voltage_min);
#else
		voltage = current = 0;
#endif
	}

	if (curr.ac) {
		if (prev_volt != voltage || prev_curr != current)
			CPRINTS("%s(%dmV, %dmA)", __func__, voltage, current);
	}

	/*
	 * Set current before voltage so that if we are just starting
	 * to charge, we allow some time (i2c delay) for charging circuit to
	 * start at a voltage just above battery voltage before jumping
	 * up. This helps avoid large current spikes when connecting
	 * battery.
	 */
	if (current >= 0)
		r2 = charger_set_current(current);
	if (r2 != EC_SUCCESS)
		problem(PR_SET_CURRENT, r2);

	if (voltage >= 0)
		r1 = charger_set_voltage(voltage);
	if (r1 != EC_SUCCESS)
		problem(PR_SET_VOLTAGE, r1);

	/*
	 * Set the charge inhibit bit when possible as it appears to save
	 * power in some cases (e.g. Nyan with BQ24735).
	 */
#if defined(CONFIG_CHARGER_BD99955) || defined(CONFIG_CHARGER_BD99956)
	/* Charger auto exits from battery learn mode if charge inhibited */
	if (current > 0 || chg_ctl_mode == CHARGE_CONTROL_DISCHARGE)
#else
	if (voltage > 0 || current > 0)
#endif
		r3 = charger_set_mode(0);
	else
		r3 = charger_set_mode(CHARGE_FLAG_INHIBIT_CHARGE);
	if (r3 != EC_SUCCESS)
		problem(PR_SET_MODE, r3);

	/*
	 * Only update if the request worked, so we'll keep trying on failures.
	 */
	if (!r1 && !r2) {
		prev_volt = voltage;
		prev_curr = current;
	}

	return r1 ? r1 : r2;
}
static void battery_charge_control(struct battery_info *info,
				   int enable,
				   int set_current)
{
	ktime_t ktime;
	struct timespec current_time;
	pr_debug("%s\n", __func__);

	ktime = alarm_get_elapsed_realtime();
	current_time = ktime_to_timespec(ktime);

	if (set_current == CHARGER_KEEP_CURRENT)
		goto charge_state_control;

	if (info->siop_state == true) {
		pr_debug("%s: siop state, charge current is %dmA\n", __func__,
			 info->siop_charge_current);
		set_current = info->siop_charge_current;
	}

	/* check charge current before and after */
	if (info->charge_current == ((set_current * 3 / 100) * 333 / 10)) {
		/*
		 * (current * 3 / 100) is converted value
		 * for register setting.
		 * (register current * 333 / 10) is actual value
		 * for charging
		 */
		pr_debug("%s: same charge current: %dmA\n", __func__,
							set_current);
	} else {
		battery_control_info(info,
				     POWER_SUPPLY_PROP_CURRENT_NOW,
				     set_current);
		pr_info("%s: update charge current: %dmA\n", __func__,
							set_current);
	}

	info->charge_current =
		battery_get_info(info, POWER_SUPPLY_PROP_CURRENT_NOW);

charge_state_control:
	/* check charge state before and after */
	if ((enable == CHARGE_ENABLE) &&
		(info->charge_start_time == 0)) {
		battery_control_info(info,
				     POWER_SUPPLY_PROP_STATUS,
				     CHARGE_ENABLE);

		info->charge_start_time = current_time.tv_sec;
		pr_info("%s: charge enabled, current as %dmA @%d\n", __func__,
				info->charge_current, info->charge_start_time);
	} else if ((enable == CHARGE_DISABLE) &&
		(info->charge_start_time != 0)) {
		battery_control_info(info,
				     POWER_SUPPLY_PROP_STATUS,
				     CHARGE_DISABLE);

		pr_info("%s: charge disabled, current as %dmA @%d\n", __func__,
				info->charge_current, (int)current_time.tv_sec);

		info->charge_start_time = 0;
	} else {
		pr_debug("%s: same charge state(%s), current as %dmA @%d\n",
				__func__, (enable ? "enabled" : "disabled"),
				info->charge_current, info->charge_start_time);
	}

	info->charge_real_state = info->charge_virt_state =
		battery_get_info(info, POWER_SUPPLY_PROP_STATUS);
}
Пример #14
0
static ssize_t factory_store_property(struct device *dev,
			     struct device_attribute *attr,
			     const char *buf, size_t count)
{
	struct battery_info *info = dev_get_drvdata(dev->parent);
	int x;
	int ret;
	const ptrdiff_t off = attr - factory_attrs;
	pr_info("%s: %s\n", __func__, factory_attrs[off].attr.name);

	x = 0;
	ret = 0;
	switch (off) {
	case BATT_RESET_SOC:
		if (sscanf(buf, "%d\n", &x) == 1) {
			if (x == 1) {
				pr_info("%s: Reset SOC.\n", __func__);
				battery_control_info(info,
						POWER_SUPPLY_PROP_CAPACITY,
						1);
				info->battery_soc =
						battery_get_info(info,
						POWER_SUPPLY_PROP_CAPACITY);
			} else
				pr_info("%s: Not supported param.\n", __func__);
			ret = count;
		}
		break;
	case TEST_MODE:
		if (sscanf(buf, "%d\n", &x) == 1) {
			info->battery_test_mode = x;
			pr_info("%s: battery test mode: %d\n", __func__,
						info->battery_test_mode);
			ret = count;
		}
		break;
	case BATT_ERROR_TEST:
		if (sscanf(buf, "%d\n", &x) == 1) {
			info->battery_error_test = x;
			pr_info("%s: battery error test: %d\n", __func__,
						info->battery_error_test);
			ret = count;
		}
		break;
	case SIOP_ACTIVATED:
		if (sscanf(buf, "%d\n", &x) == 1) {
			info->siop_state = x;

			if (info->siop_state == SIOP_ACTIVE)
				info->siop_charge_current =
					info->pdata->chg_curr_usb;

			pr_info("%s: SIOP %s\n", __func__,
				(info->siop_state ?
				"activated" : "deactivated"));
			ret = count;
		}
		break;
	case FACTORY_MODE:
		if (sscanf(buf, "%d\n", &x) == 1) {
			if (x)
				info->factory_mode = true;
			else
				info->factory_mode = false;

			pr_info("%s: factory mode %s\n", __func__,
				(info->factory_mode ? "set" : "clear"));
			ret = count;
		}
		break;
	case UPDATE:
		pr_info("%s: battery update\n", __func__);
		ret = count;
		break;
	case BATT_SLATE_MODE:
		if (sscanf(buf, "%d\n", &x) == 1) {
			if (x)
				info->slate_mode = 1;
			else
				info->slate_mode = 0;

			pr_info("%s: slate_mode %s\n", __func__,
				(info->slate_mode ? "set" : "clear"));
			ret = count;
		}
		break;
	default:
		ret = -EINVAL;
	}

	schedule_work(&info->monitor_work);

	return ret;
}
Пример #15
0
int16_t battery_get_parameter_value(uint8_t parameter)
{
	uint16_t value;

	os_enterCS();

	switch(parameter)
	{						
	case MODEL_TYPE:		value = 1;			break;
	case PROGRAM_REV:		value = 530;			break;
	case PAR_TAB_REV:		value = 530;			break;
	
	case NENNSPNG:			value = 35520;			break;
	case NENNSTROM:			value = 2500;			break;
	case SERIE_NUMMER:		value = 11178;			break;
	case REP_DATUM: 		value = 0;			break;
	case STANDZEIT:			value = 64;			break;
	case FAHR_LADE_ZEIT:		value = 9;			break;
	case LAST_ERROR:		value = 0;			break;
	case BUS_ADRESSE:		value = battery.address;	break;

	case DRIVE_STATE:		value = plc_get_drive_state();	break;
	case COMMAND:			value = !battery_info_get(BAT_REL_OPEN);	break;
	case PARAM_PROT:		value = 0;					break;

	case BINFO:			value = battery_get_info();	break;
	
	// We simulate 3 batteries. Thus each of them reports one third of the real value.
	case IST_STROM:			value = 0;	break;
	case LADESTROM:			value = 400;			break;
	case FAHRSTROM:			value = -800;			break;
	case TOTAL_SPANNUNG:		value = 0;			break;
	case SOLL_LADESPG:		value =	40000;			break;
	
	 // We simulate 3 batteries. Thus each of them reports one third of the real value.
	case AH_ZAEHLER:		value = battery.ah_counter;	break;
	case Q:				value = -1400;					break;
	case LEISTUNG:			value = 0;			break;
	case BATTERIE_TEMP:		value = 0;	break;
	case FINFO:			value = 0;					break;
	case SYM_SPANNUNG:		value = 26;					break;
				
	case TEILSPANNUNG1:		value = 5100;	break;
	case TEILSPANNUNG2:		value = 5100;	break;
	case TEILSPANNUNG3:		value = 5100;	break;
	case TEILSPANNUNG4:		value = 5100;	break;
	case TEILSPANNUNG5:		value = 5100;	break;
	case TEILSPANNUNG6:		value = 5100;	break;
	case TEILSPANNUNG7:		value = 5100;	break;
	
	case TEMPERATUR1:		value = battery.temperatur_1;	break;
	case TEMPERATUR2:		value = battery.temperatur_2;	break;
	case TEMPERATUR3:		value = battery.temperatur_3;	break;
	case TEMPERATUR4:		value = battery.temperatur_4;	break;
	case TEMPERATUR5:		value = battery.temperatur_5;	break;
	case TEMPERATUR6:		value = battery.temperatur_6;	break;
	case TEMPERATUR7:		value = battery.temperatur_7;	break;
	case TEMPERATUR8:		value = battery.temperatur_8;	break;
	case TEMPERATUR9:		value = battery.temperatur_9;	break;
	case TEMPERATUR10:		value = battery.temperatur_10;	break;
	case TEMPERATUR11:		value = battery.temperatur_11;	break;
	case TEMPERATUR12:		value = battery.temperatur_12;	break;
	case TEMPERATUR13:		value = battery.temperatur_13;	break;
	case TEMPERATUR14:		value = battery.temperatur_14;	break;
			
	case PC_CALIBR_TEMP:		value = 0x5678;			break;
	case MAX_BAT_TEMP:		value = 0;	break;
	case UMGEBUNGS_TEMP:		value = 0;		break;
	case MAX_LADETEMP:		value = 4500;			break;
	case MIN_LADETEMP:		value = 0;			break;
	case MAX_FAHRTEMP:		value = 4500;			break;
	case MIN_FAHRTEMP:		value = 0;			break;
	case MAX_LAGERTEMP:		value = 4500;			break;
	case MIN_LAGERTEMP:		value = 0;			break;

	case MAX_KAPAZITAET:		value = 305;	break;
	case MIN_KAPAZITAET:		value = 280;	break;
	case GELADENE_AH:		value = 0;	break;
	case ENTLADENE_AH:		value = 0;	break;
	case LADEZYKLEN:		value = 0;		break;
	case TIEFENTLADE_ZYKLEN:	value = 0;	break;
	
	case MAX_ENTLADE_STROM:		value = -800;	break; // Times 3 blocks -> 24A
				
	case ZYKLUS_UEBER_110:		value = 0;	break;
	case ZYKLUS_UEBER_100:		value = 0;	break;
	case ZYKLUS_UEBER_90:		value = 0;	break;
	case ZYKLUS_UEBER_80:		value = 0;	break;
	case ZYKLUS_UEBER_70:		value = 0;	break;
	case ZYKLUS_UEBER_60:		value = 0;	break;
	case ZYKLUS_UEBER_50:		value = 0;	break;
	case ZYKLUS_UEBER_40:		value = 0;	break;
	case ZYKLUS_UEBER_30:		value = 0;	break;
	case ZYKLUS_UEBER_20:		value = 0;	break;
	case ZYKLUS_UEBER_10:		value = 0;	break;
	case ZYKLUS_UNTER_10:		value = 0;	break;

	case MAX_UEBERLADUNG:		value = 850;	break;
	case MIN_LDG_F_VOLL:		value = -500;	break;
	case STROM_ZUNAHME:		value = 40;	break;
	case MAX_LADE_SPG:		value = 40000;	break;
	case MIN_LADE_TEMP:		value = 0;	break;
	case MAX_LADE_TEMP:		value = 4500;	break;
	case MAX_TEMP_ZUNAHME:		value = 100;	break;
	case MAX_LADEZEIT:		value = 800;	break;
	case SYMMETRIER_STROM:		value = 28;	break;

	case LADE_STR_UNTER_M10:	value = 56;	break;
	case LADE_STR_UEBER_M10:	value = 56;	break;
	case LADE_STR_UEBER_P00:	value = 280;	break;
	case LADE_STR_UEBER_P10:	value = 280;	break;
	case LADE_STR_UEBER_P20:	value = 280;	break;
	case LADE_STR_UEBER_P30:	value = 280;	break;
	case LADE_STR_UEBER_P40:	value = 79;	break;
	case LADE_STR_UEBER_P45:	value = 28;	break;
	case LADE_STR_UEBER_P50:	value = 28;	break;
			
	case LADE_SPG_UNTER_M10:	value = 40000;	break;
	case LADE_SPG_UEBER_M10:	value = 40000;	break;
	case LADE_SPG_UEBER_P00:	value = 40000;	break;
	case LADE_SPG_UEBER_P10:	value = 40000;	break;
	case LADE_SPG_UEBER_P20:	value = 40000;	break;
	case LADE_SPG_UEBER_P30:	value = 40000;	break;
	case LADE_SPG_UEBER_P40:	value = 37440;	break;
	case LADE_SPG_UEBER_P45:	value = 36480;	break;
	case LADE_SPG_UEBER_P50:	value = 35520;	break;
			
	case NOM_KAPAZITAET:		value = 3;	break;
	case MIN_FAHR_SPANNUNG:		value = 31000;	break;
	case SELBST_ENTL_STROM:		value = 28000;	break;
	case TIEFENTLADE_SPG:		value = TIEFENTLADE_SPANNUNG;	break;
	case MAX_SPANNUNG_DIFF:		value = 500;	break;
	case MIN_FAHR_TEMP_B:		value = -2500;	break;
	case MAX_FAHR_TEMP_B:		value = 6000;	break;
	case MAX_FAHR_STROM:		value = -1000;	break;
	
	case AD_STROM:			value = 0x817F;	break;
	
	case KAL_TEMP_7_6:		value = 0xFFFF;	break;
	case KAL_TEMP_5_4:		value = 0xFEFD;	break;
	case KAL_TEMP_3_2:		value = 0xFCFD;	break;
	case KAL_TEMP_1_AMB:		value = 0x00FE;	break;
	case KAL_TEMP_GD_14:		value = 0x7C00;	break;
	case KAL_TEMP_13_12:		value = 0x00FF;	break;
	case KAL_TEMP_11_10:		value = 0xFE00;	break;
	case KAL_TEMP_9_8:		value = 0x0002;	break;

	case SENSOR_MASK:		value = 0x0000;	break;
			
	case OFFS_KLEIN_STL:		value = 1508;	break;
	case OFFS_GROSS_STL:		value = 12523;	break;
	case KALIB_SPG_1:		value = 0x00A3;	break;
	case KALIB_SPG_2:		value = 0x009F;	break;
	case KALIB_SPG_3:		value = 0x00A6;	break;
	case KALIB_SPG_4:		value = 0x00B1;	break;
	case KALIB_SPG_5:		value = 0x007C;	break;
	case KALIB_SPG_6:		value = 0x00A7;	break;
	case KALIB_SPG_9:		value = 0x00A7;	break;
			
	case DEBUG_VALUE_C:		value = 22498;	break;
	case DEBUG_VALUE_H:		value = 0x57E2;	break;
	case DEBUG_VALUE_ADDR:		value = 0xFFFF;	break;

	case GESCHWINDIGKEIT:		value = 0;	break;
	case TAGESKILOMETER:		value = 0;	break;
	
	default:
		value = 0x0000;
		error(ERROR_UNKNOWN_PARAMETER);
	}

	os_exitCS();

	return value;
}