/* Copyright 2013 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 * Battery charging parameters and constraints
 */

#ifndef __CROS_EC_BATTERY_H
#define __CROS_EC_BATTERY_H

#include "common.h"
#include "compiler.h"
#include "host_command.h"

/* Battery index, only used with CONFIG_BATTERY_V2. */
enum battery_index {
	BATT_IDX_INVALID = -1,
	BATT_IDX_MAIN = 0,
	BATT_IDX_BASE = 1,
};

#ifdef CONFIG_BATTERY_V2
extern struct ec_response_battery_static_info_v1
	battery_static[CONFIG_BATTERY_COUNT];
extern struct ec_response_battery_dynamic_info
	battery_dynamic[CONFIG_BATTERY_COUNT];
#endif

/* Stop charge when charging and battery level >= this percentage */
#define BATTERY_LEVEL_FULL		100

/* Tell host we're charged when battery level >= this percentage */
#ifdef CONFIG_BATTERY_LEVEL_NEAR_FULL
#define BATTERY_LEVEL_NEAR_FULL		 CONFIG_BATTERY_LEVEL_NEAR_FULL
#else
#define BATTERY_LEVEL_NEAR_FULL		 97
#endif

/*
 * Send battery-low host event when discharging and battery level <= this level
 */
#define BATTERY_LEVEL_LOW		 10

/*
 * Send battery-critical host event when discharging and battery level <= this
 * level.
 */
#define BATTERY_LEVEL_CRITICAL		  5

/*
 * Shut down main processor and/or hibernate EC when discharging and battery
 * level < this level. Setting this too low makes the battery discharge too
 * deeply, which isn't good for the battery health.
 */
#define BATTERY_LEVEL_SHUTDOWN		  3

/*
 * Sometimes we have hardware to detect battery present, sometimes we have to
 * wait until we've been able to talk to the battery.
 */
FORWARD_DECLARE_ENUM(battery_present) {
	BP_NOT_INIT = -1,
	BP_NO = 0,
	BP_YES = 1,
	BP_NOT_SURE,
};

enum battery_cutoff_states {
	BATTERY_CUTOFF_STATE_NORMAL = 0,
	BATTERY_CUTOFF_STATE_CUT_OFF,
	BATTERY_CUTOFF_STATE_PENDING,
};

enum battery_disconnect_state {
	BATTERY_DISCONNECTED = 0,
	BATTERY_NOT_DISCONNECTED,
	BATTERY_DISCONNECT_ERROR,
};

/* Battery parameters */
struct batt_params {
	int temperature;      /* Temperature in 0.1 K */
	int state_of_charge;  /* State of charge (percent, 0-100) */
	int voltage;          /* Battery voltage (mV) */
	int current;          /* Battery current (mA); negative=discharging */
	int desired_voltage;  /* Charging voltage desired by battery (mV) */
	int desired_current;  /* Charging current desired by battery (mA) */
	int remaining_capacity;  /* Remaining capacity in mAh */
	int full_capacity;    /* Capacity in mAh (might change occasionally) */
	int display_charge;   /* Display charge in 10ths of a % (1000=100.0%) */
	int status;	      /* Battery status */
	enum battery_present is_present; /* Is the battery physically present */
	int flags;            /* Flags */
};

/*
 * Provide a 1 minute average of the current and voltage on the battery.
 * Does not check for flags or whether those values are bad readings.
 * See driver/battery/[your_driver].h/c for details on implementation and
 * how the average is calculated.
 */

int battery_get_avg_current(void); /* in mA */
int battery_get_avg_voltage(void); /* in mV */

/* Flags for batt_params */

/* Battery wants to be charged */
#define BATT_FLAG_WANT_CHARGE			0x00000001

/* Battery is responsive (talking to us via I2C) */
#define BATT_FLAG_RESPONSIVE			0x00000002

/* Bits to indicate which parameter(s) could not be read */
#define BATT_FLAG_BAD_TEMPERATURE		0x00000004
#define BATT_FLAG_BAD_STATE_OF_CHARGE		0x00000008
#define BATT_FLAG_BAD_VOLTAGE			0x00000010
#define BATT_FLAG_BAD_CURRENT			0x00000020
#define BATT_FLAG_BAD_DESIRED_VOLTAGE		0x00000040
#define BATT_FLAG_BAD_DESIRED_CURRENT		0x00000080
#define BATT_FLAG_BAD_REMAINING_CAPACITY	0x00000100
#define BATT_FLAG_BAD_FULL_CAPACITY		0x00000200
#define BATT_FLAG_BAD_STATUS			0x00000400
#define BATT_FLAG_IMBALANCED_CELL		0x00000800
#define BATT_FLAG_BAD_AVERAGE_CURRENT		0x00001000
/* All of the above BATT_FLAG_BAD_* bits */
#define BATT_FLAG_BAD_ANY			0x000017fc

/* Battery constants */
struct battery_info {
	/* Operation voltage in mV */
	int voltage_max;
	int voltage_normal;
	int voltage_min;
	/* (TODO(chromium:756700): add desired_charging_current */
	/**
	 * Pre-charge to fast charge threshold in mV,
	 * default to voltage_min if not specified.
	 * This option is only available on isl923x and rt946x.
	 */
	int precharge_voltage;
	/* Pre-charge current in mA */
	int precharge_current;
	/* Working temperature ranges in degrees C */
	int8_t start_charging_min_c;
	int8_t start_charging_max_c;
	int8_t charging_min_c;
	int8_t charging_max_c;
	int8_t discharging_min_c;
	int8_t discharging_max_c;
};

/**
 * Return vendor-provided battery constants.
 */
const struct battery_info *battery_get_info(void);

/**
 * Get current battery parameters.
 *
 * Error conditions are reported via batt.flags.
 *
 * @param batt		Destination for battery data
 */
void battery_get_params(struct batt_params *batt);

/**
 * Modify battery parameters to match vendor charging profile.
 *
 * @param batt		Battery parameters to modify
 */
void battery_override_params(struct batt_params *batt);

#if defined(CONFIG_BATTERY) || defined(CONFIG_BATTERY_PRESENT_CUSTOM)
/**
 * Check for presence of battery.
 *
 * @return Whether there is a battery attached or not, or if we can't tell.
 */
enum battery_present battery_is_present(void);
#else
/*
 * If battery support is not enabled and the board does not specifically
 * provide its own implementation, assume a battery is never present.
 */
static inline enum battery_present battery_is_present(void)
{
	return BP_NO;
}
#endif

/**
 * Check for physical presence of battery.
 *
 * @return Whether there is a battery physically present, but possibly
 * in a disconnected or cut off state, or if we can't tell;
 */
enum battery_present battery_hw_present(void);

/**
 * Check for battery initialization status.
 *
 * @return zero if not initialized.
 */
int board_battery_initialized(void);

/**
 * Get battery mode.
 *
 * See MODE_* constants in battery_smart.h
 *
 * @param mode         Destination for current mode.
 * @return non-zero if error.
 */
int battery_get_mode(int *mode);

/**
 * Read nominal voltage battery is designed to supply.
 *
 * @param voltage	Destination for voltage in mW
 * @return non-zero if error.
 */
int battery_design_voltage(int *voltage);

/**
 * Read absolute state of charge.
 *
 * @param percent	Destination for charge in percent
 * @return non-zero if error.
 */
int battery_state_of_charge_abs(int *percent);

/**
 * Read battery remaining capacity.
 *
 * @param capacity	Destination for capacity in mAh
 * @return non-zero if error.
 */
int battery_remaining_capacity(int *capacity);

/**
 * Read battery full charge capacity.
 *
 * @param capacity	Destination for capacity in mAh
 * @return non-zero if error.
 */
int battery_full_charge_capacity(int *capacity);

/**
 * Read the nominal capacity the battery is designed to supply when new.
 *
 * @param capacity	Destination for capacity in mAh
 * @return non-zero if error.
 */
int battery_design_capacity(int *capacity);

/**
 * Read time in minutes left when discharging.
 *
 * @param capacity	Destination for remaining time in minutes.
 * @return non-zero if error.
 */
int battery_time_to_empty(int *minutes);

/**
 * Read run time in minutes left when discharging.
 *
 * @param capacity	Destination for remaining time in minutes.
 * @return non-zero if error.
 */
int battery_run_time_to_empty(int *minutes);

/**
 * Read time in minutes left to full capacity when charging.
 *
 * @param capacity	Destination for remaining time in minutes.
 * @return non-zero if error.
 */
int battery_time_to_full(int *minutes);

/**
 * Calculate battery time in minutes, under an assumed current.
 *
 * @param rate		Current to use for calculation, in mA.
 *			If > 0, calculates charging time; if < 0, calculates
 *			discharging time; 0 is invalid and sets minutes=0.
 * @param minutes	Destination for calculated time in minutes.
 * @return non-zero if error.
 */
int battery_time_at_rate(int rate, int *minutes);

/**
 * Read battery status.
 *
 * @param status	Destination for status; see STATUS_* in battery_smart.h.
 * @return non-zero if error.
 */
int battery_status(int *status);

/**
 * Read battery charge cycle count.
 *
 * @param count		Destination for count.
 * @return non-zero if error.
 */
int battery_cycle_count(int *count);

/**
 * Read battery manufacture date.
 *
 * @param year		Destination for year
 * @param month		Destination for month
 * @param day		Destination for day
 * @return non-zero if error.
 */
int battery_manufacture_date(int *year, int *month, int *day);

/**
 * Read battery serial number.
 *
 * @param serial	Destination for serial number.
 * @return non-zero if error.
 */
int battery_serial_number(int *serial);

/**
 * Read manufacturer name.
 *
 * @param dest		Destination buffer.
 * @param size		Length of destination buffer in chars.
 * @return non-zero if error.
 */
int battery_manufacturer_name(char *dest, int size);

/**
 * Read manufacturer name.
 *
 * This can be overridden to return a chip or board custom string.
 *
 * @param dest		Destination buffer.
 * @param size		Length of destination buffer in chars.
 * @return non-zero if error.
 */
int get_battery_manufacturer_name(char *dest, int size);

/**
 * Read device name.
 *
 * @param dest		Destination buffer.
 * @param size		Length of destination buffer in chars.
 * @return non-zero if error.
 */
int battery_device_name(char *dest, int size);

/**
 * Read battery type/chemistry.
 *
 * @param dest		Destination buffer.
 * @param size		Length of destination buffer in chars.
 * @return non-zero if error.
 */
int battery_device_chemistry(char *dest, int size);

/**
 * Read device manufacture date.
 *
 * @param year		Destination for year
 * @param month		Destination for month
 * @param day		Destination for day
 * @return non-zero if error.
 */
int battery_manufacturer_date(int *year, int *month, int *day);

/**
 * Report the absolute difference between the highest and lowest cell voltage in
 * the battery pack, in millivolts.  On error or unimplemented, returns '0'.
 */
int battery_imbalance_mv(void);

/**
 * Call board-specific cut-off function.
 *
 * @return EC_RES_INVALID_COMMAND if the battery doesn't support.
 */
int board_cut_off_battery(void);

/**
 * Return if the battery has been cut off.
 */
int battery_is_cut_off(void);

/**
 * Read battery vendor parameter.
 *
 * Vendor parameter handlers are implemented in a board-specific battery.c
 *
 * @param param		Parameter identifier.
 * @param value		Location to store retrieved value.
 * @return non-zero if error.
 */
int battery_get_vendor_param(uint32_t param, uint32_t *value);

/**
 * Write battery vendor parameter.
 *
 * Vendor parameter handlers are implemented in a board-specific battery.c
 *
 * @param param		Parameter identifier.
 * @param value		Value to write to the battery.
 * @return non-zero if error.
 */
int battery_set_vendor_param(uint32_t param, uint32_t value);

/**
 * Wait for battery stable.
 *
 * @return non-zero if error.
 */
int battery_wait_for_stable(void);

/**
 * Print all battery info for debugging purposes
 */
void print_battery_debug(void);

/**
 * Get the disconnect state of the battery.
 */
enum battery_disconnect_state battery_get_disconnect_state(void);

#ifdef CONFIG_BATTERY_V2
/**
 * Refresh battery information in host memory mapped region, if index is
 * currently presented.
 */
void battery_memmap_refresh(enum battery_index index);

/**
 * Set which index to present in host memory mapped region.
 */
void battery_memmap_set_index(enum battery_index index);
#endif /* CONFIG_BATTERY_V2 */

#ifdef CONFIG_CMD_I2C_STRESS_TEST_BATTERY
extern struct i2c_stress_test_dev battery_i2c_stress_test_dev;
#endif

/*
 * If remaining charge is more than x% of the full capacity, the
 * remaining charge is raised to the full capacity before it's
 * reported to the rest of the system.
 *
 * Some batteries don't update full capacity timely or don't update it
 * at all. On such systems, compensation is required to guarantee
 * the remaining charge will be equal to the full capacity eventually.
 *
 * On some systems, Rohm charger generates audio noise when the battery
 * is fully charged and AC is plugged. A workaround is to do charge-
 * discharge cycles between 93 and 100%. On such systems, compensation
 * was also applied to mask this cycle from users.
 *
 * This used to be done in ACPI, thus, all software components except EC
 * was seeing the compensated charge. Now we do it in EC. It has more
 * knowledge on the charger and the battery. So, it can perform more
 * granular and precise compensation.
 *
 * TODO: Currently, this is applied only to smart battery. Apply it to other
 *       battery drivers as needed.
 */
void battery_compensate_params(struct batt_params *batt);

/**
 * board-specific battery_compensate_params
 */
__override_proto void board_battery_compensate_params(struct batt_params *batt);

void battery_validate_params(struct batt_params *batt);

#endif /* __CROS_EC_BATTERY_H */
