diff options
author | Anton Vorontsov <anton@enomsg.org> | 2013-01-05 20:14:22 -0500 |
---|---|---|
committer | Anton Vorontsov <anton@enomsg.org> | 2013-01-05 20:14:22 -0500 |
commit | 240fbe2347f1bb58c45fe07fd7c1e5ed96e2e983 (patch) | |
tree | 8481027b056197db888e51eae47a8f95931b84cb /drivers/power/ab8500_charger.c | |
parent | 2fbb520d2079186727786b728ebc5bf20fc85520 (diff) | |
parent | 215cf5c93d2deda4df38d0c9b2429ab2e86808a5 (diff) |
Merge branch 'for-anton' of git://git.linaro.org/people/ljones/linux-3.0-ux500
Diffstat (limited to 'drivers/power/ab8500_charger.c')
-rw-r--r-- | drivers/power/ab8500_charger.c | 222 |
1 files changed, 158 insertions, 64 deletions
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 3be9c0ee3fc5..e5755f0ba831 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c | |||
@@ -79,6 +79,9 @@ | |||
79 | /* Lowest charger voltage is 3.39V -> 0x4E */ | 79 | /* Lowest charger voltage is 3.39V -> 0x4E */ |
80 | #define LOW_VOLT_REG 0x4E | 80 | #define LOW_VOLT_REG 0x4E |
81 | 81 | ||
82 | /* Step up/down delay in us */ | ||
83 | #define STEP_UDELAY 1000 | ||
84 | |||
82 | /* UsbLineStatus register - usb types */ | 85 | /* UsbLineStatus register - usb types */ |
83 | enum ab8500_charger_link_status { | 86 | enum ab8500_charger_link_status { |
84 | USB_STAT_NOT_CONFIGURED, | 87 | USB_STAT_NOT_CONFIGURED, |
@@ -186,7 +189,7 @@ struct ab8500_charger_usb_state { | |||
186 | * @autopower_cfg platform specific power config support for "pwron after pwrloss" | 189 | * @autopower_cfg platform specific power config support for "pwron after pwrloss" |
187 | * @parent: Pointer to the struct ab8500 | 190 | * @parent: Pointer to the struct ab8500 |
188 | * @gpadc: Pointer to the struct gpadc | 191 | * @gpadc: Pointer to the struct gpadc |
189 | * @bat: Pointer to the abx500_bm platform data | 192 | * @bm: Platform specific battery management information |
190 | * @flags: Structure for information about events triggered | 193 | * @flags: Structure for information about events triggered |
191 | * @usb_state: Structure for usb stack information | 194 | * @usb_state: Structure for usb stack information |
192 | * @ac_chg: AC charger power supply | 195 | * @ac_chg: AC charger power supply |
@@ -223,7 +226,7 @@ struct ab8500_charger { | |||
223 | bool autopower_cfg; | 226 | bool autopower_cfg; |
224 | struct ab8500 *parent; | 227 | struct ab8500 *parent; |
225 | struct ab8500_gpadc *gpadc; | 228 | struct ab8500_gpadc *gpadc; |
226 | struct abx500_bm_data *bat; | 229 | struct abx500_bm_data *bm; |
227 | struct ab8500_charger_event_flags flags; | 230 | struct ab8500_charger_event_flags flags; |
228 | struct ab8500_charger_usb_state usb_state; | 231 | struct ab8500_charger_usb_state usb_state; |
229 | struct ux500_charger ac_chg; | 232 | struct ux500_charger ac_chg; |
@@ -936,6 +939,88 @@ static int ab8500_charger_get_usb_cur(struct ab8500_charger *di) | |||
936 | } | 939 | } |
937 | 940 | ||
938 | /** | 941 | /** |
942 | * ab8500_charger_set_current() - set charger current | ||
943 | * @di: pointer to the ab8500_charger structure | ||
944 | * @ich: charger current, in mA | ||
945 | * @reg: select what charger register to set | ||
946 | * | ||
947 | * Set charger current. | ||
948 | * There is no state machine in the AB to step up/down the charger | ||
949 | * current to avoid dips and spikes on MAIN, VBUS and VBAT when | ||
950 | * charging is started. Instead we need to implement | ||
951 | * this charger current step-up/down here. | ||
952 | * Returns error code in case of failure else 0(on success) | ||
953 | */ | ||
954 | static int ab8500_charger_set_current(struct ab8500_charger *di, | ||
955 | int ich, int reg) | ||
956 | { | ||
957 | int ret, i; | ||
958 | int curr_index, prev_curr_index, shift_value; | ||
959 | u8 reg_value; | ||
960 | |||
961 | switch (reg) { | ||
962 | case AB8500_MCH_IPT_CURLVL_REG: | ||
963 | shift_value = MAIN_CH_INPUT_CURR_SHIFT; | ||
964 | curr_index = ab8500_current_to_regval(ich); | ||
965 | break; | ||
966 | case AB8500_USBCH_IPT_CRNTLVL_REG: | ||
967 | shift_value = VBUS_IN_CURR_LIM_SHIFT; | ||
968 | curr_index = ab8500_vbus_in_curr_to_regval(ich); | ||
969 | break; | ||
970 | case AB8500_CH_OPT_CRNTLVL_REG: | ||
971 | shift_value = 0; | ||
972 | curr_index = ab8500_current_to_regval(ich); | ||
973 | break; | ||
974 | default: | ||
975 | dev_err(di->dev, "%s current register not valid\n", __func__); | ||
976 | return -ENXIO; | ||
977 | } | ||
978 | |||
979 | if (curr_index < 0) { | ||
980 | dev_err(di->dev, "requested current limit out-of-range\n"); | ||
981 | return -ENXIO; | ||
982 | } | ||
983 | |||
984 | ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, | ||
985 | reg, ®_value); | ||
986 | if (ret < 0) { | ||
987 | dev_err(di->dev, "%s read failed\n", __func__); | ||
988 | return ret; | ||
989 | } | ||
990 | prev_curr_index = (reg_value >> shift_value); | ||
991 | |||
992 | /* only update current if it's been changed */ | ||
993 | if (prev_curr_index == curr_index) | ||
994 | return 0; | ||
995 | |||
996 | dev_dbg(di->dev, "%s set charger current: %d mA for reg: 0x%02x\n", | ||
997 | __func__, ich, reg); | ||
998 | |||
999 | if (prev_curr_index > curr_index) { | ||
1000 | for (i = prev_curr_index - 1; i >= curr_index; i--) { | ||
1001 | ret = abx500_set_register_interruptible(di->dev, | ||
1002 | AB8500_CHARGER, reg, (u8) i << shift_value); | ||
1003 | if (ret) { | ||
1004 | dev_err(di->dev, "%s write failed\n", __func__); | ||
1005 | return ret; | ||
1006 | } | ||
1007 | usleep_range(STEP_UDELAY, STEP_UDELAY * 2); | ||
1008 | } | ||
1009 | } else { | ||
1010 | for (i = prev_curr_index + 1; i <= curr_index; i++) { | ||
1011 | ret = abx500_set_register_interruptible(di->dev, | ||
1012 | AB8500_CHARGER, reg, (u8) i << shift_value); | ||
1013 | if (ret) { | ||
1014 | dev_err(di->dev, "%s write failed\n", __func__); | ||
1015 | return ret; | ||
1016 | } | ||
1017 | usleep_range(STEP_UDELAY, STEP_UDELAY * 2); | ||
1018 | } | ||
1019 | } | ||
1020 | return ret; | ||
1021 | } | ||
1022 | |||
1023 | /** | ||
939 | * ab8500_charger_set_vbus_in_curr() - set VBUS input current limit | 1024 | * ab8500_charger_set_vbus_in_curr() - set VBUS input current limit |
940 | * @di: pointer to the ab8500_charger structure | 1025 | * @di: pointer to the ab8500_charger structure |
941 | * @ich_in: charger input current limit | 1026 | * @ich_in: charger input current limit |
@@ -946,12 +1031,10 @@ static int ab8500_charger_get_usb_cur(struct ab8500_charger *di) | |||
946 | static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, | 1031 | static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, |
947 | int ich_in) | 1032 | int ich_in) |
948 | { | 1033 | { |
949 | int ret; | ||
950 | int input_curr_index; | ||
951 | int min_value; | 1034 | int min_value; |
952 | 1035 | ||
953 | /* We should always use to lowest current limit */ | 1036 | /* We should always use to lowest current limit */ |
954 | min_value = min(di->bat->chg_params->usb_curr_max, ich_in); | 1037 | min_value = min(di->bm->chg_params->usb_curr_max, ich_in); |
955 | 1038 | ||
956 | switch (min_value) { | 1039 | switch (min_value) { |
957 | case 100: | 1040 | case 100: |
@@ -966,19 +1049,38 @@ static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, | |||
966 | break; | 1049 | break; |
967 | } | 1050 | } |
968 | 1051 | ||
969 | input_curr_index = ab8500_vbus_in_curr_to_regval(min_value); | 1052 | return ab8500_charger_set_current(di, min_value, |
970 | if (input_curr_index < 0) { | 1053 | AB8500_USBCH_IPT_CRNTLVL_REG); |
971 | dev_err(di->dev, "VBUS input current limit too high\n"); | 1054 | } |
972 | return -ENXIO; | ||
973 | } | ||
974 | 1055 | ||
975 | ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, | 1056 | /** |
976 | AB8500_USBCH_IPT_CRNTLVL_REG, | 1057 | * ab8500_charger_set_main_in_curr() - set main charger input current |
977 | input_curr_index << VBUS_IN_CURR_LIM_SHIFT); | 1058 | * @di: pointer to the ab8500_charger structure |
978 | if (ret) | 1059 | * @ich_in: input charger current, in mA |
979 | dev_err(di->dev, "%s write failed\n", __func__); | 1060 | * |
1061 | * Set main charger input current. | ||
1062 | * Returns error code in case of failure else 0(on success) | ||
1063 | */ | ||
1064 | static int ab8500_charger_set_main_in_curr(struct ab8500_charger *di, | ||
1065 | int ich_in) | ||
1066 | { | ||
1067 | return ab8500_charger_set_current(di, ich_in, | ||
1068 | AB8500_MCH_IPT_CURLVL_REG); | ||
1069 | } | ||
980 | 1070 | ||
981 | return ret; | 1071 | /** |
1072 | * ab8500_charger_set_output_curr() - set charger output current | ||
1073 | * @di: pointer to the ab8500_charger structure | ||
1074 | * @ich_out: output charger current, in mA | ||
1075 | * | ||
1076 | * Set charger output current. | ||
1077 | * Returns error code in case of failure else 0(on success) | ||
1078 | */ | ||
1079 | static int ab8500_charger_set_output_curr(struct ab8500_charger *di, | ||
1080 | int ich_out) | ||
1081 | { | ||
1082 | return ab8500_charger_set_current(di, ich_out, | ||
1083 | AB8500_CH_OPT_CRNTLVL_REG); | ||
982 | } | 1084 | } |
983 | 1085 | ||
984 | /** | 1086 | /** |
@@ -1074,7 +1176,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, | |||
1074 | volt_index = ab8500_voltage_to_regval(vset); | 1176 | volt_index = ab8500_voltage_to_regval(vset); |
1075 | curr_index = ab8500_current_to_regval(iset); | 1177 | curr_index = ab8500_current_to_regval(iset); |
1076 | input_curr_index = ab8500_current_to_regval( | 1178 | input_curr_index = ab8500_current_to_regval( |
1077 | di->bat->chg_params->ac_curr_max); | 1179 | di->bm->chg_params->ac_curr_max); |
1078 | if (volt_index < 0 || curr_index < 0 || input_curr_index < 0) { | 1180 | if (volt_index < 0 || curr_index < 0 || input_curr_index < 0) { |
1079 | dev_err(di->dev, | 1181 | dev_err(di->dev, |
1080 | "Charger voltage or current too high, " | 1182 | "Charger voltage or current too high, " |
@@ -1090,23 +1192,24 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, | |||
1090 | return ret; | 1192 | return ret; |
1091 | } | 1193 | } |
1092 | /* MainChInputCurr: current that can be drawn from the charger*/ | 1194 | /* MainChInputCurr: current that can be drawn from the charger*/ |
1093 | ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, | 1195 | ret = ab8500_charger_set_main_in_curr(di, |
1094 | AB8500_MCH_IPT_CURLVL_REG, | 1196 | di->bm->chg_params->ac_curr_max); |
1095 | input_curr_index << MAIN_CH_INPUT_CURR_SHIFT); | ||
1096 | if (ret) { | 1197 | if (ret) { |
1097 | dev_err(di->dev, "%s write failed\n", __func__); | 1198 | dev_err(di->dev, "%s Failed to set MainChInputCurr\n", |
1199 | __func__); | ||
1098 | return ret; | 1200 | return ret; |
1099 | } | 1201 | } |
1100 | /* ChOutputCurentLevel: protected output current */ | 1202 | /* ChOutputCurentLevel: protected output current */ |
1101 | ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, | 1203 | ret = ab8500_charger_set_output_curr(di, iset); |
1102 | AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index); | ||
1103 | if (ret) { | 1204 | if (ret) { |
1104 | dev_err(di->dev, "%s write failed\n", __func__); | 1205 | dev_err(di->dev, "%s " |
1206 | "Failed to set ChOutputCurentLevel\n", | ||
1207 | __func__); | ||
1105 | return ret; | 1208 | return ret; |
1106 | } | 1209 | } |
1107 | 1210 | ||
1108 | /* Check if VBAT overshoot control should be enabled */ | 1211 | /* Check if VBAT overshoot control should be enabled */ |
1109 | if (!di->bat->enable_overshoot) | 1212 | if (!di->bm->enable_overshoot) |
1110 | overshoot = MAIN_CH_NO_OVERSHOOT_ENA_N; | 1213 | overshoot = MAIN_CH_NO_OVERSHOOT_ENA_N; |
1111 | 1214 | ||
1112 | /* Enable Main Charger */ | 1215 | /* Enable Main Charger */ |
@@ -1158,12 +1261,11 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, | |||
1158 | return ret; | 1261 | return ret; |
1159 | } | 1262 | } |
1160 | 1263 | ||
1161 | ret = abx500_set_register_interruptible(di->dev, | 1264 | ret = ab8500_charger_set_output_curr(di, 0); |
1162 | AB8500_CHARGER, | ||
1163 | AB8500_CH_OPT_CRNTLVL_REG, CH_OP_CUR_LVL_0P1); | ||
1164 | if (ret) { | 1265 | if (ret) { |
1165 | dev_err(di->dev, | 1266 | dev_err(di->dev, "%s " |
1166 | "%s write failed\n", __func__); | 1267 | "Failed to set ChOutputCurentLevel\n", |
1268 | __func__); | ||
1167 | return ret; | 1269 | return ret; |
1168 | } | 1270 | } |
1169 | } else { | 1271 | } else { |
@@ -1266,14 +1368,15 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, | |||
1266 | return ret; | 1368 | return ret; |
1267 | } | 1369 | } |
1268 | /* ChOutputCurentLevel: protected output current */ | 1370 | /* ChOutputCurentLevel: protected output current */ |
1269 | ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, | 1371 | ret = ab8500_charger_set_output_curr(di, ich_out); |
1270 | AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index); | ||
1271 | if (ret) { | 1372 | if (ret) { |
1272 | dev_err(di->dev, "%s write failed\n", __func__); | 1373 | dev_err(di->dev, "%s " |
1374 | "Failed to set ChOutputCurentLevel\n", | ||
1375 | __func__); | ||
1273 | return ret; | 1376 | return ret; |
1274 | } | 1377 | } |
1275 | /* Check if VBAT overshoot control should be enabled */ | 1378 | /* Check if VBAT overshoot control should be enabled */ |
1276 | if (!di->bat->enable_overshoot) | 1379 | if (!di->bm->enable_overshoot) |
1277 | overshoot = USB_CHG_NO_OVERSHOOT_ENA_N; | 1380 | overshoot = USB_CHG_NO_OVERSHOOT_ENA_N; |
1278 | 1381 | ||
1279 | /* Enable USB Charger */ | 1382 | /* Enable USB Charger */ |
@@ -1366,7 +1469,6 @@ static int ab8500_charger_update_charger_current(struct ux500_charger *charger, | |||
1366 | int ich_out) | 1469 | int ich_out) |
1367 | { | 1470 | { |
1368 | int ret; | 1471 | int ret; |
1369 | int curr_index; | ||
1370 | struct ab8500_charger *di; | 1472 | struct ab8500_charger *di; |
1371 | 1473 | ||
1372 | if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS) | 1474 | if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS) |
@@ -1376,18 +1478,11 @@ static int ab8500_charger_update_charger_current(struct ux500_charger *charger, | |||
1376 | else | 1478 | else |
1377 | return -ENXIO; | 1479 | return -ENXIO; |
1378 | 1480 | ||
1379 | curr_index = ab8500_current_to_regval(ich_out); | 1481 | ret = ab8500_charger_set_output_curr(di, ich_out); |
1380 | if (curr_index < 0) { | ||
1381 | dev_err(di->dev, | ||
1382 | "Charger current too high, " | ||
1383 | "charging not started\n"); | ||
1384 | return -ENXIO; | ||
1385 | } | ||
1386 | |||
1387 | ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, | ||
1388 | AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index); | ||
1389 | if (ret) { | 1482 | if (ret) { |
1390 | dev_err(di->dev, "%s write failed\n", __func__); | 1483 | dev_err(di->dev, "%s " |
1484 | "Failed to set ChOutputCurentLevel\n", | ||
1485 | __func__); | ||
1391 | return ret; | 1486 | return ret; |
1392 | } | 1487 | } |
1393 | 1488 | ||
@@ -2359,8 +2454,8 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di) | |||
2359 | ret = abx500_set_register_interruptible(di->dev, | 2454 | ret = abx500_set_register_interruptible(di->dev, |
2360 | AB8500_RTC, | 2455 | AB8500_RTC, |
2361 | AB8500_RTC_BACKUP_CHG_REG, | 2456 | AB8500_RTC_BACKUP_CHG_REG, |
2362 | di->bat->bkup_bat_v | | 2457 | di->bm->bkup_bat_v | |
2363 | di->bat->bkup_bat_i); | 2458 | di->bm->bkup_bat_i); |
2364 | if (ret) { | 2459 | if (ret) { |
2365 | dev_err(di->dev, "failed to setup backup battery charging\n"); | 2460 | dev_err(di->dev, "failed to setup backup battery charging\n"); |
2366 | goto out; | 2461 | goto out; |
@@ -2541,6 +2636,7 @@ static char *supply_interface[] = { | |||
2541 | static int ab8500_charger_probe(struct platform_device *pdev) | 2636 | static int ab8500_charger_probe(struct platform_device *pdev) |
2542 | { | 2637 | { |
2543 | struct device_node *np = pdev->dev.of_node; | 2638 | struct device_node *np = pdev->dev.of_node; |
2639 | struct abx500_bm_data *plat = pdev->dev.platform_data; | ||
2544 | struct ab8500_charger *di; | 2640 | struct ab8500_charger *di; |
2545 | int irq, i, charger_status, ret = 0; | 2641 | int irq, i, charger_status, ret = 0; |
2546 | 2642 | ||
@@ -2549,24 +2645,22 @@ static int ab8500_charger_probe(struct platform_device *pdev) | |||
2549 | dev_err(&pdev->dev, "%s no mem for ab8500_charger\n", __func__); | 2645 | dev_err(&pdev->dev, "%s no mem for ab8500_charger\n", __func__); |
2550 | return -ENOMEM; | 2646 | return -ENOMEM; |
2551 | } | 2647 | } |
2552 | di->bat = pdev->mfd_cell->platform_data; | 2648 | |
2553 | if (!di->bat) { | 2649 | if (!plat) { |
2554 | if (np) { | 2650 | dev_err(&pdev->dev, "no battery management data supplied\n"); |
2555 | ret = bmdevs_of_probe(&pdev->dev, np, &di->bat); | 2651 | return -EINVAL; |
2556 | if (ret) { | 2652 | } |
2557 | dev_err(&pdev->dev, | 2653 | di->bm = plat; |
2558 | "failed to get battery information\n"); | 2654 | |
2559 | return ret; | 2655 | if (np) { |
2560 | } | 2656 | ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm); |
2561 | di->autopower_cfg = of_property_read_bool(np, "autopower_cfg"); | 2657 | if (ret) { |
2562 | } else { | 2658 | dev_err(&pdev->dev, "failed to get battery information\n"); |
2563 | dev_err(&pdev->dev, "missing dt node for ab8500_charger\n"); | 2659 | return ret; |
2564 | return -EINVAL; | ||
2565 | } | 2660 | } |
2566 | } else { | 2661 | di->autopower_cfg = of_property_read_bool(np, "autopower_cfg"); |
2567 | dev_info(&pdev->dev, "falling back to legacy platform data\n"); | 2662 | } else |
2568 | di->autopower_cfg = false; | 2663 | di->autopower_cfg = false; |
2569 | } | ||
2570 | 2664 | ||
2571 | /* get parent data */ | 2665 | /* get parent data */ |
2572 | di->dev = &pdev->dev; | 2666 | di->dev = &pdev->dev; |