aboutsummaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
authorJohan Palsson <johan.palsson@stericsson.com>2011-03-04 11:05:09 +0100
committerJonas ABERG <jonas.aberg@stericsson.com>2011-03-07 10:57:17 +0100
commit4a81f851ec238fad6245084d013cb6b7935457dc (patch)
tree226bd61b34737abc68393821e17381e2c7c66b45 /drivers/power
parentde25423857112e0f846a4ce0aee999c1da2d9db9 (diff)
power: ab8500_bm: Use maximum charger current according to charger configuration
During configuration of the charger, a maximum charger current is set. The requested charger current will never be more than this. ST-Ericsson Linux next: - ST-Ericsson ID: WP324204 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I00e71ec126ff5f13fe1e1581020456d6609c788d Signed-off-by: Johan Palsson <johan.palsson@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/17417 Reviewed-by: Karl KOMIEROWSKI <karl.komierowski@stericsson.com> Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/ab8500_chargalg.c24
-rw-r--r--drivers/power/ab8500_charger.c137
2 files changed, 130 insertions, 31 deletions
diff --git a/drivers/power/ab8500_chargalg.c b/drivers/power/ab8500_chargalg.c
index 7f216bd7f0a..d09d830a5f6 100644
--- a/drivers/power/ab8500_chargalg.c
+++ b/drivers/power/ab8500_chargalg.c
@@ -613,21 +613,19 @@ static void ab8500_chargalg_check_temp(struct ab8500_chargalg *di)
}
/**
- * ab8500_chargalg_check_charger_health() - Check charger health
+ * ab8500_chargalg_check_charger_voltage() - Check charger voltage
* @di: pointer to the ab8500_chargalg structure
*
- * Charger voltage and current is checked against maximum limits
+ * Charger voltage is checked against maximum limit
*/
-static void ab8500_chargalg_check_charger_health(struct ab8500_chargalg *di)
+static void ab8500_chargalg_check_charger_voltage(struct ab8500_chargalg *di)
{
- if (di->chg_info.usb_volt > di->bat->chg_params->usb_volt_max ||
- di->chg_info.usb_curr > di->bat->chg_params->usb_curr_max)
+ if (di->chg_info.usb_volt > di->bat->chg_params->usb_volt_max)
di->chg_info.usb_chg_ok = false;
else
di->chg_info.usb_chg_ok = true;
- if (di->chg_info.ac_volt > di->bat->chg_params->ac_volt_max ||
- di->chg_info.ac_curr > di->bat->chg_params->ac_curr_max)
+ if (di->chg_info.ac_volt > di->bat->chg_params->ac_volt_max)
di->chg_info.ac_chg_ok = false;
else
di->chg_info.ac_chg_ok = true;
@@ -771,15 +769,21 @@ static enum maxim_ret ab8500_chargalg_chg_curr_maxim(struct ab8500_chargalg *di)
static void handle_maxim_chg_curr(struct ab8500_chargalg *di)
{
enum maxim_ret ret;
+ int result;
ret = ab8500_chargalg_chg_curr_maxim(di);
switch (ret) {
case MAXIM_RET_CHANGE:
- ab8500_chargalg_update_chg_curr(di, di->ccm.current_iset);
+ result = ab8500_chargalg_update_chg_curr(di,
+ di->ccm.current_iset);
+ if (result)
+ dev_err(di->dev, "failed to set chg curr\n");
break;
case MAXIM_RET_IBAT_TOO_HIGH:
- ab8500_chargalg_update_chg_curr(di,
+ result = ab8500_chargalg_update_chg_curr(di,
di->bat->bat_type[di->bat->batt_id].normal_cur_lvl);
+ if (result)
+ dev_err(di->dev, "failed to set chg curr\n");
break;
case MAXIM_RET_NOACTION:
@@ -1131,7 +1135,7 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
ab8500_chargalg_end_of_charge(di);
ab8500_chargalg_check_temp(di);
- ab8500_chargalg_check_charger_health(di);
+ ab8500_chargalg_check_charger_voltage(di);
charger_status = ab8500_chargalg_check_charger_connection(di);
/*
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 66e99be9e16..1bf6e23350f 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -46,6 +46,9 @@
#define VBUS_DET_DBNC1 0x01
#define OTP_ENABLE_WD 0x01
+#define MAIN_CH_INPUT_CURR_SHIFT 4
+#define VBUS_IN_CURR_LIM_SHIFT 4
+
#define LED_INDICATOR_PWM_ENA 0x01
#define LED_INDICATOR_PWM_DIS 0x00
#define LED_IND_CUR_5MA 0x04
@@ -99,6 +102,24 @@ enum ab8500_usb_state {
AB8500_BM_USB_STATE_MAX,
};
+/* VBUS input current limits supported in AB8500 in mA */
+#define USB_CH_IP_CUR_LVL_0P05 50
+#define USB_CH_IP_CUR_LVL_0P09 98
+#define USB_CH_IP_CUR_LVL_0P19 193
+#define USB_CH_IP_CUR_LVL_0P29 290
+#define USB_CH_IP_CUR_LVL_0P38 380
+#define USB_CH_IP_CUR_LVL_0P45 450
+#define USB_CH_IP_CUR_LVL_0P5 500
+#define USB_CH_IP_CUR_LVL_0P6 600
+#define USB_CH_IP_CUR_LVL_0P7 700
+#define USB_CH_IP_CUR_LVL_0P8 800
+#define USB_CH_IP_CUR_LVL_0P9 900
+#define USB_CH_IP_CUR_LVL_1P0 1000
+#define USB_CH_IP_CUR_LVL_1P1 1100
+#define USB_CH_IP_CUR_LVL_1P3 1300
+#define USB_CH_IP_CUR_LVL_1P4 1400
+#define USB_CH_IP_CUR_LVL_1P5 1500
+
#define to_ab8500_charger_usb_device_info(x) container_of((x), \
struct ab8500_charger, usb_chg)
#define to_ab8500_charger_ac_device_info(x) container_of((x), \
@@ -485,7 +506,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
break;
};
- dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: 0x%02x",
+ dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d",
link_status, di->max_usb_in_curr);
return ret;
@@ -680,6 +701,29 @@ static int ab8500_charger_current_map[] = {
1500 ,
};
+/*
+ * This array maps the raw hex value to VBUS input current used by the AB8500
+ * Values taken from the UM0836
+ */
+static int ab8500_charger_vbus_in_curr_map[] = {
+ USB_CH_IP_CUR_LVL_0P05,
+ USB_CH_IP_CUR_LVL_0P09,
+ USB_CH_IP_CUR_LVL_0P19,
+ USB_CH_IP_CUR_LVL_0P29,
+ USB_CH_IP_CUR_LVL_0P38,
+ USB_CH_IP_CUR_LVL_0P45,
+ USB_CH_IP_CUR_LVL_0P5,
+ USB_CH_IP_CUR_LVL_0P6,
+ USB_CH_IP_CUR_LVL_0P7,
+ USB_CH_IP_CUR_LVL_0P8,
+ USB_CH_IP_CUR_LVL_0P9,
+ USB_CH_IP_CUR_LVL_1P0,
+ USB_CH_IP_CUR_LVL_1P1,
+ USB_CH_IP_CUR_LVL_1P3,
+ USB_CH_IP_CUR_LVL_1P4,
+ USB_CH_IP_CUR_LVL_1P5,
+};
+
static int ab8500_voltage_to_regval(int voltage)
{
int i;
@@ -721,6 +765,26 @@ static int ab8500_current_to_regval(int curr)
return -1;
}
+static int ab8500_vbus_in_curr_to_regval(int curr)
+{
+ int i;
+
+ if (curr < ab8500_charger_vbus_in_curr_map[0])
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(ab8500_charger_vbus_in_curr_map); i++) {
+ if (curr < ab8500_charger_vbus_in_curr_map[i])
+ return i - 1;
+ }
+
+ /* If not last element, return error */
+ i = ARRAY_SIZE(ab8500_charger_vbus_in_curr_map) - 1;
+ if (curr == ab8500_charger_vbus_in_curr_map[i])
+ return i;
+ else
+ return -1;
+}
+
/**
* ab8500_charger_get_usb_cur() - get usb current
* @di: pointer to the ab8500_charger structre
@@ -757,6 +821,39 @@ static int ab8500_charger_get_usb_cur(struct ab8500_charger *di)
}
/**
+ * ab8500_charger_set_vbus_in_curr() - set VBUS input current limit
+ * @di: pointer to the ab8500_charger structure
+ * @ich_in: charger input current limit
+ *
+ * Sets the current that can be drawn from the USB host
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di,
+ int ich_in)
+{
+ int ret;
+ int input_curr_index;
+ int min_value;
+
+ /* We should always use to lowest current limit */
+ min_value = min(di->bat->chg_params->usb_curr_max, ich_in);
+
+ input_curr_index = ab8500_vbus_in_curr_to_regval(min_value);
+ if (input_curr_index < 0) {
+ dev_err(di->dev, "VBUS input current limit too high\n");
+ return -ENXIO;
+ }
+
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_USBCH_IPT_CRNTLVL_REG,
+ input_curr_index << VBUS_IN_CURR_LIM_SHIFT);
+ if (ret)
+ dev_err(di->dev, "%s write failed\n", __func__);
+
+ return ret;
+}
+
+/**
* ab8500_charger_led_en() - turn on/off chargign led
* @di: pointer to the ab8500_charger structure
* @on: flag to turn on/off the chargign led
@@ -815,6 +912,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger,
int ret;
int volt_index;
int curr_index;
+ int input_curr_index;
u8 overshoot = 0;
struct ab8500_charger *di = to_ab8500_charger_ac_device_info(charger);
@@ -832,7 +930,9 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger,
/* Check if the requested voltage or current is valid */
volt_index = ab8500_voltage_to_regval(vset);
curr_index = ab8500_current_to_regval(iset);
- if (volt_index < 0 || curr_index < 0) {
+ input_curr_index = ab8500_current_to_regval(
+ di->bat->chg_params->ac_curr_max);
+ if (volt_index < 0 || curr_index < 0 || input_curr_index < 0) {
dev_err(di->dev,
"Charger voltage or current too high, "
"charging not started\n");
@@ -848,7 +948,8 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger,
}
/* MainChInputCurr: current that can be drawn from the charger*/
ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
- AB8500_MCH_IPT_CURLVL_REG, MAIN_CH_IP_CUR_1P5A);
+ AB8500_MCH_IPT_CURLVL_REG,
+ input_curr_index << MAIN_CH_INPUT_CURR_SHIFT);
if (ret) {
dev_err(di->dev, "%s write failed\n", __func__);
return ret;
@@ -1001,11 +1102,9 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger,
return ret;
}
/* USBChInputCurr: current that can be drawn from the usb */
- ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
- AB8500_USBCH_IPT_CRNTLVL_REG,
- di->max_usb_in_curr);
+ ret = ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr);
if (ret) {
- dev_err(di->dev, "%s write failed\n", __func__);
+ dev_err(di->dev, "setting USBChInputCurr failed\n");
return ret;
}
/* ChOutputCurentLevel: protected output current */
@@ -1108,7 +1207,7 @@ static int ab8500_charger_update_charger_current(struct ux500_charger *charger,
curr_index = ab8500_current_to_regval(ich_out);
if (curr_index < 0) {
dev_err(di->dev,
- "Charger voltage or current too high, "
+ "Charger current too high, "
"charging not started\n");
return -ENXIO;
}
@@ -1322,13 +1421,11 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work)
ret = ab8500_charger_read_usb_type(di);
if (!ret) {
/* Update maximum input current */
- ret = abx500_set_register_interruptible(di->dev,
- AB8500_CHARGER, AB8500_USBCH_IPT_CRNTLVL_REG,
- di->max_usb_in_curr);
- if (ret) {
- dev_err(di->dev, "%s write failed\n", __func__);
+ ret = ab8500_charger_set_vbus_in_curr(di,
+ di->max_usb_in_curr);
+ if (ret)
return;
- }
+
di->usb.charger_connected = 1;
power_supply_changed(&di->usb_chg.psy);
} else if (ret == -ENXIO) {
@@ -1387,13 +1484,11 @@ static void ab8500_charger_usb_state_changed_work(struct work_struct *work)
*/
if (!ab8500_charger_get_usb_cur(di)) {
/* Update maximum input current */
- ret = abx500_set_register_interruptible(di->dev,
- AB8500_CHARGER, AB8500_USBCH_IPT_CRNTLVL_REG,
- di->max_usb_in_curr);
- if (ret) {
- dev_err(di->dev, "%s write failed\n", __func__);
+ ret = ab8500_charger_set_vbus_in_curr(di,
+ di->max_usb_in_curr);
+ if (ret)
return;
- }
+
di->usb.charger_connected = 1;
power_supply_changed(&di->usb_chg.psy);
}
@@ -2204,7 +2299,7 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev)
/* ux500_charger sub-class */
di->usb_chg.ops.enable = &ab8500_charger_usb_en;
di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick;
- di->ac_chg.ops.update_curr = &ab8500_charger_update_charger_current;
+ di->usb_chg.ops.update_curr = &ab8500_charger_update_charger_current;
di->usb_chg.max_out_volt = ab8500_charger_voltage_map[
ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
di->usb_chg.max_out_curr = ab8500_charger_current_map[