18c0984e5SSebastian Reichel /* 28c0984e5SSebastian Reichel * Copyright (C) ST-Ericsson SA 2012 38c0984e5SSebastian Reichel * 48c0984e5SSebastian Reichel * Charger driver for AB8500 58c0984e5SSebastian Reichel * 68c0984e5SSebastian Reichel * License Terms: GNU General Public License v2 78c0984e5SSebastian Reichel * Author: 88c0984e5SSebastian Reichel * Johan Palsson <johan.palsson@stericsson.com> 98c0984e5SSebastian Reichel * Karl Komierowski <karl.komierowski@stericsson.com> 108c0984e5SSebastian Reichel * Arun R Murthy <arun.murthy@stericsson.com> 118c0984e5SSebastian Reichel */ 128c0984e5SSebastian Reichel 138c0984e5SSebastian Reichel #include <linux/init.h> 148c0984e5SSebastian Reichel #include <linux/module.h> 158c0984e5SSebastian Reichel #include <linux/device.h> 168c0984e5SSebastian Reichel #include <linux/interrupt.h> 178c0984e5SSebastian Reichel #include <linux/delay.h> 188c0984e5SSebastian Reichel #include <linux/notifier.h> 198c0984e5SSebastian Reichel #include <linux/slab.h> 208c0984e5SSebastian Reichel #include <linux/platform_device.h> 218c0984e5SSebastian Reichel #include <linux/power_supply.h> 228c0984e5SSebastian Reichel #include <linux/completion.h> 238c0984e5SSebastian Reichel #include <linux/regulator/consumer.h> 248c0984e5SSebastian Reichel #include <linux/err.h> 258c0984e5SSebastian Reichel #include <linux/workqueue.h> 268c0984e5SSebastian Reichel #include <linux/kobject.h> 278c0984e5SSebastian Reichel #include <linux/of.h> 288c0984e5SSebastian Reichel #include <linux/mfd/core.h> 298c0984e5SSebastian Reichel #include <linux/mfd/abx500/ab8500.h> 308c0984e5SSebastian Reichel #include <linux/mfd/abx500.h> 318c0984e5SSebastian Reichel #include <linux/mfd/abx500/ab8500-bm.h> 328c0984e5SSebastian Reichel #include <linux/mfd/abx500/ab8500-gpadc.h> 338c0984e5SSebastian Reichel #include <linux/mfd/abx500/ux500_chargalg.h> 348c0984e5SSebastian Reichel #include <linux/usb/otg.h> 358c0984e5SSebastian Reichel #include <linux/mutex.h> 368c0984e5SSebastian Reichel 378c0984e5SSebastian Reichel /* Charger constants */ 388c0984e5SSebastian Reichel #define NO_PW_CONN 0 398c0984e5SSebastian Reichel #define AC_PW_CONN 1 408c0984e5SSebastian Reichel #define USB_PW_CONN 2 418c0984e5SSebastian Reichel 428c0984e5SSebastian Reichel #define MAIN_WDOG_ENA 0x01 438c0984e5SSebastian Reichel #define MAIN_WDOG_KICK 0x02 448c0984e5SSebastian Reichel #define MAIN_WDOG_DIS 0x00 458c0984e5SSebastian Reichel #define CHARG_WD_KICK 0x01 468c0984e5SSebastian Reichel #define MAIN_CH_ENA 0x01 478c0984e5SSebastian Reichel #define MAIN_CH_NO_OVERSHOOT_ENA_N 0x02 488c0984e5SSebastian Reichel #define USB_CH_ENA 0x01 498c0984e5SSebastian Reichel #define USB_CHG_NO_OVERSHOOT_ENA_N 0x02 508c0984e5SSebastian Reichel #define MAIN_CH_DET 0x01 518c0984e5SSebastian Reichel #define MAIN_CH_CV_ON 0x04 528c0984e5SSebastian Reichel #define USB_CH_CV_ON 0x08 538c0984e5SSebastian Reichel #define VBUS_DET_DBNC100 0x02 548c0984e5SSebastian Reichel #define VBUS_DET_DBNC1 0x01 558c0984e5SSebastian Reichel #define OTP_ENABLE_WD 0x01 568c0984e5SSebastian Reichel #define DROP_COUNT_RESET 0x01 578c0984e5SSebastian Reichel #define USB_CH_DET 0x01 588c0984e5SSebastian Reichel 598c0984e5SSebastian Reichel #define MAIN_CH_INPUT_CURR_SHIFT 4 608c0984e5SSebastian Reichel #define VBUS_IN_CURR_LIM_SHIFT 4 618c0984e5SSebastian Reichel #define AB8540_VBUS_IN_CURR_LIM_SHIFT 2 628c0984e5SSebastian Reichel #define AUTO_VBUS_IN_CURR_LIM_SHIFT 4 638c0984e5SSebastian Reichel #define AB8540_AUTO_VBUS_IN_CURR_MASK 0x3F 648c0984e5SSebastian Reichel #define VBUS_IN_CURR_LIM_RETRY_SET_TIME 30 /* seconds */ 658c0984e5SSebastian Reichel 668c0984e5SSebastian Reichel #define LED_INDICATOR_PWM_ENA 0x01 678c0984e5SSebastian Reichel #define LED_INDICATOR_PWM_DIS 0x00 688c0984e5SSebastian Reichel #define LED_IND_CUR_5MA 0x04 698c0984e5SSebastian Reichel #define LED_INDICATOR_PWM_DUTY_252_256 0xBF 708c0984e5SSebastian Reichel 718c0984e5SSebastian Reichel /* HW failure constants */ 728c0984e5SSebastian Reichel #define MAIN_CH_TH_PROT 0x02 738c0984e5SSebastian Reichel #define VBUS_CH_NOK 0x08 748c0984e5SSebastian Reichel #define USB_CH_TH_PROT 0x02 758c0984e5SSebastian Reichel #define VBUS_OVV_TH 0x01 768c0984e5SSebastian Reichel #define MAIN_CH_NOK 0x01 778c0984e5SSebastian Reichel #define VBUS_DET 0x80 788c0984e5SSebastian Reichel 798c0984e5SSebastian Reichel #define MAIN_CH_STATUS2_MAINCHGDROP 0x80 808c0984e5SSebastian Reichel #define MAIN_CH_STATUS2_MAINCHARGERDETDBNC 0x40 818c0984e5SSebastian Reichel #define USB_CH_VBUSDROP 0x40 828c0984e5SSebastian Reichel #define USB_CH_VBUSDETDBNC 0x01 838c0984e5SSebastian Reichel 848c0984e5SSebastian Reichel /* UsbLineStatus register bit masks */ 858c0984e5SSebastian Reichel #define AB8500_USB_LINK_STATUS 0x78 868c0984e5SSebastian Reichel #define AB8505_USB_LINK_STATUS 0xF8 878c0984e5SSebastian Reichel #define AB8500_STD_HOST_SUSP 0x18 888c0984e5SSebastian Reichel #define USB_LINK_STATUS_SHIFT 3 898c0984e5SSebastian Reichel 908c0984e5SSebastian Reichel /* Watchdog timeout constant */ 918c0984e5SSebastian Reichel #define WD_TIMER 0x30 /* 4min */ 928c0984e5SSebastian Reichel #define WD_KICK_INTERVAL (60 * HZ) 938c0984e5SSebastian Reichel 948c0984e5SSebastian Reichel /* Lowest charger voltage is 3.39V -> 0x4E */ 958c0984e5SSebastian Reichel #define LOW_VOLT_REG 0x4E 968c0984e5SSebastian Reichel 978c0984e5SSebastian Reichel /* Step up/down delay in us */ 988c0984e5SSebastian Reichel #define STEP_UDELAY 1000 998c0984e5SSebastian Reichel 1008c0984e5SSebastian Reichel #define CHARGER_STATUS_POLL 10 /* in ms */ 1018c0984e5SSebastian Reichel 1028c0984e5SSebastian Reichel #define CHG_WD_INTERVAL (60 * HZ) 1038c0984e5SSebastian Reichel 1048c0984e5SSebastian Reichel #define AB8500_SW_CONTROL_FALLBACK 0x03 1058c0984e5SSebastian Reichel /* Wait for enumeration before charing in us */ 1068c0984e5SSebastian Reichel #define WAIT_ACA_RID_ENUMERATION (5 * 1000) 1078c0984e5SSebastian Reichel /*External charger control*/ 1088c0984e5SSebastian Reichel #define AB8500_SYS_CHARGER_CONTROL_REG 0x52 1098c0984e5SSebastian Reichel #define EXTERNAL_CHARGER_DISABLE_REG_VAL 0x03 1108c0984e5SSebastian Reichel #define EXTERNAL_CHARGER_ENABLE_REG_VAL 0x07 1118c0984e5SSebastian Reichel 1128c0984e5SSebastian Reichel /* UsbLineStatus register - usb types */ 1138c0984e5SSebastian Reichel enum ab8500_charger_link_status { 1148c0984e5SSebastian Reichel USB_STAT_NOT_CONFIGURED, 1158c0984e5SSebastian Reichel USB_STAT_STD_HOST_NC, 1168c0984e5SSebastian Reichel USB_STAT_STD_HOST_C_NS, 1178c0984e5SSebastian Reichel USB_STAT_STD_HOST_C_S, 1188c0984e5SSebastian Reichel USB_STAT_HOST_CHG_NM, 1198c0984e5SSebastian Reichel USB_STAT_HOST_CHG_HS, 1208c0984e5SSebastian Reichel USB_STAT_HOST_CHG_HS_CHIRP, 1218c0984e5SSebastian Reichel USB_STAT_DEDICATED_CHG, 1228c0984e5SSebastian Reichel USB_STAT_ACA_RID_A, 1238c0984e5SSebastian Reichel USB_STAT_ACA_RID_B, 1248c0984e5SSebastian Reichel USB_STAT_ACA_RID_C_NM, 1258c0984e5SSebastian Reichel USB_STAT_ACA_RID_C_HS, 1268c0984e5SSebastian Reichel USB_STAT_ACA_RID_C_HS_CHIRP, 1278c0984e5SSebastian Reichel USB_STAT_HM_IDGND, 1288c0984e5SSebastian Reichel USB_STAT_RESERVED, 1298c0984e5SSebastian Reichel USB_STAT_NOT_VALID_LINK, 1308c0984e5SSebastian Reichel USB_STAT_PHY_EN, 1318c0984e5SSebastian Reichel USB_STAT_SUP_NO_IDGND_VBUS, 1328c0984e5SSebastian Reichel USB_STAT_SUP_IDGND_VBUS, 1338c0984e5SSebastian Reichel USB_STAT_CHARGER_LINE_1, 1348c0984e5SSebastian Reichel USB_STAT_CARKIT_1, 1358c0984e5SSebastian Reichel USB_STAT_CARKIT_2, 1368c0984e5SSebastian Reichel USB_STAT_ACA_DOCK_CHARGER, 1378c0984e5SSebastian Reichel }; 1388c0984e5SSebastian Reichel 1398c0984e5SSebastian Reichel enum ab8500_usb_state { 1408c0984e5SSebastian Reichel AB8500_BM_USB_STATE_RESET_HS, /* HighSpeed Reset */ 1418c0984e5SSebastian Reichel AB8500_BM_USB_STATE_RESET_FS, /* FullSpeed/LowSpeed Reset */ 1428c0984e5SSebastian Reichel AB8500_BM_USB_STATE_CONFIGURED, 1438c0984e5SSebastian Reichel AB8500_BM_USB_STATE_SUSPEND, 1448c0984e5SSebastian Reichel AB8500_BM_USB_STATE_RESUME, 1458c0984e5SSebastian Reichel AB8500_BM_USB_STATE_MAX, 1468c0984e5SSebastian Reichel }; 1478c0984e5SSebastian Reichel 1488c0984e5SSebastian Reichel /* VBUS input current limits supported in AB8500 in mA */ 1498c0984e5SSebastian Reichel #define USB_CH_IP_CUR_LVL_0P05 50 1508c0984e5SSebastian Reichel #define USB_CH_IP_CUR_LVL_0P09 98 1518c0984e5SSebastian Reichel #define USB_CH_IP_CUR_LVL_0P19 193 1528c0984e5SSebastian Reichel #define USB_CH_IP_CUR_LVL_0P29 290 1538c0984e5SSebastian Reichel #define USB_CH_IP_CUR_LVL_0P38 380 1548c0984e5SSebastian Reichel #define USB_CH_IP_CUR_LVL_0P45 450 1558c0984e5SSebastian Reichel #define USB_CH_IP_CUR_LVL_0P5 500 1568c0984e5SSebastian Reichel #define USB_CH_IP_CUR_LVL_0P6 600 1578c0984e5SSebastian Reichel #define USB_CH_IP_CUR_LVL_0P7 700 1588c0984e5SSebastian Reichel #define USB_CH_IP_CUR_LVL_0P8 800 1598c0984e5SSebastian Reichel #define USB_CH_IP_CUR_LVL_0P9 900 1608c0984e5SSebastian Reichel #define USB_CH_IP_CUR_LVL_1P0 1000 1618c0984e5SSebastian Reichel #define USB_CH_IP_CUR_LVL_1P1 1100 1628c0984e5SSebastian Reichel #define USB_CH_IP_CUR_LVL_1P3 1300 1638c0984e5SSebastian Reichel #define USB_CH_IP_CUR_LVL_1P4 1400 1648c0984e5SSebastian Reichel #define USB_CH_IP_CUR_LVL_1P5 1500 1658c0984e5SSebastian Reichel 1668c0984e5SSebastian Reichel #define VBAT_TRESH_IP_CUR_RED 3800 1678c0984e5SSebastian Reichel 1688c0984e5SSebastian Reichel #define to_ab8500_charger_usb_device_info(x) container_of((x), \ 1698c0984e5SSebastian Reichel struct ab8500_charger, usb_chg) 1708c0984e5SSebastian Reichel #define to_ab8500_charger_ac_device_info(x) container_of((x), \ 1718c0984e5SSebastian Reichel struct ab8500_charger, ac_chg) 1728c0984e5SSebastian Reichel 1738c0984e5SSebastian Reichel /** 1748c0984e5SSebastian Reichel * struct ab8500_charger_interrupts - ab8500 interupts 1758c0984e5SSebastian Reichel * @name: name of the interrupt 1768c0984e5SSebastian Reichel * @isr function pointer to the isr 1778c0984e5SSebastian Reichel */ 1788c0984e5SSebastian Reichel struct ab8500_charger_interrupts { 1798c0984e5SSebastian Reichel char *name; 1808c0984e5SSebastian Reichel irqreturn_t (*isr)(int irq, void *data); 1818c0984e5SSebastian Reichel }; 1828c0984e5SSebastian Reichel 1838c0984e5SSebastian Reichel struct ab8500_charger_info { 1848c0984e5SSebastian Reichel int charger_connected; 1858c0984e5SSebastian Reichel int charger_online; 1868c0984e5SSebastian Reichel int charger_voltage; 1878c0984e5SSebastian Reichel int cv_active; 1888c0984e5SSebastian Reichel bool wd_expired; 1898c0984e5SSebastian Reichel int charger_current; 1908c0984e5SSebastian Reichel }; 1918c0984e5SSebastian Reichel 1928c0984e5SSebastian Reichel struct ab8500_charger_event_flags { 1938c0984e5SSebastian Reichel bool mainextchnotok; 1948c0984e5SSebastian Reichel bool main_thermal_prot; 1958c0984e5SSebastian Reichel bool usb_thermal_prot; 1968c0984e5SSebastian Reichel bool vbus_ovv; 1978c0984e5SSebastian Reichel bool usbchargernotok; 1988c0984e5SSebastian Reichel bool chgwdexp; 1998c0984e5SSebastian Reichel bool vbus_collapse; 2008c0984e5SSebastian Reichel bool vbus_drop_end; 2018c0984e5SSebastian Reichel }; 2028c0984e5SSebastian Reichel 2038c0984e5SSebastian Reichel struct ab8500_charger_usb_state { 2048c0984e5SSebastian Reichel int usb_current; 2058c0984e5SSebastian Reichel int usb_current_tmp; 2068c0984e5SSebastian Reichel enum ab8500_usb_state state; 2078c0984e5SSebastian Reichel enum ab8500_usb_state state_tmp; 2088c0984e5SSebastian Reichel spinlock_t usb_lock; 2098c0984e5SSebastian Reichel }; 2108c0984e5SSebastian Reichel 2118c0984e5SSebastian Reichel struct ab8500_charger_max_usb_in_curr { 2128c0984e5SSebastian Reichel int usb_type_max; 2138c0984e5SSebastian Reichel int set_max; 2148c0984e5SSebastian Reichel int calculated_max; 2158c0984e5SSebastian Reichel }; 2168c0984e5SSebastian Reichel 2178c0984e5SSebastian Reichel /** 2188c0984e5SSebastian Reichel * struct ab8500_charger - ab8500 Charger device information 2198c0984e5SSebastian Reichel * @dev: Pointer to the structure device 2208c0984e5SSebastian Reichel * @vbus_detected: VBUS detected 2218c0984e5SSebastian Reichel * @vbus_detected_start: 2228c0984e5SSebastian Reichel * VBUS detected during startup 2238c0984e5SSebastian Reichel * @ac_conn: This will be true when the AC charger has been plugged 2248c0984e5SSebastian Reichel * @vddadc_en_ac: Indicate if VDD ADC supply is enabled because AC 2258c0984e5SSebastian Reichel * charger is enabled 2268c0984e5SSebastian Reichel * @vddadc_en_usb: Indicate if VDD ADC supply is enabled because USB 2278c0984e5SSebastian Reichel * charger is enabled 2288c0984e5SSebastian Reichel * @vbat Battery voltage 2298c0984e5SSebastian Reichel * @old_vbat Previously measured battery voltage 2308c0984e5SSebastian Reichel * @usb_device_is_unrecognised USB device is unrecognised by the hardware 2318c0984e5SSebastian Reichel * @autopower Indicate if we should have automatic pwron after pwrloss 2328c0984e5SSebastian Reichel * @autopower_cfg platform specific power config support for "pwron after pwrloss" 2338c0984e5SSebastian Reichel * @invalid_charger_detect_state State when forcing AB to use invalid charger 2348c0984e5SSebastian Reichel * @is_aca_rid: Incicate if accessory is ACA type 2358c0984e5SSebastian Reichel * @current_stepping_sessions: 2368c0984e5SSebastian Reichel * Counter for current stepping sessions 2378c0984e5SSebastian Reichel * @parent: Pointer to the struct ab8500 2388c0984e5SSebastian Reichel * @gpadc: Pointer to the struct gpadc 2398c0984e5SSebastian Reichel * @bm: Platform specific battery management information 2408c0984e5SSebastian Reichel * @flags: Structure for information about events triggered 2418c0984e5SSebastian Reichel * @usb_state: Structure for usb stack information 2428c0984e5SSebastian Reichel * @max_usb_in_curr: Max USB charger input current 2438c0984e5SSebastian Reichel * @ac_chg: AC charger power supply 2448c0984e5SSebastian Reichel * @usb_chg: USB charger power supply 2458c0984e5SSebastian Reichel * @ac: Structure that holds the AC charger properties 2468c0984e5SSebastian Reichel * @usb: Structure that holds the USB charger properties 2478c0984e5SSebastian Reichel * @regu: Pointer to the struct regulator 2488c0984e5SSebastian Reichel * @charger_wq: Work queue for the IRQs and checking HW state 2498c0984e5SSebastian Reichel * @usb_ipt_crnt_lock: Lock to protect VBUS input current setting from mutuals 2508c0984e5SSebastian Reichel * @pm_lock: Lock to prevent system to suspend 2518c0984e5SSebastian Reichel * @check_vbat_work Work for checking vbat threshold to adjust vbus current 2528c0984e5SSebastian Reichel * @check_hw_failure_work: Work for checking HW state 2538c0984e5SSebastian Reichel * @check_usbchgnotok_work: Work for checking USB charger not ok status 2548c0984e5SSebastian Reichel * @kick_wd_work: Work for kicking the charger watchdog in case 2558c0984e5SSebastian Reichel * of ABB rev 1.* due to the watchog logic bug 2568c0984e5SSebastian Reichel * @ac_charger_attached_work: Work for checking if AC charger is still 2578c0984e5SSebastian Reichel * connected 2588c0984e5SSebastian Reichel * @usb_charger_attached_work: Work for checking if USB charger is still 2598c0984e5SSebastian Reichel * connected 2608c0984e5SSebastian Reichel * @ac_work: Work for checking AC charger connection 2618c0984e5SSebastian Reichel * @detect_usb_type_work: Work for detecting the USB type connected 2628c0984e5SSebastian Reichel * @usb_link_status_work: Work for checking the new USB link status 2638c0984e5SSebastian Reichel * @usb_state_changed_work: Work for checking USB state 2648c0984e5SSebastian Reichel * @attach_work: Work for detecting USB type 2658c0984e5SSebastian Reichel * @vbus_drop_end_work: Work for detecting VBUS drop end 2668c0984e5SSebastian Reichel * @check_main_thermal_prot_work: 2678c0984e5SSebastian Reichel * Work for checking Main thermal status 2688c0984e5SSebastian Reichel * @check_usb_thermal_prot_work: 2698c0984e5SSebastian Reichel * Work for checking USB thermal status 2708c0984e5SSebastian Reichel * @charger_attached_mutex: For controlling the wakelock 2718c0984e5SSebastian Reichel */ 2728c0984e5SSebastian Reichel struct ab8500_charger { 2738c0984e5SSebastian Reichel struct device *dev; 2748c0984e5SSebastian Reichel bool vbus_detected; 2758c0984e5SSebastian Reichel bool vbus_detected_start; 2768c0984e5SSebastian Reichel bool ac_conn; 2778c0984e5SSebastian Reichel bool vddadc_en_ac; 2788c0984e5SSebastian Reichel bool vddadc_en_usb; 2798c0984e5SSebastian Reichel int vbat; 2808c0984e5SSebastian Reichel int old_vbat; 2818c0984e5SSebastian Reichel bool usb_device_is_unrecognised; 2828c0984e5SSebastian Reichel bool autopower; 2838c0984e5SSebastian Reichel bool autopower_cfg; 2848c0984e5SSebastian Reichel int invalid_charger_detect_state; 2858c0984e5SSebastian Reichel int is_aca_rid; 2868c0984e5SSebastian Reichel atomic_t current_stepping_sessions; 2878c0984e5SSebastian Reichel struct ab8500 *parent; 2888c0984e5SSebastian Reichel struct ab8500_gpadc *gpadc; 2898c0984e5SSebastian Reichel struct abx500_bm_data *bm; 2908c0984e5SSebastian Reichel struct ab8500_charger_event_flags flags; 2918c0984e5SSebastian Reichel struct ab8500_charger_usb_state usb_state; 2928c0984e5SSebastian Reichel struct ab8500_charger_max_usb_in_curr max_usb_in_curr; 2938c0984e5SSebastian Reichel struct ux500_charger ac_chg; 2948c0984e5SSebastian Reichel struct ux500_charger usb_chg; 2958c0984e5SSebastian Reichel struct ab8500_charger_info ac; 2968c0984e5SSebastian Reichel struct ab8500_charger_info usb; 2978c0984e5SSebastian Reichel struct regulator *regu; 2988c0984e5SSebastian Reichel struct workqueue_struct *charger_wq; 2998c0984e5SSebastian Reichel struct mutex usb_ipt_crnt_lock; 3008c0984e5SSebastian Reichel struct delayed_work check_vbat_work; 3018c0984e5SSebastian Reichel struct delayed_work check_hw_failure_work; 3028c0984e5SSebastian Reichel struct delayed_work check_usbchgnotok_work; 3038c0984e5SSebastian Reichel struct delayed_work kick_wd_work; 3048c0984e5SSebastian Reichel struct delayed_work usb_state_changed_work; 3058c0984e5SSebastian Reichel struct delayed_work attach_work; 3068c0984e5SSebastian Reichel struct delayed_work ac_charger_attached_work; 3078c0984e5SSebastian Reichel struct delayed_work usb_charger_attached_work; 3088c0984e5SSebastian Reichel struct delayed_work vbus_drop_end_work; 3098c0984e5SSebastian Reichel struct work_struct ac_work; 3108c0984e5SSebastian Reichel struct work_struct detect_usb_type_work; 3118c0984e5SSebastian Reichel struct work_struct usb_link_status_work; 3128c0984e5SSebastian Reichel struct work_struct check_main_thermal_prot_work; 3138c0984e5SSebastian Reichel struct work_struct check_usb_thermal_prot_work; 3148c0984e5SSebastian Reichel struct usb_phy *usb_phy; 3158c0984e5SSebastian Reichel struct notifier_block nb; 3168c0984e5SSebastian Reichel struct mutex charger_attached_mutex; 3178c0984e5SSebastian Reichel }; 3188c0984e5SSebastian Reichel 3198c0984e5SSebastian Reichel /* AC properties */ 3208c0984e5SSebastian Reichel static enum power_supply_property ab8500_charger_ac_props[] = { 3218c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 3228c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 3238c0984e5SSebastian Reichel POWER_SUPPLY_PROP_ONLINE, 3248c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 3258c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_AVG, 3268c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 3278c0984e5SSebastian Reichel }; 3288c0984e5SSebastian Reichel 3298c0984e5SSebastian Reichel /* USB properties */ 3308c0984e5SSebastian Reichel static enum power_supply_property ab8500_charger_usb_props[] = { 3318c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 3328c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_AVG, 3338c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 3348c0984e5SSebastian Reichel POWER_SUPPLY_PROP_ONLINE, 3358c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 3368c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_AVG, 3378c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 3388c0984e5SSebastian Reichel }; 3398c0984e5SSebastian Reichel 3408c0984e5SSebastian Reichel /* 3418c0984e5SSebastian Reichel * Function for enabling and disabling sw fallback mode 3428c0984e5SSebastian Reichel * should always be disabled when no charger is connected. 3438c0984e5SSebastian Reichel */ 3448c0984e5SSebastian Reichel static void ab8500_enable_disable_sw_fallback(struct ab8500_charger *di, 3458c0984e5SSebastian Reichel bool fallback) 3468c0984e5SSebastian Reichel { 3478c0984e5SSebastian Reichel u8 val; 3488c0984e5SSebastian Reichel u8 reg; 3498c0984e5SSebastian Reichel u8 bank; 3508c0984e5SSebastian Reichel u8 bit; 3518c0984e5SSebastian Reichel int ret; 3528c0984e5SSebastian Reichel 3538c0984e5SSebastian Reichel dev_dbg(di->dev, "SW Fallback: %d\n", fallback); 3548c0984e5SSebastian Reichel 3558c0984e5SSebastian Reichel if (is_ab8500(di->parent)) { 3568c0984e5SSebastian Reichel bank = 0x15; 3578c0984e5SSebastian Reichel reg = 0x0; 3588c0984e5SSebastian Reichel bit = 3; 3598c0984e5SSebastian Reichel } else { 3608c0984e5SSebastian Reichel bank = AB8500_SYS_CTRL1_BLOCK; 3618c0984e5SSebastian Reichel reg = AB8500_SW_CONTROL_FALLBACK; 3628c0984e5SSebastian Reichel bit = 0; 3638c0984e5SSebastian Reichel } 3648c0984e5SSebastian Reichel 3658c0984e5SSebastian Reichel /* read the register containing fallback bit */ 3668c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, bank, reg, &val); 3678c0984e5SSebastian Reichel if (ret < 0) { 3688c0984e5SSebastian Reichel dev_err(di->dev, "%d read failed\n", __LINE__); 3698c0984e5SSebastian Reichel return; 3708c0984e5SSebastian Reichel } 3718c0984e5SSebastian Reichel 3728c0984e5SSebastian Reichel if (is_ab8500(di->parent)) { 3738c0984e5SSebastian Reichel /* enable the OPT emulation registers */ 3748c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x2); 3758c0984e5SSebastian Reichel if (ret) { 3768c0984e5SSebastian Reichel dev_err(di->dev, "%d write failed\n", __LINE__); 3778c0984e5SSebastian Reichel goto disable_otp; 3788c0984e5SSebastian Reichel } 3798c0984e5SSebastian Reichel } 3808c0984e5SSebastian Reichel 3818c0984e5SSebastian Reichel if (fallback) 3828c0984e5SSebastian Reichel val |= (1 << bit); 3838c0984e5SSebastian Reichel else 3848c0984e5SSebastian Reichel val &= ~(1 << bit); 3858c0984e5SSebastian Reichel 3868c0984e5SSebastian Reichel /* write back the changed fallback bit value to register */ 3878c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, bank, reg, val); 3888c0984e5SSebastian Reichel if (ret) { 3898c0984e5SSebastian Reichel dev_err(di->dev, "%d write failed\n", __LINE__); 3908c0984e5SSebastian Reichel } 3918c0984e5SSebastian Reichel 3928c0984e5SSebastian Reichel disable_otp: 3938c0984e5SSebastian Reichel if (is_ab8500(di->parent)) { 3948c0984e5SSebastian Reichel /* disable the set OTP registers again */ 3958c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x0); 3968c0984e5SSebastian Reichel if (ret) { 3978c0984e5SSebastian Reichel dev_err(di->dev, "%d write failed\n", __LINE__); 3988c0984e5SSebastian Reichel } 3998c0984e5SSebastian Reichel } 4008c0984e5SSebastian Reichel } 4018c0984e5SSebastian Reichel 4028c0984e5SSebastian Reichel /** 4038c0984e5SSebastian Reichel * ab8500_power_supply_changed - a wrapper with local extentions for 4048c0984e5SSebastian Reichel * power_supply_changed 4058c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 4068c0984e5SSebastian Reichel * @psy: pointer to power_supply_that have changed. 4078c0984e5SSebastian Reichel * 4088c0984e5SSebastian Reichel */ 4098c0984e5SSebastian Reichel static void ab8500_power_supply_changed(struct ab8500_charger *di, 4108c0984e5SSebastian Reichel struct power_supply *psy) 4118c0984e5SSebastian Reichel { 4128c0984e5SSebastian Reichel if (di->autopower_cfg) { 4138c0984e5SSebastian Reichel if (!di->usb.charger_connected && 4148c0984e5SSebastian Reichel !di->ac.charger_connected && 4158c0984e5SSebastian Reichel di->autopower) { 4168c0984e5SSebastian Reichel di->autopower = false; 4178c0984e5SSebastian Reichel ab8500_enable_disable_sw_fallback(di, false); 4188c0984e5SSebastian Reichel } else if (!di->autopower && 4198c0984e5SSebastian Reichel (di->ac.charger_connected || 4208c0984e5SSebastian Reichel di->usb.charger_connected)) { 4218c0984e5SSebastian Reichel di->autopower = true; 4228c0984e5SSebastian Reichel ab8500_enable_disable_sw_fallback(di, true); 4238c0984e5SSebastian Reichel } 4248c0984e5SSebastian Reichel } 4258c0984e5SSebastian Reichel power_supply_changed(psy); 4268c0984e5SSebastian Reichel } 4278c0984e5SSebastian Reichel 4288c0984e5SSebastian Reichel static void ab8500_charger_set_usb_connected(struct ab8500_charger *di, 4298c0984e5SSebastian Reichel bool connected) 4308c0984e5SSebastian Reichel { 4318c0984e5SSebastian Reichel if (connected != di->usb.charger_connected) { 4328c0984e5SSebastian Reichel dev_dbg(di->dev, "USB connected:%i\n", connected); 4338c0984e5SSebastian Reichel di->usb.charger_connected = connected; 4348c0984e5SSebastian Reichel 4358c0984e5SSebastian Reichel if (!connected) 4368c0984e5SSebastian Reichel di->flags.vbus_drop_end = false; 4378c0984e5SSebastian Reichel 4388c0984e5SSebastian Reichel sysfs_notify(&di->usb_chg.psy->dev.kobj, NULL, "present"); 4398c0984e5SSebastian Reichel 4408c0984e5SSebastian Reichel if (connected) { 4418c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 4428c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 4438c0984e5SSebastian Reichel 4448c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 4458c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 4468c0984e5SSebastian Reichel &di->usb_charger_attached_work, 4478c0984e5SSebastian Reichel HZ); 4488c0984e5SSebastian Reichel } else { 4498c0984e5SSebastian Reichel cancel_delayed_work_sync(&di->usb_charger_attached_work); 4508c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 4518c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 4528c0984e5SSebastian Reichel } 4538c0984e5SSebastian Reichel } 4548c0984e5SSebastian Reichel } 4558c0984e5SSebastian Reichel 4568c0984e5SSebastian Reichel /** 4578c0984e5SSebastian Reichel * ab8500_charger_get_ac_voltage() - get ac charger voltage 4588c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 4598c0984e5SSebastian Reichel * 4608c0984e5SSebastian Reichel * Returns ac charger voltage (on success) 4618c0984e5SSebastian Reichel */ 4628c0984e5SSebastian Reichel static int ab8500_charger_get_ac_voltage(struct ab8500_charger *di) 4638c0984e5SSebastian Reichel { 4648c0984e5SSebastian Reichel int vch; 4658c0984e5SSebastian Reichel 4668c0984e5SSebastian Reichel /* Only measure voltage if the charger is connected */ 4678c0984e5SSebastian Reichel if (di->ac.charger_connected) { 4688c0984e5SSebastian Reichel vch = ab8500_gpadc_convert(di->gpadc, MAIN_CHARGER_V); 4698c0984e5SSebastian Reichel if (vch < 0) 4708c0984e5SSebastian Reichel dev_err(di->dev, "%s gpadc conv failed,\n", __func__); 4718c0984e5SSebastian Reichel } else { 4728c0984e5SSebastian Reichel vch = 0; 4738c0984e5SSebastian Reichel } 4748c0984e5SSebastian Reichel return vch; 4758c0984e5SSebastian Reichel } 4768c0984e5SSebastian Reichel 4778c0984e5SSebastian Reichel /** 4788c0984e5SSebastian Reichel * ab8500_charger_ac_cv() - check if the main charger is in CV mode 4798c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 4808c0984e5SSebastian Reichel * 4818c0984e5SSebastian Reichel * Returns ac charger CV mode (on success) else error code 4828c0984e5SSebastian Reichel */ 4838c0984e5SSebastian Reichel static int ab8500_charger_ac_cv(struct ab8500_charger *di) 4848c0984e5SSebastian Reichel { 4858c0984e5SSebastian Reichel u8 val; 4868c0984e5SSebastian Reichel int ret = 0; 4878c0984e5SSebastian Reichel 4888c0984e5SSebastian Reichel /* Only check CV mode if the charger is online */ 4898c0984e5SSebastian Reichel if (di->ac.charger_online) { 4908c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 4918c0984e5SSebastian Reichel AB8500_CH_STATUS1_REG, &val); 4928c0984e5SSebastian Reichel if (ret < 0) { 4938c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 4948c0984e5SSebastian Reichel return 0; 4958c0984e5SSebastian Reichel } 4968c0984e5SSebastian Reichel 4978c0984e5SSebastian Reichel if (val & MAIN_CH_CV_ON) 4988c0984e5SSebastian Reichel ret = 1; 4998c0984e5SSebastian Reichel else 5008c0984e5SSebastian Reichel ret = 0; 5018c0984e5SSebastian Reichel } 5028c0984e5SSebastian Reichel 5038c0984e5SSebastian Reichel return ret; 5048c0984e5SSebastian Reichel } 5058c0984e5SSebastian Reichel 5068c0984e5SSebastian Reichel /** 5078c0984e5SSebastian Reichel * ab8500_charger_get_vbus_voltage() - get vbus voltage 5088c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 5098c0984e5SSebastian Reichel * 5108c0984e5SSebastian Reichel * This function returns the vbus voltage. 5118c0984e5SSebastian Reichel * Returns vbus voltage (on success) 5128c0984e5SSebastian Reichel */ 5138c0984e5SSebastian Reichel static int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di) 5148c0984e5SSebastian Reichel { 5158c0984e5SSebastian Reichel int vch; 5168c0984e5SSebastian Reichel 5178c0984e5SSebastian Reichel /* Only measure voltage if the charger is connected */ 5188c0984e5SSebastian Reichel if (di->usb.charger_connected) { 5198c0984e5SSebastian Reichel vch = ab8500_gpadc_convert(di->gpadc, VBUS_V); 5208c0984e5SSebastian Reichel if (vch < 0) 5218c0984e5SSebastian Reichel dev_err(di->dev, "%s gpadc conv failed\n", __func__); 5228c0984e5SSebastian Reichel } else { 5238c0984e5SSebastian Reichel vch = 0; 5248c0984e5SSebastian Reichel } 5258c0984e5SSebastian Reichel return vch; 5268c0984e5SSebastian Reichel } 5278c0984e5SSebastian Reichel 5288c0984e5SSebastian Reichel /** 5298c0984e5SSebastian Reichel * ab8500_charger_get_usb_current() - get usb charger current 5308c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 5318c0984e5SSebastian Reichel * 5328c0984e5SSebastian Reichel * This function returns the usb charger current. 5338c0984e5SSebastian Reichel * Returns usb current (on success) and error code on failure 5348c0984e5SSebastian Reichel */ 5358c0984e5SSebastian Reichel static int ab8500_charger_get_usb_current(struct ab8500_charger *di) 5368c0984e5SSebastian Reichel { 5378c0984e5SSebastian Reichel int ich; 5388c0984e5SSebastian Reichel 5398c0984e5SSebastian Reichel /* Only measure current if the charger is online */ 5408c0984e5SSebastian Reichel if (di->usb.charger_online) { 5418c0984e5SSebastian Reichel ich = ab8500_gpadc_convert(di->gpadc, USB_CHARGER_C); 5428c0984e5SSebastian Reichel if (ich < 0) 5438c0984e5SSebastian Reichel dev_err(di->dev, "%s gpadc conv failed\n", __func__); 5448c0984e5SSebastian Reichel } else { 5458c0984e5SSebastian Reichel ich = 0; 5468c0984e5SSebastian Reichel } 5478c0984e5SSebastian Reichel return ich; 5488c0984e5SSebastian Reichel } 5498c0984e5SSebastian Reichel 5508c0984e5SSebastian Reichel /** 5518c0984e5SSebastian Reichel * ab8500_charger_get_ac_current() - get ac charger current 5528c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 5538c0984e5SSebastian Reichel * 5548c0984e5SSebastian Reichel * This function returns the ac charger current. 5558c0984e5SSebastian Reichel * Returns ac current (on success) and error code on failure. 5568c0984e5SSebastian Reichel */ 5578c0984e5SSebastian Reichel static int ab8500_charger_get_ac_current(struct ab8500_charger *di) 5588c0984e5SSebastian Reichel { 5598c0984e5SSebastian Reichel int ich; 5608c0984e5SSebastian Reichel 5618c0984e5SSebastian Reichel /* Only measure current if the charger is online */ 5628c0984e5SSebastian Reichel if (di->ac.charger_online) { 5638c0984e5SSebastian Reichel ich = ab8500_gpadc_convert(di->gpadc, MAIN_CHARGER_C); 5648c0984e5SSebastian Reichel if (ich < 0) 5658c0984e5SSebastian Reichel dev_err(di->dev, "%s gpadc conv failed\n", __func__); 5668c0984e5SSebastian Reichel } else { 5678c0984e5SSebastian Reichel ich = 0; 5688c0984e5SSebastian Reichel } 5698c0984e5SSebastian Reichel return ich; 5708c0984e5SSebastian Reichel } 5718c0984e5SSebastian Reichel 5728c0984e5SSebastian Reichel /** 5738c0984e5SSebastian Reichel * ab8500_charger_usb_cv() - check if the usb charger is in CV mode 5748c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 5758c0984e5SSebastian Reichel * 5768c0984e5SSebastian Reichel * Returns ac charger CV mode (on success) else error code 5778c0984e5SSebastian Reichel */ 5788c0984e5SSebastian Reichel static int ab8500_charger_usb_cv(struct ab8500_charger *di) 5798c0984e5SSebastian Reichel { 5808c0984e5SSebastian Reichel int ret; 5818c0984e5SSebastian Reichel u8 val; 5828c0984e5SSebastian Reichel 5838c0984e5SSebastian Reichel /* Only check CV mode if the charger is online */ 5848c0984e5SSebastian Reichel if (di->usb.charger_online) { 5858c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 5868c0984e5SSebastian Reichel AB8500_CH_USBCH_STAT1_REG, &val); 5878c0984e5SSebastian Reichel if (ret < 0) { 5888c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 5898c0984e5SSebastian Reichel return 0; 5908c0984e5SSebastian Reichel } 5918c0984e5SSebastian Reichel 5928c0984e5SSebastian Reichel if (val & USB_CH_CV_ON) 5938c0984e5SSebastian Reichel ret = 1; 5948c0984e5SSebastian Reichel else 5958c0984e5SSebastian Reichel ret = 0; 5968c0984e5SSebastian Reichel } else { 5978c0984e5SSebastian Reichel ret = 0; 5988c0984e5SSebastian Reichel } 5998c0984e5SSebastian Reichel 6008c0984e5SSebastian Reichel return ret; 6018c0984e5SSebastian Reichel } 6028c0984e5SSebastian Reichel 6038c0984e5SSebastian Reichel /** 6048c0984e5SSebastian Reichel * ab8500_charger_detect_chargers() - Detect the connected chargers 6058c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 6068c0984e5SSebastian Reichel * @probe: if probe, don't delay and wait for HW 6078c0984e5SSebastian Reichel * 6088c0984e5SSebastian Reichel * Returns the type of charger connected. 6098c0984e5SSebastian Reichel * For USB it will not mean we can actually charge from it 6108c0984e5SSebastian Reichel * but that there is a USB cable connected that we have to 6118c0984e5SSebastian Reichel * identify. This is used during startup when we don't get 6128c0984e5SSebastian Reichel * interrupts of the charger detection 6138c0984e5SSebastian Reichel * 6148c0984e5SSebastian Reichel * Returns an integer value, that means, 6158c0984e5SSebastian Reichel * NO_PW_CONN no power supply is connected 6168c0984e5SSebastian Reichel * AC_PW_CONN if the AC power supply is connected 6178c0984e5SSebastian Reichel * USB_PW_CONN if the USB power supply is connected 6188c0984e5SSebastian Reichel * AC_PW_CONN + USB_PW_CONN if USB and AC power supplies are both connected 6198c0984e5SSebastian Reichel */ 6208c0984e5SSebastian Reichel static int ab8500_charger_detect_chargers(struct ab8500_charger *di, bool probe) 6218c0984e5SSebastian Reichel { 6228c0984e5SSebastian Reichel int result = NO_PW_CONN; 6238c0984e5SSebastian Reichel int ret; 6248c0984e5SSebastian Reichel u8 val; 6258c0984e5SSebastian Reichel 6268c0984e5SSebastian Reichel /* Check for AC charger */ 6278c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 6288c0984e5SSebastian Reichel AB8500_CH_STATUS1_REG, &val); 6298c0984e5SSebastian Reichel if (ret < 0) { 6308c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 6318c0984e5SSebastian Reichel return ret; 6328c0984e5SSebastian Reichel } 6338c0984e5SSebastian Reichel 6348c0984e5SSebastian Reichel if (val & MAIN_CH_DET) 6358c0984e5SSebastian Reichel result = AC_PW_CONN; 6368c0984e5SSebastian Reichel 6378c0984e5SSebastian Reichel /* Check for USB charger */ 6388c0984e5SSebastian Reichel 6398c0984e5SSebastian Reichel if (!probe) { 6408c0984e5SSebastian Reichel /* 6418c0984e5SSebastian Reichel * AB8500 says VBUS_DET_DBNC1 & VBUS_DET_DBNC100 6428c0984e5SSebastian Reichel * when disconnecting ACA even though no 6438c0984e5SSebastian Reichel * charger was connected. Try waiting a little 6448c0984e5SSebastian Reichel * longer than the 100 ms of VBUS_DET_DBNC100... 6458c0984e5SSebastian Reichel */ 6468c0984e5SSebastian Reichel msleep(110); 6478c0984e5SSebastian Reichel } 6488c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 6498c0984e5SSebastian Reichel AB8500_CH_USBCH_STAT1_REG, &val); 6508c0984e5SSebastian Reichel if (ret < 0) { 6518c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 6528c0984e5SSebastian Reichel return ret; 6538c0984e5SSebastian Reichel } 6548c0984e5SSebastian Reichel dev_dbg(di->dev, 6558c0984e5SSebastian Reichel "%s AB8500_CH_USBCH_STAT1_REG %x\n", __func__, 6568c0984e5SSebastian Reichel val); 6578c0984e5SSebastian Reichel if ((val & VBUS_DET_DBNC1) && (val & VBUS_DET_DBNC100)) 6588c0984e5SSebastian Reichel result |= USB_PW_CONN; 6598c0984e5SSebastian Reichel 6608c0984e5SSebastian Reichel return result; 6618c0984e5SSebastian Reichel } 6628c0984e5SSebastian Reichel 6638c0984e5SSebastian Reichel /** 6648c0984e5SSebastian Reichel * ab8500_charger_max_usb_curr() - get the max curr for the USB type 6658c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 6668c0984e5SSebastian Reichel * @link_status: the identified USB type 6678c0984e5SSebastian Reichel * 6688c0984e5SSebastian Reichel * Get the maximum current that is allowed to be drawn from the host 6698c0984e5SSebastian Reichel * based on the USB type. 6708c0984e5SSebastian Reichel * Returns error code in case of failure else 0 on success 6718c0984e5SSebastian Reichel */ 6728c0984e5SSebastian Reichel static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, 6738c0984e5SSebastian Reichel enum ab8500_charger_link_status link_status) 6748c0984e5SSebastian Reichel { 6758c0984e5SSebastian Reichel int ret = 0; 6768c0984e5SSebastian Reichel 6778c0984e5SSebastian Reichel di->usb_device_is_unrecognised = false; 6788c0984e5SSebastian Reichel 6798c0984e5SSebastian Reichel /* 6808c0984e5SSebastian Reichel * Platform only supports USB 2.0. 6818c0984e5SSebastian Reichel * This means that charging current from USB source 6828c0984e5SSebastian Reichel * is maximum 500 mA. Every occurence of USB_STAT_*_HOST_* 6838c0984e5SSebastian Reichel * should set USB_CH_IP_CUR_LVL_0P5. 6848c0984e5SSebastian Reichel */ 6858c0984e5SSebastian Reichel 6868c0984e5SSebastian Reichel switch (link_status) { 6878c0984e5SSebastian Reichel case USB_STAT_STD_HOST_NC: 6888c0984e5SSebastian Reichel case USB_STAT_STD_HOST_C_NS: 6898c0984e5SSebastian Reichel case USB_STAT_STD_HOST_C_S: 6908c0984e5SSebastian Reichel dev_dbg(di->dev, "USB Type - Standard host is " 6918c0984e5SSebastian Reichel "detected through USB driver\n"); 6928c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; 6938c0984e5SSebastian Reichel di->is_aca_rid = 0; 6948c0984e5SSebastian Reichel break; 6958c0984e5SSebastian Reichel case USB_STAT_HOST_CHG_HS_CHIRP: 6968c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; 6978c0984e5SSebastian Reichel di->is_aca_rid = 0; 6988c0984e5SSebastian Reichel break; 6998c0984e5SSebastian Reichel case USB_STAT_HOST_CHG_HS: 7008c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; 7018c0984e5SSebastian Reichel di->is_aca_rid = 0; 7028c0984e5SSebastian Reichel break; 7038c0984e5SSebastian Reichel case USB_STAT_ACA_RID_C_HS: 7048c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P9; 7058c0984e5SSebastian Reichel di->is_aca_rid = 0; 7068c0984e5SSebastian Reichel break; 7078c0984e5SSebastian Reichel case USB_STAT_ACA_RID_A: 7088c0984e5SSebastian Reichel /* 7098c0984e5SSebastian Reichel * Dedicated charger level minus maximum current accessory 7108c0984e5SSebastian Reichel * can consume (900mA). Closest level is 500mA 7118c0984e5SSebastian Reichel */ 7128c0984e5SSebastian Reichel dev_dbg(di->dev, "USB_STAT_ACA_RID_A detected\n"); 7138c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; 7148c0984e5SSebastian Reichel di->is_aca_rid = 1; 7158c0984e5SSebastian Reichel break; 7168c0984e5SSebastian Reichel case USB_STAT_ACA_RID_B: 7178c0984e5SSebastian Reichel /* 7188c0984e5SSebastian Reichel * Dedicated charger level minus 120mA (20mA for ACA and 7198c0984e5SSebastian Reichel * 100mA for potential accessory). Closest level is 1300mA 7208c0984e5SSebastian Reichel */ 7218c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_1P3; 7228c0984e5SSebastian Reichel dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status, 7238c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max); 7248c0984e5SSebastian Reichel di->is_aca_rid = 1; 7258c0984e5SSebastian Reichel break; 7268c0984e5SSebastian Reichel case USB_STAT_HOST_CHG_NM: 7278c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; 7288c0984e5SSebastian Reichel di->is_aca_rid = 0; 7298c0984e5SSebastian Reichel break; 7308c0984e5SSebastian Reichel case USB_STAT_DEDICATED_CHG: 7318c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_1P5; 7328c0984e5SSebastian Reichel di->is_aca_rid = 0; 7338c0984e5SSebastian Reichel break; 7348c0984e5SSebastian Reichel case USB_STAT_ACA_RID_C_HS_CHIRP: 7358c0984e5SSebastian Reichel case USB_STAT_ACA_RID_C_NM: 7368c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_1P5; 7378c0984e5SSebastian Reichel di->is_aca_rid = 1; 7388c0984e5SSebastian Reichel break; 7398c0984e5SSebastian Reichel case USB_STAT_NOT_CONFIGURED: 7408c0984e5SSebastian Reichel if (di->vbus_detected) { 7418c0984e5SSebastian Reichel di->usb_device_is_unrecognised = true; 7428c0984e5SSebastian Reichel dev_dbg(di->dev, "USB Type - Legacy charger.\n"); 7438c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = 7448c0984e5SSebastian Reichel USB_CH_IP_CUR_LVL_1P5; 7458c0984e5SSebastian Reichel break; 7468c0984e5SSebastian Reichel } 7478c0984e5SSebastian Reichel case USB_STAT_HM_IDGND: 7488c0984e5SSebastian Reichel dev_err(di->dev, "USB Type - Charging not allowed\n"); 7498c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05; 7508c0984e5SSebastian Reichel ret = -ENXIO; 7518c0984e5SSebastian Reichel break; 7528c0984e5SSebastian Reichel case USB_STAT_RESERVED: 7538c0984e5SSebastian Reichel if (is_ab8500(di->parent)) { 7548c0984e5SSebastian Reichel di->flags.vbus_collapse = true; 7558c0984e5SSebastian Reichel dev_err(di->dev, "USB Type - USB_STAT_RESERVED " 7568c0984e5SSebastian Reichel "VBUS has collapsed\n"); 7578c0984e5SSebastian Reichel ret = -ENXIO; 7588c0984e5SSebastian Reichel break; 7598c0984e5SSebastian Reichel } else { 7608c0984e5SSebastian Reichel dev_dbg(di->dev, "USB Type - Charging not allowed\n"); 7618c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = 7628c0984e5SSebastian Reichel USB_CH_IP_CUR_LVL_0P05; 7638c0984e5SSebastian Reichel dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", 7648c0984e5SSebastian Reichel link_status, 7658c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max); 7668c0984e5SSebastian Reichel ret = -ENXIO; 7678c0984e5SSebastian Reichel break; 7688c0984e5SSebastian Reichel } 7698c0984e5SSebastian Reichel case USB_STAT_CARKIT_1: 7708c0984e5SSebastian Reichel case USB_STAT_CARKIT_2: 7718c0984e5SSebastian Reichel case USB_STAT_ACA_DOCK_CHARGER: 7728c0984e5SSebastian Reichel case USB_STAT_CHARGER_LINE_1: 7738c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; 7748c0984e5SSebastian Reichel dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status, 7758c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max); 7768c0984e5SSebastian Reichel break; 7778c0984e5SSebastian Reichel case USB_STAT_NOT_VALID_LINK: 7788c0984e5SSebastian Reichel dev_err(di->dev, "USB Type invalid - try charging anyway\n"); 7798c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; 7808c0984e5SSebastian Reichel break; 7818c0984e5SSebastian Reichel 7828c0984e5SSebastian Reichel default: 7838c0984e5SSebastian Reichel dev_err(di->dev, "USB Type - Unknown\n"); 7848c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05; 7858c0984e5SSebastian Reichel ret = -ENXIO; 7868c0984e5SSebastian Reichel break; 7878c0984e5SSebastian Reichel }; 7888c0984e5SSebastian Reichel 7898c0984e5SSebastian Reichel di->max_usb_in_curr.set_max = di->max_usb_in_curr.usb_type_max; 7908c0984e5SSebastian Reichel dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", 7918c0984e5SSebastian Reichel link_status, di->max_usb_in_curr.set_max); 7928c0984e5SSebastian Reichel 7938c0984e5SSebastian Reichel return ret; 7948c0984e5SSebastian Reichel } 7958c0984e5SSebastian Reichel 7968c0984e5SSebastian Reichel /** 7978c0984e5SSebastian Reichel * ab8500_charger_read_usb_type() - read the type of usb connected 7988c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 7998c0984e5SSebastian Reichel * 8008c0984e5SSebastian Reichel * Detect the type of the plugged USB 8018c0984e5SSebastian Reichel * Returns error code in case of failure else 0 on success 8028c0984e5SSebastian Reichel */ 8038c0984e5SSebastian Reichel static int ab8500_charger_read_usb_type(struct ab8500_charger *di) 8048c0984e5SSebastian Reichel { 8058c0984e5SSebastian Reichel int ret; 8068c0984e5SSebastian Reichel u8 val; 8078c0984e5SSebastian Reichel 8088c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 8098c0984e5SSebastian Reichel AB8500_INTERRUPT, AB8500_IT_SOURCE21_REG, &val); 8108c0984e5SSebastian Reichel if (ret < 0) { 8118c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 8128c0984e5SSebastian Reichel return ret; 8138c0984e5SSebastian Reichel } 8148c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 8158c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_USB, 8168c0984e5SSebastian Reichel AB8500_USB_LINE_STAT_REG, &val); 8178c0984e5SSebastian Reichel else 8188c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 8198c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val); 8208c0984e5SSebastian Reichel if (ret < 0) { 8218c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 8228c0984e5SSebastian Reichel return ret; 8238c0984e5SSebastian Reichel } 8248c0984e5SSebastian Reichel 8258c0984e5SSebastian Reichel /* get the USB type */ 8268c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 8278c0984e5SSebastian Reichel val = (val & AB8500_USB_LINK_STATUS) >> USB_LINK_STATUS_SHIFT; 8288c0984e5SSebastian Reichel else 8298c0984e5SSebastian Reichel val = (val & AB8505_USB_LINK_STATUS) >> USB_LINK_STATUS_SHIFT; 8308c0984e5SSebastian Reichel ret = ab8500_charger_max_usb_curr(di, 8318c0984e5SSebastian Reichel (enum ab8500_charger_link_status) val); 8328c0984e5SSebastian Reichel 8338c0984e5SSebastian Reichel return ret; 8348c0984e5SSebastian Reichel } 8358c0984e5SSebastian Reichel 8368c0984e5SSebastian Reichel /** 8378c0984e5SSebastian Reichel * ab8500_charger_detect_usb_type() - get the type of usb connected 8388c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 8398c0984e5SSebastian Reichel * 8408c0984e5SSebastian Reichel * Detect the type of the plugged USB 8418c0984e5SSebastian Reichel * Returns error code in case of failure else 0 on success 8428c0984e5SSebastian Reichel */ 8438c0984e5SSebastian Reichel static int ab8500_charger_detect_usb_type(struct ab8500_charger *di) 8448c0984e5SSebastian Reichel { 8458c0984e5SSebastian Reichel int i, ret; 8468c0984e5SSebastian Reichel u8 val; 8478c0984e5SSebastian Reichel 8488c0984e5SSebastian Reichel /* 8498c0984e5SSebastian Reichel * On getting the VBUS rising edge detect interrupt there 8508c0984e5SSebastian Reichel * is a 250ms delay after which the register UsbLineStatus 8518c0984e5SSebastian Reichel * is filled with valid data. 8528c0984e5SSebastian Reichel */ 8538c0984e5SSebastian Reichel for (i = 0; i < 10; i++) { 8548c0984e5SSebastian Reichel msleep(250); 8558c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 8568c0984e5SSebastian Reichel AB8500_INTERRUPT, AB8500_IT_SOURCE21_REG, 8578c0984e5SSebastian Reichel &val); 8588c0984e5SSebastian Reichel dev_dbg(di->dev, "%s AB8500_IT_SOURCE21_REG %x\n", 8598c0984e5SSebastian Reichel __func__, val); 8608c0984e5SSebastian Reichel if (ret < 0) { 8618c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 8628c0984e5SSebastian Reichel return ret; 8638c0984e5SSebastian Reichel } 8648c0984e5SSebastian Reichel 8658c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 8668c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 8678c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINE_STAT_REG, &val); 8688c0984e5SSebastian Reichel else 8698c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 8708c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val); 8718c0984e5SSebastian Reichel if (ret < 0) { 8728c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 8738c0984e5SSebastian Reichel return ret; 8748c0984e5SSebastian Reichel } 8758c0984e5SSebastian Reichel dev_dbg(di->dev, "%s AB8500_USB_LINE_STAT_REG %x\n", __func__, 8768c0984e5SSebastian Reichel val); 8778c0984e5SSebastian Reichel /* 8788c0984e5SSebastian Reichel * Until the IT source register is read the UsbLineStatus 8798c0984e5SSebastian Reichel * register is not updated, hence doing the same 8808c0984e5SSebastian Reichel * Revisit this: 8818c0984e5SSebastian Reichel */ 8828c0984e5SSebastian Reichel 8838c0984e5SSebastian Reichel /* get the USB type */ 8848c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 8858c0984e5SSebastian Reichel val = (val & AB8500_USB_LINK_STATUS) >> 8868c0984e5SSebastian Reichel USB_LINK_STATUS_SHIFT; 8878c0984e5SSebastian Reichel else 8888c0984e5SSebastian Reichel val = (val & AB8505_USB_LINK_STATUS) >> 8898c0984e5SSebastian Reichel USB_LINK_STATUS_SHIFT; 8908c0984e5SSebastian Reichel if (val) 8918c0984e5SSebastian Reichel break; 8928c0984e5SSebastian Reichel } 8938c0984e5SSebastian Reichel ret = ab8500_charger_max_usb_curr(di, 8948c0984e5SSebastian Reichel (enum ab8500_charger_link_status) val); 8958c0984e5SSebastian Reichel 8968c0984e5SSebastian Reichel return ret; 8978c0984e5SSebastian Reichel } 8988c0984e5SSebastian Reichel 8998c0984e5SSebastian Reichel /* 9008c0984e5SSebastian Reichel * This array maps the raw hex value to charger voltage used by the AB8500 9018c0984e5SSebastian Reichel * Values taken from the UM0836 9028c0984e5SSebastian Reichel */ 9038c0984e5SSebastian Reichel static int ab8500_charger_voltage_map[] = { 9048c0984e5SSebastian Reichel 3500 , 9058c0984e5SSebastian Reichel 3525 , 9068c0984e5SSebastian Reichel 3550 , 9078c0984e5SSebastian Reichel 3575 , 9088c0984e5SSebastian Reichel 3600 , 9098c0984e5SSebastian Reichel 3625 , 9108c0984e5SSebastian Reichel 3650 , 9118c0984e5SSebastian Reichel 3675 , 9128c0984e5SSebastian Reichel 3700 , 9138c0984e5SSebastian Reichel 3725 , 9148c0984e5SSebastian Reichel 3750 , 9158c0984e5SSebastian Reichel 3775 , 9168c0984e5SSebastian Reichel 3800 , 9178c0984e5SSebastian Reichel 3825 , 9188c0984e5SSebastian Reichel 3850 , 9198c0984e5SSebastian Reichel 3875 , 9208c0984e5SSebastian Reichel 3900 , 9218c0984e5SSebastian Reichel 3925 , 9228c0984e5SSebastian Reichel 3950 , 9238c0984e5SSebastian Reichel 3975 , 9248c0984e5SSebastian Reichel 4000 , 9258c0984e5SSebastian Reichel 4025 , 9268c0984e5SSebastian Reichel 4050 , 9278c0984e5SSebastian Reichel 4060 , 9288c0984e5SSebastian Reichel 4070 , 9298c0984e5SSebastian Reichel 4080 , 9308c0984e5SSebastian Reichel 4090 , 9318c0984e5SSebastian Reichel 4100 , 9328c0984e5SSebastian Reichel 4110 , 9338c0984e5SSebastian Reichel 4120 , 9348c0984e5SSebastian Reichel 4130 , 9358c0984e5SSebastian Reichel 4140 , 9368c0984e5SSebastian Reichel 4150 , 9378c0984e5SSebastian Reichel 4160 , 9388c0984e5SSebastian Reichel 4170 , 9398c0984e5SSebastian Reichel 4180 , 9408c0984e5SSebastian Reichel 4190 , 9418c0984e5SSebastian Reichel 4200 , 9428c0984e5SSebastian Reichel 4210 , 9438c0984e5SSebastian Reichel 4220 , 9448c0984e5SSebastian Reichel 4230 , 9458c0984e5SSebastian Reichel 4240 , 9468c0984e5SSebastian Reichel 4250 , 9478c0984e5SSebastian Reichel 4260 , 9488c0984e5SSebastian Reichel 4270 , 9498c0984e5SSebastian Reichel 4280 , 9508c0984e5SSebastian Reichel 4290 , 9518c0984e5SSebastian Reichel 4300 , 9528c0984e5SSebastian Reichel 4310 , 9538c0984e5SSebastian Reichel 4320 , 9548c0984e5SSebastian Reichel 4330 , 9558c0984e5SSebastian Reichel 4340 , 9568c0984e5SSebastian Reichel 4350 , 9578c0984e5SSebastian Reichel 4360 , 9588c0984e5SSebastian Reichel 4370 , 9598c0984e5SSebastian Reichel 4380 , 9608c0984e5SSebastian Reichel 4390 , 9618c0984e5SSebastian Reichel 4400 , 9628c0984e5SSebastian Reichel 4410 , 9638c0984e5SSebastian Reichel 4420 , 9648c0984e5SSebastian Reichel 4430 , 9658c0984e5SSebastian Reichel 4440 , 9668c0984e5SSebastian Reichel 4450 , 9678c0984e5SSebastian Reichel 4460 , 9688c0984e5SSebastian Reichel 4470 , 9698c0984e5SSebastian Reichel 4480 , 9708c0984e5SSebastian Reichel 4490 , 9718c0984e5SSebastian Reichel 4500 , 9728c0984e5SSebastian Reichel 4510 , 9738c0984e5SSebastian Reichel 4520 , 9748c0984e5SSebastian Reichel 4530 , 9758c0984e5SSebastian Reichel 4540 , 9768c0984e5SSebastian Reichel 4550 , 9778c0984e5SSebastian Reichel 4560 , 9788c0984e5SSebastian Reichel 4570 , 9798c0984e5SSebastian Reichel 4580 , 9808c0984e5SSebastian Reichel 4590 , 9818c0984e5SSebastian Reichel 4600 , 9828c0984e5SSebastian Reichel }; 9838c0984e5SSebastian Reichel 9848c0984e5SSebastian Reichel static int ab8500_voltage_to_regval(int voltage) 9858c0984e5SSebastian Reichel { 9868c0984e5SSebastian Reichel int i; 9878c0984e5SSebastian Reichel 9888c0984e5SSebastian Reichel /* Special case for voltage below 3.5V */ 9898c0984e5SSebastian Reichel if (voltage < ab8500_charger_voltage_map[0]) 9908c0984e5SSebastian Reichel return LOW_VOLT_REG; 9918c0984e5SSebastian Reichel 9928c0984e5SSebastian Reichel for (i = 1; i < ARRAY_SIZE(ab8500_charger_voltage_map); i++) { 9938c0984e5SSebastian Reichel if (voltage < ab8500_charger_voltage_map[i]) 9948c0984e5SSebastian Reichel return i - 1; 9958c0984e5SSebastian Reichel } 9968c0984e5SSebastian Reichel 9978c0984e5SSebastian Reichel /* If not last element, return error */ 9988c0984e5SSebastian Reichel i = ARRAY_SIZE(ab8500_charger_voltage_map) - 1; 9998c0984e5SSebastian Reichel if (voltage == ab8500_charger_voltage_map[i]) 10008c0984e5SSebastian Reichel return i; 10018c0984e5SSebastian Reichel else 10028c0984e5SSebastian Reichel return -1; 10038c0984e5SSebastian Reichel } 10048c0984e5SSebastian Reichel 10058c0984e5SSebastian Reichel static int ab8500_current_to_regval(struct ab8500_charger *di, int curr) 10068c0984e5SSebastian Reichel { 10078c0984e5SSebastian Reichel int i; 10088c0984e5SSebastian Reichel 10098c0984e5SSebastian Reichel if (curr < di->bm->chg_output_curr[0]) 10108c0984e5SSebastian Reichel return 0; 10118c0984e5SSebastian Reichel 10128c0984e5SSebastian Reichel for (i = 0; i < di->bm->n_chg_out_curr; i++) { 10138c0984e5SSebastian Reichel if (curr < di->bm->chg_output_curr[i]) 10148c0984e5SSebastian Reichel return i - 1; 10158c0984e5SSebastian Reichel } 10168c0984e5SSebastian Reichel 10178c0984e5SSebastian Reichel /* If not last element, return error */ 10188c0984e5SSebastian Reichel i = di->bm->n_chg_out_curr - 1; 10198c0984e5SSebastian Reichel if (curr == di->bm->chg_output_curr[i]) 10208c0984e5SSebastian Reichel return i; 10218c0984e5SSebastian Reichel else 10228c0984e5SSebastian Reichel return -1; 10238c0984e5SSebastian Reichel } 10248c0984e5SSebastian Reichel 10258c0984e5SSebastian Reichel static int ab8500_vbus_in_curr_to_regval(struct ab8500_charger *di, int curr) 10268c0984e5SSebastian Reichel { 10278c0984e5SSebastian Reichel int i; 10288c0984e5SSebastian Reichel 10298c0984e5SSebastian Reichel if (curr < di->bm->chg_input_curr[0]) 10308c0984e5SSebastian Reichel return 0; 10318c0984e5SSebastian Reichel 10328c0984e5SSebastian Reichel for (i = 0; i < di->bm->n_chg_in_curr; i++) { 10338c0984e5SSebastian Reichel if (curr < di->bm->chg_input_curr[i]) 10348c0984e5SSebastian Reichel return i - 1; 10358c0984e5SSebastian Reichel } 10368c0984e5SSebastian Reichel 10378c0984e5SSebastian Reichel /* If not last element, return error */ 10388c0984e5SSebastian Reichel i = di->bm->n_chg_in_curr - 1; 10398c0984e5SSebastian Reichel if (curr == di->bm->chg_input_curr[i]) 10408c0984e5SSebastian Reichel return i; 10418c0984e5SSebastian Reichel else 10428c0984e5SSebastian Reichel return -1; 10438c0984e5SSebastian Reichel } 10448c0984e5SSebastian Reichel 10458c0984e5SSebastian Reichel /** 10468c0984e5SSebastian Reichel * ab8500_charger_get_usb_cur() - get usb current 10478c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structre 10488c0984e5SSebastian Reichel * 10498c0984e5SSebastian Reichel * The usb stack provides the maximum current that can be drawn from 10508c0984e5SSebastian Reichel * the standard usb host. This will be in mA. 10518c0984e5SSebastian Reichel * This function converts current in mA to a value that can be written 10528c0984e5SSebastian Reichel * to the register. Returns -1 if charging is not allowed 10538c0984e5SSebastian Reichel */ 10548c0984e5SSebastian Reichel static int ab8500_charger_get_usb_cur(struct ab8500_charger *di) 10558c0984e5SSebastian Reichel { 10568c0984e5SSebastian Reichel int ret = 0; 10578c0984e5SSebastian Reichel switch (di->usb_state.usb_current) { 10588c0984e5SSebastian Reichel case 100: 10598c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P09; 10608c0984e5SSebastian Reichel break; 10618c0984e5SSebastian Reichel case 200: 10628c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P19; 10638c0984e5SSebastian Reichel break; 10648c0984e5SSebastian Reichel case 300: 10658c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P29; 10668c0984e5SSebastian Reichel break; 10678c0984e5SSebastian Reichel case 400: 10688c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P38; 10698c0984e5SSebastian Reichel break; 10708c0984e5SSebastian Reichel case 500: 10718c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; 10728c0984e5SSebastian Reichel break; 10738c0984e5SSebastian Reichel default: 10748c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05; 10758c0984e5SSebastian Reichel ret = -EPERM; 10768c0984e5SSebastian Reichel break; 10778c0984e5SSebastian Reichel }; 10788c0984e5SSebastian Reichel di->max_usb_in_curr.set_max = di->max_usb_in_curr.usb_type_max; 10798c0984e5SSebastian Reichel return ret; 10808c0984e5SSebastian Reichel } 10818c0984e5SSebastian Reichel 10828c0984e5SSebastian Reichel /** 10838c0984e5SSebastian Reichel * ab8500_charger_check_continue_stepping() - Check to allow stepping 10848c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 10858c0984e5SSebastian Reichel * @reg: select what charger register to check 10868c0984e5SSebastian Reichel * 10878c0984e5SSebastian Reichel * Check if current stepping should be allowed to continue. 10888c0984e5SSebastian Reichel * Checks if charger source has not collapsed. If it has, further stepping 10898c0984e5SSebastian Reichel * is not allowed. 10908c0984e5SSebastian Reichel */ 10918c0984e5SSebastian Reichel static bool ab8500_charger_check_continue_stepping(struct ab8500_charger *di, 10928c0984e5SSebastian Reichel int reg) 10938c0984e5SSebastian Reichel { 10948c0984e5SSebastian Reichel if (reg == AB8500_USBCH_IPT_CRNTLVL_REG) 10958c0984e5SSebastian Reichel return !di->flags.vbus_drop_end; 10968c0984e5SSebastian Reichel else 10978c0984e5SSebastian Reichel return true; 10988c0984e5SSebastian Reichel } 10998c0984e5SSebastian Reichel 11008c0984e5SSebastian Reichel /** 11018c0984e5SSebastian Reichel * ab8500_charger_set_current() - set charger current 11028c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 11038c0984e5SSebastian Reichel * @ich: charger current, in mA 11048c0984e5SSebastian Reichel * @reg: select what charger register to set 11058c0984e5SSebastian Reichel * 11068c0984e5SSebastian Reichel * Set charger current. 11078c0984e5SSebastian Reichel * There is no state machine in the AB to step up/down the charger 11088c0984e5SSebastian Reichel * current to avoid dips and spikes on MAIN, VBUS and VBAT when 11098c0984e5SSebastian Reichel * charging is started. Instead we need to implement 11108c0984e5SSebastian Reichel * this charger current step-up/down here. 11118c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 11128c0984e5SSebastian Reichel */ 11138c0984e5SSebastian Reichel static int ab8500_charger_set_current(struct ab8500_charger *di, 11148c0984e5SSebastian Reichel int ich, int reg) 11158c0984e5SSebastian Reichel { 11168c0984e5SSebastian Reichel int ret = 0; 11178c0984e5SSebastian Reichel int curr_index, prev_curr_index, shift_value, i; 11188c0984e5SSebastian Reichel u8 reg_value; 11198c0984e5SSebastian Reichel u32 step_udelay; 11208c0984e5SSebastian Reichel bool no_stepping = false; 11218c0984e5SSebastian Reichel 11228c0984e5SSebastian Reichel atomic_inc(&di->current_stepping_sessions); 11238c0984e5SSebastian Reichel 11248c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 11258c0984e5SSebastian Reichel reg, ®_value); 11268c0984e5SSebastian Reichel if (ret < 0) { 11278c0984e5SSebastian Reichel dev_err(di->dev, "%s read failed\n", __func__); 11288c0984e5SSebastian Reichel goto exit_set_current; 11298c0984e5SSebastian Reichel } 11308c0984e5SSebastian Reichel 11318c0984e5SSebastian Reichel switch (reg) { 11328c0984e5SSebastian Reichel case AB8500_MCH_IPT_CURLVL_REG: 11338c0984e5SSebastian Reichel shift_value = MAIN_CH_INPUT_CURR_SHIFT; 11348c0984e5SSebastian Reichel prev_curr_index = (reg_value >> shift_value); 11358c0984e5SSebastian Reichel curr_index = ab8500_current_to_regval(di, ich); 11368c0984e5SSebastian Reichel step_udelay = STEP_UDELAY; 11378c0984e5SSebastian Reichel if (!di->ac.charger_connected) 11388c0984e5SSebastian Reichel no_stepping = true; 11398c0984e5SSebastian Reichel break; 11408c0984e5SSebastian Reichel case AB8500_USBCH_IPT_CRNTLVL_REG: 11418c0984e5SSebastian Reichel if (is_ab8540(di->parent)) 11428c0984e5SSebastian Reichel shift_value = AB8540_VBUS_IN_CURR_LIM_SHIFT; 11438c0984e5SSebastian Reichel else 11448c0984e5SSebastian Reichel shift_value = VBUS_IN_CURR_LIM_SHIFT; 11458c0984e5SSebastian Reichel prev_curr_index = (reg_value >> shift_value); 11468c0984e5SSebastian Reichel curr_index = ab8500_vbus_in_curr_to_regval(di, ich); 11478c0984e5SSebastian Reichel step_udelay = STEP_UDELAY * 100; 11488c0984e5SSebastian Reichel 11498c0984e5SSebastian Reichel if (!di->usb.charger_connected) 11508c0984e5SSebastian Reichel no_stepping = true; 11518c0984e5SSebastian Reichel break; 11528c0984e5SSebastian Reichel case AB8500_CH_OPT_CRNTLVL_REG: 11538c0984e5SSebastian Reichel shift_value = 0; 11548c0984e5SSebastian Reichel prev_curr_index = (reg_value >> shift_value); 11558c0984e5SSebastian Reichel curr_index = ab8500_current_to_regval(di, ich); 11568c0984e5SSebastian Reichel step_udelay = STEP_UDELAY; 11578c0984e5SSebastian Reichel if (curr_index && (curr_index - prev_curr_index) > 1) 11588c0984e5SSebastian Reichel step_udelay *= 100; 11598c0984e5SSebastian Reichel 11608c0984e5SSebastian Reichel if (!di->usb.charger_connected && !di->ac.charger_connected) 11618c0984e5SSebastian Reichel no_stepping = true; 11628c0984e5SSebastian Reichel 11638c0984e5SSebastian Reichel break; 11648c0984e5SSebastian Reichel default: 11658c0984e5SSebastian Reichel dev_err(di->dev, "%s current register not valid\n", __func__); 11668c0984e5SSebastian Reichel ret = -ENXIO; 11678c0984e5SSebastian Reichel goto exit_set_current; 11688c0984e5SSebastian Reichel } 11698c0984e5SSebastian Reichel 11708c0984e5SSebastian Reichel if (curr_index < 0) { 11718c0984e5SSebastian Reichel dev_err(di->dev, "requested current limit out-of-range\n"); 11728c0984e5SSebastian Reichel ret = -ENXIO; 11738c0984e5SSebastian Reichel goto exit_set_current; 11748c0984e5SSebastian Reichel } 11758c0984e5SSebastian Reichel 11768c0984e5SSebastian Reichel /* only update current if it's been changed */ 11778c0984e5SSebastian Reichel if (prev_curr_index == curr_index) { 11788c0984e5SSebastian Reichel dev_dbg(di->dev, "%s current not changed for reg: 0x%02x\n", 11798c0984e5SSebastian Reichel __func__, reg); 11808c0984e5SSebastian Reichel ret = 0; 11818c0984e5SSebastian Reichel goto exit_set_current; 11828c0984e5SSebastian Reichel } 11838c0984e5SSebastian Reichel 11848c0984e5SSebastian Reichel dev_dbg(di->dev, "%s set charger current: %d mA for reg: 0x%02x\n", 11858c0984e5SSebastian Reichel __func__, ich, reg); 11868c0984e5SSebastian Reichel 11878c0984e5SSebastian Reichel if (no_stepping) { 11888c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 11898c0984e5SSebastian Reichel reg, (u8)curr_index << shift_value); 11908c0984e5SSebastian Reichel if (ret) 11918c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 11928c0984e5SSebastian Reichel } else if (prev_curr_index > curr_index) { 11938c0984e5SSebastian Reichel for (i = prev_curr_index - 1; i >= curr_index; i--) { 11948c0984e5SSebastian Reichel dev_dbg(di->dev, "curr change_1 to: %x for 0x%02x\n", 11958c0984e5SSebastian Reichel (u8) i << shift_value, reg); 11968c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 11978c0984e5SSebastian Reichel AB8500_CHARGER, reg, (u8)i << shift_value); 11988c0984e5SSebastian Reichel if (ret) { 11998c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 12008c0984e5SSebastian Reichel goto exit_set_current; 12018c0984e5SSebastian Reichel } 12028c0984e5SSebastian Reichel if (i != curr_index) 12038c0984e5SSebastian Reichel usleep_range(step_udelay, step_udelay * 2); 12048c0984e5SSebastian Reichel } 12058c0984e5SSebastian Reichel } else { 12068c0984e5SSebastian Reichel bool allow = true; 12078c0984e5SSebastian Reichel for (i = prev_curr_index + 1; i <= curr_index && allow; i++) { 12088c0984e5SSebastian Reichel dev_dbg(di->dev, "curr change_2 to: %x for 0x%02x\n", 12098c0984e5SSebastian Reichel (u8)i << shift_value, reg); 12108c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 12118c0984e5SSebastian Reichel AB8500_CHARGER, reg, (u8)i << shift_value); 12128c0984e5SSebastian Reichel if (ret) { 12138c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 12148c0984e5SSebastian Reichel goto exit_set_current; 12158c0984e5SSebastian Reichel } 12168c0984e5SSebastian Reichel if (i != curr_index) 12178c0984e5SSebastian Reichel usleep_range(step_udelay, step_udelay * 2); 12188c0984e5SSebastian Reichel 12198c0984e5SSebastian Reichel allow = ab8500_charger_check_continue_stepping(di, reg); 12208c0984e5SSebastian Reichel } 12218c0984e5SSebastian Reichel } 12228c0984e5SSebastian Reichel 12238c0984e5SSebastian Reichel exit_set_current: 12248c0984e5SSebastian Reichel atomic_dec(&di->current_stepping_sessions); 12258c0984e5SSebastian Reichel 12268c0984e5SSebastian Reichel return ret; 12278c0984e5SSebastian Reichel } 12288c0984e5SSebastian Reichel 12298c0984e5SSebastian Reichel /** 12308c0984e5SSebastian Reichel * ab8500_charger_set_vbus_in_curr() - set VBUS input current limit 12318c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 12328c0984e5SSebastian Reichel * @ich_in: charger input current limit 12338c0984e5SSebastian Reichel * 12348c0984e5SSebastian Reichel * Sets the current that can be drawn from the USB host 12358c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 12368c0984e5SSebastian Reichel */ 12378c0984e5SSebastian Reichel static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, 12388c0984e5SSebastian Reichel int ich_in) 12398c0984e5SSebastian Reichel { 12408c0984e5SSebastian Reichel int min_value; 12418c0984e5SSebastian Reichel int ret; 12428c0984e5SSebastian Reichel 12438c0984e5SSebastian Reichel /* We should always use to lowest current limit */ 12448c0984e5SSebastian Reichel min_value = min(di->bm->chg_params->usb_curr_max, ich_in); 12458c0984e5SSebastian Reichel if (di->max_usb_in_curr.set_max > 0) 12468c0984e5SSebastian Reichel min_value = min(di->max_usb_in_curr.set_max, min_value); 12478c0984e5SSebastian Reichel 12488c0984e5SSebastian Reichel if (di->usb_state.usb_current >= 0) 12498c0984e5SSebastian Reichel min_value = min(di->usb_state.usb_current, min_value); 12508c0984e5SSebastian Reichel 12518c0984e5SSebastian Reichel switch (min_value) { 12528c0984e5SSebastian Reichel case 100: 12538c0984e5SSebastian Reichel if (di->vbat < VBAT_TRESH_IP_CUR_RED) 12548c0984e5SSebastian Reichel min_value = USB_CH_IP_CUR_LVL_0P05; 12558c0984e5SSebastian Reichel break; 12568c0984e5SSebastian Reichel case 500: 12578c0984e5SSebastian Reichel if (di->vbat < VBAT_TRESH_IP_CUR_RED) 12588c0984e5SSebastian Reichel min_value = USB_CH_IP_CUR_LVL_0P45; 12598c0984e5SSebastian Reichel break; 12608c0984e5SSebastian Reichel default: 12618c0984e5SSebastian Reichel break; 12628c0984e5SSebastian Reichel } 12638c0984e5SSebastian Reichel 12648c0984e5SSebastian Reichel dev_info(di->dev, "VBUS input current limit set to %d mA\n", min_value); 12658c0984e5SSebastian Reichel 12668c0984e5SSebastian Reichel mutex_lock(&di->usb_ipt_crnt_lock); 12678c0984e5SSebastian Reichel ret = ab8500_charger_set_current(di, min_value, 12688c0984e5SSebastian Reichel AB8500_USBCH_IPT_CRNTLVL_REG); 12698c0984e5SSebastian Reichel mutex_unlock(&di->usb_ipt_crnt_lock); 12708c0984e5SSebastian Reichel 12718c0984e5SSebastian Reichel return ret; 12728c0984e5SSebastian Reichel } 12738c0984e5SSebastian Reichel 12748c0984e5SSebastian Reichel /** 12758c0984e5SSebastian Reichel * ab8500_charger_set_main_in_curr() - set main charger input current 12768c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 12778c0984e5SSebastian Reichel * @ich_in: input charger current, in mA 12788c0984e5SSebastian Reichel * 12798c0984e5SSebastian Reichel * Set main charger input current. 12808c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 12818c0984e5SSebastian Reichel */ 12828c0984e5SSebastian Reichel static int ab8500_charger_set_main_in_curr(struct ab8500_charger *di, 12838c0984e5SSebastian Reichel int ich_in) 12848c0984e5SSebastian Reichel { 12858c0984e5SSebastian Reichel return ab8500_charger_set_current(di, ich_in, 12868c0984e5SSebastian Reichel AB8500_MCH_IPT_CURLVL_REG); 12878c0984e5SSebastian Reichel } 12888c0984e5SSebastian Reichel 12898c0984e5SSebastian Reichel /** 12908c0984e5SSebastian Reichel * ab8500_charger_set_output_curr() - set charger output current 12918c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 12928c0984e5SSebastian Reichel * @ich_out: output charger current, in mA 12938c0984e5SSebastian Reichel * 12948c0984e5SSebastian Reichel * Set charger output current. 12958c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 12968c0984e5SSebastian Reichel */ 12978c0984e5SSebastian Reichel static int ab8500_charger_set_output_curr(struct ab8500_charger *di, 12988c0984e5SSebastian Reichel int ich_out) 12998c0984e5SSebastian Reichel { 13008c0984e5SSebastian Reichel return ab8500_charger_set_current(di, ich_out, 13018c0984e5SSebastian Reichel AB8500_CH_OPT_CRNTLVL_REG); 13028c0984e5SSebastian Reichel } 13038c0984e5SSebastian Reichel 13048c0984e5SSebastian Reichel /** 13058c0984e5SSebastian Reichel * ab8500_charger_led_en() - turn on/off chargign led 13068c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 13078c0984e5SSebastian Reichel * @on: flag to turn on/off the chargign led 13088c0984e5SSebastian Reichel * 13098c0984e5SSebastian Reichel * Power ON/OFF charging LED indication 13108c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 13118c0984e5SSebastian Reichel */ 13128c0984e5SSebastian Reichel static int ab8500_charger_led_en(struct ab8500_charger *di, int on) 13138c0984e5SSebastian Reichel { 13148c0984e5SSebastian Reichel int ret; 13158c0984e5SSebastian Reichel 13168c0984e5SSebastian Reichel if (on) { 13178c0984e5SSebastian Reichel /* Power ON charging LED indicator, set LED current to 5mA */ 13188c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 13198c0984e5SSebastian Reichel AB8500_LED_INDICATOR_PWM_CTRL, 13208c0984e5SSebastian Reichel (LED_IND_CUR_5MA | LED_INDICATOR_PWM_ENA)); 13218c0984e5SSebastian Reichel if (ret) { 13228c0984e5SSebastian Reichel dev_err(di->dev, "Power ON LED failed\n"); 13238c0984e5SSebastian Reichel return ret; 13248c0984e5SSebastian Reichel } 13258c0984e5SSebastian Reichel /* LED indicator PWM duty cycle 252/256 */ 13268c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 13278c0984e5SSebastian Reichel AB8500_LED_INDICATOR_PWM_DUTY, 13288c0984e5SSebastian Reichel LED_INDICATOR_PWM_DUTY_252_256); 13298c0984e5SSebastian Reichel if (ret) { 13308c0984e5SSebastian Reichel dev_err(di->dev, "Set LED PWM duty cycle failed\n"); 13318c0984e5SSebastian Reichel return ret; 13328c0984e5SSebastian Reichel } 13338c0984e5SSebastian Reichel } else { 13348c0984e5SSebastian Reichel /* Power off charging LED indicator */ 13358c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 13368c0984e5SSebastian Reichel AB8500_LED_INDICATOR_PWM_CTRL, 13378c0984e5SSebastian Reichel LED_INDICATOR_PWM_DIS); 13388c0984e5SSebastian Reichel if (ret) { 13398c0984e5SSebastian Reichel dev_err(di->dev, "Power-off LED failed\n"); 13408c0984e5SSebastian Reichel return ret; 13418c0984e5SSebastian Reichel } 13428c0984e5SSebastian Reichel } 13438c0984e5SSebastian Reichel 13448c0984e5SSebastian Reichel return ret; 13458c0984e5SSebastian Reichel } 13468c0984e5SSebastian Reichel 13478c0984e5SSebastian Reichel /** 13488c0984e5SSebastian Reichel * ab8500_charger_ac_en() - enable or disable ac charging 13498c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 13508c0984e5SSebastian Reichel * @enable: enable/disable flag 13518c0984e5SSebastian Reichel * @vset: charging voltage 13528c0984e5SSebastian Reichel * @iset: charging current 13538c0984e5SSebastian Reichel * 13548c0984e5SSebastian Reichel * Enable/Disable AC/Mains charging and turns on/off the charging led 13558c0984e5SSebastian Reichel * respectively. 13568c0984e5SSebastian Reichel **/ 13578c0984e5SSebastian Reichel static int ab8500_charger_ac_en(struct ux500_charger *charger, 13588c0984e5SSebastian Reichel int enable, int vset, int iset) 13598c0984e5SSebastian Reichel { 13608c0984e5SSebastian Reichel int ret; 13618c0984e5SSebastian Reichel int volt_index; 13628c0984e5SSebastian Reichel int curr_index; 13638c0984e5SSebastian Reichel int input_curr_index; 13648c0984e5SSebastian Reichel u8 overshoot = 0; 13658c0984e5SSebastian Reichel 13668c0984e5SSebastian Reichel struct ab8500_charger *di = to_ab8500_charger_ac_device_info(charger); 13678c0984e5SSebastian Reichel 13688c0984e5SSebastian Reichel if (enable) { 13698c0984e5SSebastian Reichel /* Check if AC is connected */ 13708c0984e5SSebastian Reichel if (!di->ac.charger_connected) { 13718c0984e5SSebastian Reichel dev_err(di->dev, "AC charger not connected\n"); 13728c0984e5SSebastian Reichel return -ENXIO; 13738c0984e5SSebastian Reichel } 13748c0984e5SSebastian Reichel 13758c0984e5SSebastian Reichel /* Enable AC charging */ 13768c0984e5SSebastian Reichel dev_dbg(di->dev, "Enable AC: %dmV %dmA\n", vset, iset); 13778c0984e5SSebastian Reichel 13788c0984e5SSebastian Reichel /* 13798c0984e5SSebastian Reichel * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts 13808c0984e5SSebastian Reichel * will be triggered everytime we enable the VDD ADC supply. 13818c0984e5SSebastian Reichel * This will turn off charging for a short while. 13828c0984e5SSebastian Reichel * It can be avoided by having the supply on when 13838c0984e5SSebastian Reichel * there is a charger enabled. Normally the VDD ADC supply 13848c0984e5SSebastian Reichel * is enabled everytime a GPADC conversion is triggered. We will 13858c0984e5SSebastian Reichel * force it to be enabled from this driver to have 13868c0984e5SSebastian Reichel * the GPADC module independant of the AB8500 chargers 13878c0984e5SSebastian Reichel */ 13888c0984e5SSebastian Reichel if (!di->vddadc_en_ac) { 13898c0984e5SSebastian Reichel ret = regulator_enable(di->regu); 13908c0984e5SSebastian Reichel if (ret) 13918c0984e5SSebastian Reichel dev_warn(di->dev, 13928c0984e5SSebastian Reichel "Failed to enable regulator\n"); 13938c0984e5SSebastian Reichel else 13948c0984e5SSebastian Reichel di->vddadc_en_ac = true; 13958c0984e5SSebastian Reichel } 13968c0984e5SSebastian Reichel 13978c0984e5SSebastian Reichel /* Check if the requested voltage or current is valid */ 13988c0984e5SSebastian Reichel volt_index = ab8500_voltage_to_regval(vset); 13998c0984e5SSebastian Reichel curr_index = ab8500_current_to_regval(di, iset); 14008c0984e5SSebastian Reichel input_curr_index = ab8500_current_to_regval(di, 14018c0984e5SSebastian Reichel di->bm->chg_params->ac_curr_max); 14028c0984e5SSebastian Reichel if (volt_index < 0 || curr_index < 0 || input_curr_index < 0) { 14038c0984e5SSebastian Reichel dev_err(di->dev, 14048c0984e5SSebastian Reichel "Charger voltage or current too high, " 14058c0984e5SSebastian Reichel "charging not started\n"); 14068c0984e5SSebastian Reichel return -ENXIO; 14078c0984e5SSebastian Reichel } 14088c0984e5SSebastian Reichel 14098c0984e5SSebastian Reichel /* ChVoltLevel: maximum battery charging voltage */ 14108c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 14118c0984e5SSebastian Reichel AB8500_CH_VOLT_LVL_REG, (u8) volt_index); 14128c0984e5SSebastian Reichel if (ret) { 14138c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 14148c0984e5SSebastian Reichel return ret; 14158c0984e5SSebastian Reichel } 14168c0984e5SSebastian Reichel /* MainChInputCurr: current that can be drawn from the charger*/ 14178c0984e5SSebastian Reichel ret = ab8500_charger_set_main_in_curr(di, 14188c0984e5SSebastian Reichel di->bm->chg_params->ac_curr_max); 14198c0984e5SSebastian Reichel if (ret) { 14208c0984e5SSebastian Reichel dev_err(di->dev, "%s Failed to set MainChInputCurr\n", 14218c0984e5SSebastian Reichel __func__); 14228c0984e5SSebastian Reichel return ret; 14238c0984e5SSebastian Reichel } 14248c0984e5SSebastian Reichel /* ChOutputCurentLevel: protected output current */ 14258c0984e5SSebastian Reichel ret = ab8500_charger_set_output_curr(di, iset); 14268c0984e5SSebastian Reichel if (ret) { 14278c0984e5SSebastian Reichel dev_err(di->dev, "%s " 14288c0984e5SSebastian Reichel "Failed to set ChOutputCurentLevel\n", 14298c0984e5SSebastian Reichel __func__); 14308c0984e5SSebastian Reichel return ret; 14318c0984e5SSebastian Reichel } 14328c0984e5SSebastian Reichel 14338c0984e5SSebastian Reichel /* Check if VBAT overshoot control should be enabled */ 14348c0984e5SSebastian Reichel if (!di->bm->enable_overshoot) 14358c0984e5SSebastian Reichel overshoot = MAIN_CH_NO_OVERSHOOT_ENA_N; 14368c0984e5SSebastian Reichel 14378c0984e5SSebastian Reichel /* Enable Main Charger */ 14388c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 14398c0984e5SSebastian Reichel AB8500_MCH_CTRL1, MAIN_CH_ENA | overshoot); 14408c0984e5SSebastian Reichel if (ret) { 14418c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 14428c0984e5SSebastian Reichel return ret; 14438c0984e5SSebastian Reichel } 14448c0984e5SSebastian Reichel 14458c0984e5SSebastian Reichel /* Power on charging LED indication */ 14468c0984e5SSebastian Reichel ret = ab8500_charger_led_en(di, true); 14478c0984e5SSebastian Reichel if (ret < 0) 14488c0984e5SSebastian Reichel dev_err(di->dev, "failed to enable LED\n"); 14498c0984e5SSebastian Reichel 14508c0984e5SSebastian Reichel di->ac.charger_online = 1; 14518c0984e5SSebastian Reichel } else { 14528c0984e5SSebastian Reichel /* Disable AC charging */ 14538c0984e5SSebastian Reichel if (is_ab8500_1p1_or_earlier(di->parent)) { 14548c0984e5SSebastian Reichel /* 14558c0984e5SSebastian Reichel * For ABB revision 1.0 and 1.1 there is a bug in the 14568c0984e5SSebastian Reichel * watchdog logic. That means we have to continously 14578c0984e5SSebastian Reichel * kick the charger watchdog even when no charger is 14588c0984e5SSebastian Reichel * connected. This is only valid once the AC charger 14598c0984e5SSebastian Reichel * has been enabled. This is a bug that is not handled 14608c0984e5SSebastian Reichel * by the algorithm and the watchdog have to be kicked 14618c0984e5SSebastian Reichel * by the charger driver when the AC charger 14628c0984e5SSebastian Reichel * is disabled 14638c0984e5SSebastian Reichel */ 14648c0984e5SSebastian Reichel if (di->ac_conn) { 14658c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 14668c0984e5SSebastian Reichel &di->kick_wd_work, 14678c0984e5SSebastian Reichel round_jiffies(WD_KICK_INTERVAL)); 14688c0984e5SSebastian Reichel } 14698c0984e5SSebastian Reichel 14708c0984e5SSebastian Reichel /* 14718c0984e5SSebastian Reichel * We can't turn off charging completely 14728c0984e5SSebastian Reichel * due to a bug in AB8500 cut1. 14738c0984e5SSebastian Reichel * If we do, charging will not start again. 14748c0984e5SSebastian Reichel * That is why we set the lowest voltage 14758c0984e5SSebastian Reichel * and current possible 14768c0984e5SSebastian Reichel */ 14778c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 14788c0984e5SSebastian Reichel AB8500_CHARGER, 14798c0984e5SSebastian Reichel AB8500_CH_VOLT_LVL_REG, CH_VOL_LVL_3P5); 14808c0984e5SSebastian Reichel if (ret) { 14818c0984e5SSebastian Reichel dev_err(di->dev, 14828c0984e5SSebastian Reichel "%s write failed\n", __func__); 14838c0984e5SSebastian Reichel return ret; 14848c0984e5SSebastian Reichel } 14858c0984e5SSebastian Reichel 14868c0984e5SSebastian Reichel ret = ab8500_charger_set_output_curr(di, 0); 14878c0984e5SSebastian Reichel if (ret) { 14888c0984e5SSebastian Reichel dev_err(di->dev, "%s " 14898c0984e5SSebastian Reichel "Failed to set ChOutputCurentLevel\n", 14908c0984e5SSebastian Reichel __func__); 14918c0984e5SSebastian Reichel return ret; 14928c0984e5SSebastian Reichel } 14938c0984e5SSebastian Reichel } else { 14948c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 14958c0984e5SSebastian Reichel AB8500_CHARGER, 14968c0984e5SSebastian Reichel AB8500_MCH_CTRL1, 0); 14978c0984e5SSebastian Reichel if (ret) { 14988c0984e5SSebastian Reichel dev_err(di->dev, 14998c0984e5SSebastian Reichel "%s write failed\n", __func__); 15008c0984e5SSebastian Reichel return ret; 15018c0984e5SSebastian Reichel } 15028c0984e5SSebastian Reichel } 15038c0984e5SSebastian Reichel 15048c0984e5SSebastian Reichel ret = ab8500_charger_led_en(di, false); 15058c0984e5SSebastian Reichel if (ret < 0) 15068c0984e5SSebastian Reichel dev_err(di->dev, "failed to disable LED\n"); 15078c0984e5SSebastian Reichel 15088c0984e5SSebastian Reichel di->ac.charger_online = 0; 15098c0984e5SSebastian Reichel di->ac.wd_expired = false; 15108c0984e5SSebastian Reichel 15118c0984e5SSebastian Reichel /* Disable regulator if enabled */ 15128c0984e5SSebastian Reichel if (di->vddadc_en_ac) { 15138c0984e5SSebastian Reichel regulator_disable(di->regu); 15148c0984e5SSebastian Reichel di->vddadc_en_ac = false; 15158c0984e5SSebastian Reichel } 15168c0984e5SSebastian Reichel 15178c0984e5SSebastian Reichel dev_dbg(di->dev, "%s Disabled AC charging\n", __func__); 15188c0984e5SSebastian Reichel } 15198c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 15208c0984e5SSebastian Reichel 15218c0984e5SSebastian Reichel return ret; 15228c0984e5SSebastian Reichel } 15238c0984e5SSebastian Reichel 15248c0984e5SSebastian Reichel /** 15258c0984e5SSebastian Reichel * ab8500_charger_usb_en() - enable usb charging 15268c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 15278c0984e5SSebastian Reichel * @enable: enable/disable flag 15288c0984e5SSebastian Reichel * @vset: charging voltage 15298c0984e5SSebastian Reichel * @ich_out: charger output current 15308c0984e5SSebastian Reichel * 15318c0984e5SSebastian Reichel * Enable/Disable USB charging and turns on/off the charging led respectively. 15328c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 15338c0984e5SSebastian Reichel */ 15348c0984e5SSebastian Reichel static int ab8500_charger_usb_en(struct ux500_charger *charger, 15358c0984e5SSebastian Reichel int enable, int vset, int ich_out) 15368c0984e5SSebastian Reichel { 15378c0984e5SSebastian Reichel int ret; 15388c0984e5SSebastian Reichel int volt_index; 15398c0984e5SSebastian Reichel int curr_index; 15408c0984e5SSebastian Reichel u8 overshoot = 0; 15418c0984e5SSebastian Reichel 15428c0984e5SSebastian Reichel struct ab8500_charger *di = to_ab8500_charger_usb_device_info(charger); 15438c0984e5SSebastian Reichel 15448c0984e5SSebastian Reichel if (enable) { 15458c0984e5SSebastian Reichel /* Check if USB is connected */ 15468c0984e5SSebastian Reichel if (!di->usb.charger_connected) { 15478c0984e5SSebastian Reichel dev_err(di->dev, "USB charger not connected\n"); 15488c0984e5SSebastian Reichel return -ENXIO; 15498c0984e5SSebastian Reichel } 15508c0984e5SSebastian Reichel 15518c0984e5SSebastian Reichel /* 15528c0984e5SSebastian Reichel * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts 15538c0984e5SSebastian Reichel * will be triggered everytime we enable the VDD ADC supply. 15548c0984e5SSebastian Reichel * This will turn off charging for a short while. 15558c0984e5SSebastian Reichel * It can be avoided by having the supply on when 15568c0984e5SSebastian Reichel * there is a charger enabled. Normally the VDD ADC supply 15578c0984e5SSebastian Reichel * is enabled everytime a GPADC conversion is triggered. We will 15588c0984e5SSebastian Reichel * force it to be enabled from this driver to have 15598c0984e5SSebastian Reichel * the GPADC module independant of the AB8500 chargers 15608c0984e5SSebastian Reichel */ 15618c0984e5SSebastian Reichel if (!di->vddadc_en_usb) { 15628c0984e5SSebastian Reichel ret = regulator_enable(di->regu); 15638c0984e5SSebastian Reichel if (ret) 15648c0984e5SSebastian Reichel dev_warn(di->dev, 15658c0984e5SSebastian Reichel "Failed to enable regulator\n"); 15668c0984e5SSebastian Reichel else 15678c0984e5SSebastian Reichel di->vddadc_en_usb = true; 15688c0984e5SSebastian Reichel } 15698c0984e5SSebastian Reichel 15708c0984e5SSebastian Reichel /* Enable USB charging */ 15718c0984e5SSebastian Reichel dev_dbg(di->dev, "Enable USB: %dmV %dmA\n", vset, ich_out); 15728c0984e5SSebastian Reichel 15738c0984e5SSebastian Reichel /* Check if the requested voltage or current is valid */ 15748c0984e5SSebastian Reichel volt_index = ab8500_voltage_to_regval(vset); 15758c0984e5SSebastian Reichel curr_index = ab8500_current_to_regval(di, ich_out); 15768c0984e5SSebastian Reichel if (volt_index < 0 || curr_index < 0) { 15778c0984e5SSebastian Reichel dev_err(di->dev, 15788c0984e5SSebastian Reichel "Charger voltage or current too high, " 15798c0984e5SSebastian Reichel "charging not started\n"); 15808c0984e5SSebastian Reichel return -ENXIO; 15818c0984e5SSebastian Reichel } 15828c0984e5SSebastian Reichel 15838c0984e5SSebastian Reichel /* ChVoltLevel: max voltage upto which battery can be charged */ 15848c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 15858c0984e5SSebastian Reichel AB8500_CH_VOLT_LVL_REG, (u8) volt_index); 15868c0984e5SSebastian Reichel if (ret) { 15878c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 15888c0984e5SSebastian Reichel return ret; 15898c0984e5SSebastian Reichel } 15908c0984e5SSebastian Reichel /* Check if VBAT overshoot control should be enabled */ 15918c0984e5SSebastian Reichel if (!di->bm->enable_overshoot) 15928c0984e5SSebastian Reichel overshoot = USB_CHG_NO_OVERSHOOT_ENA_N; 15938c0984e5SSebastian Reichel 15948c0984e5SSebastian Reichel /* Enable USB Charger */ 15958c0984e5SSebastian Reichel dev_dbg(di->dev, 15968c0984e5SSebastian Reichel "Enabling USB with write to AB8500_USBCH_CTRL1_REG\n"); 15978c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 15988c0984e5SSebastian Reichel AB8500_USBCH_CTRL1_REG, USB_CH_ENA | overshoot); 15998c0984e5SSebastian Reichel if (ret) { 16008c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 16018c0984e5SSebastian Reichel return ret; 16028c0984e5SSebastian Reichel } 16038c0984e5SSebastian Reichel 16048c0984e5SSebastian Reichel /* If success power on charging LED indication */ 16058c0984e5SSebastian Reichel ret = ab8500_charger_led_en(di, true); 16068c0984e5SSebastian Reichel if (ret < 0) 16078c0984e5SSebastian Reichel dev_err(di->dev, "failed to enable LED\n"); 16088c0984e5SSebastian Reichel 16098c0984e5SSebastian Reichel di->usb.charger_online = 1; 16108c0984e5SSebastian Reichel 16118c0984e5SSebastian Reichel /* USBChInputCurr: current that can be drawn from the usb */ 16128c0984e5SSebastian Reichel ret = ab8500_charger_set_vbus_in_curr(di, 16138c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max); 16148c0984e5SSebastian Reichel if (ret) { 16158c0984e5SSebastian Reichel dev_err(di->dev, "setting USBChInputCurr failed\n"); 16168c0984e5SSebastian Reichel return ret; 16178c0984e5SSebastian Reichel } 16188c0984e5SSebastian Reichel 16198c0984e5SSebastian Reichel /* ChOutputCurentLevel: protected output current */ 16208c0984e5SSebastian Reichel ret = ab8500_charger_set_output_curr(di, ich_out); 16218c0984e5SSebastian Reichel if (ret) { 16228c0984e5SSebastian Reichel dev_err(di->dev, "%s " 16238c0984e5SSebastian Reichel "Failed to set ChOutputCurentLevel\n", 16248c0984e5SSebastian Reichel __func__); 16258c0984e5SSebastian Reichel return ret; 16268c0984e5SSebastian Reichel } 16278c0984e5SSebastian Reichel 16288c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->check_vbat_work, HZ); 16298c0984e5SSebastian Reichel 16308c0984e5SSebastian Reichel } else { 16318c0984e5SSebastian Reichel /* Disable USB charging */ 16328c0984e5SSebastian Reichel dev_dbg(di->dev, "%s Disabled USB charging\n", __func__); 16338c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 16348c0984e5SSebastian Reichel AB8500_CHARGER, 16358c0984e5SSebastian Reichel AB8500_USBCH_CTRL1_REG, 0); 16368c0984e5SSebastian Reichel if (ret) { 16378c0984e5SSebastian Reichel dev_err(di->dev, 16388c0984e5SSebastian Reichel "%s write failed\n", __func__); 16398c0984e5SSebastian Reichel return ret; 16408c0984e5SSebastian Reichel } 16418c0984e5SSebastian Reichel 16428c0984e5SSebastian Reichel ret = ab8500_charger_led_en(di, false); 16438c0984e5SSebastian Reichel if (ret < 0) 16448c0984e5SSebastian Reichel dev_err(di->dev, "failed to disable LED\n"); 16458c0984e5SSebastian Reichel /* USBChInputCurr: current that can be drawn from the usb */ 16468c0984e5SSebastian Reichel ret = ab8500_charger_set_vbus_in_curr(di, 0); 16478c0984e5SSebastian Reichel if (ret) { 16488c0984e5SSebastian Reichel dev_err(di->dev, "setting USBChInputCurr failed\n"); 16498c0984e5SSebastian Reichel return ret; 16508c0984e5SSebastian Reichel } 16518c0984e5SSebastian Reichel 16528c0984e5SSebastian Reichel /* ChOutputCurentLevel: protected output current */ 16538c0984e5SSebastian Reichel ret = ab8500_charger_set_output_curr(di, 0); 16548c0984e5SSebastian Reichel if (ret) { 16558c0984e5SSebastian Reichel dev_err(di->dev, "%s " 16568c0984e5SSebastian Reichel "Failed to reset ChOutputCurentLevel\n", 16578c0984e5SSebastian Reichel __func__); 16588c0984e5SSebastian Reichel return ret; 16598c0984e5SSebastian Reichel } 16608c0984e5SSebastian Reichel di->usb.charger_online = 0; 16618c0984e5SSebastian Reichel di->usb.wd_expired = false; 16628c0984e5SSebastian Reichel 16638c0984e5SSebastian Reichel /* Disable regulator if enabled */ 16648c0984e5SSebastian Reichel if (di->vddadc_en_usb) { 16658c0984e5SSebastian Reichel regulator_disable(di->regu); 16668c0984e5SSebastian Reichel di->vddadc_en_usb = false; 16678c0984e5SSebastian Reichel } 16688c0984e5SSebastian Reichel 16698c0984e5SSebastian Reichel dev_dbg(di->dev, "%s Disabled USB charging\n", __func__); 16708c0984e5SSebastian Reichel 16718c0984e5SSebastian Reichel /* Cancel any pending Vbat check work */ 16728c0984e5SSebastian Reichel cancel_delayed_work(&di->check_vbat_work); 16738c0984e5SSebastian Reichel 16748c0984e5SSebastian Reichel } 16758c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 16768c0984e5SSebastian Reichel 16778c0984e5SSebastian Reichel return ret; 16788c0984e5SSebastian Reichel } 16798c0984e5SSebastian Reichel 16808c0984e5SSebastian Reichel static int ab8500_external_charger_prepare(struct notifier_block *charger_nb, 16818c0984e5SSebastian Reichel unsigned long event, void *data) 16828c0984e5SSebastian Reichel { 16838c0984e5SSebastian Reichel int ret; 16848c0984e5SSebastian Reichel struct device *dev = data; 16858c0984e5SSebastian Reichel /*Toggle External charger control pin*/ 16868c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK, 16878c0984e5SSebastian Reichel AB8500_SYS_CHARGER_CONTROL_REG, 16888c0984e5SSebastian Reichel EXTERNAL_CHARGER_DISABLE_REG_VAL); 16898c0984e5SSebastian Reichel if (ret < 0) { 16908c0984e5SSebastian Reichel dev_err(dev, "write reg failed %d\n", ret); 16918c0984e5SSebastian Reichel goto out; 16928c0984e5SSebastian Reichel } 16938c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK, 16948c0984e5SSebastian Reichel AB8500_SYS_CHARGER_CONTROL_REG, 16958c0984e5SSebastian Reichel EXTERNAL_CHARGER_ENABLE_REG_VAL); 16968c0984e5SSebastian Reichel if (ret < 0) 16978c0984e5SSebastian Reichel dev_err(dev, "Write reg failed %d\n", ret); 16988c0984e5SSebastian Reichel 16998c0984e5SSebastian Reichel out: 17008c0984e5SSebastian Reichel return ret; 17018c0984e5SSebastian Reichel } 17028c0984e5SSebastian Reichel 17038c0984e5SSebastian Reichel /** 17048c0984e5SSebastian Reichel * ab8500_charger_usb_check_enable() - enable usb charging 17058c0984e5SSebastian Reichel * @charger: pointer to the ux500_charger structure 17068c0984e5SSebastian Reichel * @vset: charging voltage 17078c0984e5SSebastian Reichel * @iset: charger output current 17088c0984e5SSebastian Reichel * 17098c0984e5SSebastian Reichel * Check if the VBUS charger has been disconnected and reconnected without 17108c0984e5SSebastian Reichel * AB8500 rising an interrupt. Returns 0 on success. 17118c0984e5SSebastian Reichel */ 17128c0984e5SSebastian Reichel static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, 17138c0984e5SSebastian Reichel int vset, int iset) 17148c0984e5SSebastian Reichel { 17158c0984e5SSebastian Reichel u8 usbch_ctrl1 = 0; 17168c0984e5SSebastian Reichel int ret = 0; 17178c0984e5SSebastian Reichel 17188c0984e5SSebastian Reichel struct ab8500_charger *di = to_ab8500_charger_usb_device_info(charger); 17198c0984e5SSebastian Reichel 17208c0984e5SSebastian Reichel if (!di->usb.charger_connected) 17218c0984e5SSebastian Reichel return ret; 17228c0984e5SSebastian Reichel 17238c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 17248c0984e5SSebastian Reichel AB8500_USBCH_CTRL1_REG, &usbch_ctrl1); 17258c0984e5SSebastian Reichel if (ret < 0) { 17268c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 read failed %d\n", __LINE__); 17278c0984e5SSebastian Reichel return ret; 17288c0984e5SSebastian Reichel } 17298c0984e5SSebastian Reichel dev_dbg(di->dev, "USB charger ctrl: 0x%02x\n", usbch_ctrl1); 17308c0984e5SSebastian Reichel 17318c0984e5SSebastian Reichel if (!(usbch_ctrl1 & USB_CH_ENA)) { 17328c0984e5SSebastian Reichel dev_info(di->dev, "Charging has been disabled abnormally and will be re-enabled\n"); 17338c0984e5SSebastian Reichel 17348c0984e5SSebastian Reichel ret = abx500_mask_and_set_register_interruptible(di->dev, 17358c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CHARGER_CTRL, 17368c0984e5SSebastian Reichel DROP_COUNT_RESET, DROP_COUNT_RESET); 17378c0984e5SSebastian Reichel if (ret < 0) { 17388c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 write failed %d\n", __LINE__); 17398c0984e5SSebastian Reichel return ret; 17408c0984e5SSebastian Reichel } 17418c0984e5SSebastian Reichel 17428c0984e5SSebastian Reichel ret = ab8500_charger_usb_en(&di->usb_chg, true, vset, iset); 17438c0984e5SSebastian Reichel if (ret < 0) { 17448c0984e5SSebastian Reichel dev_err(di->dev, "Failed to enable VBUS charger %d\n", 17458c0984e5SSebastian Reichel __LINE__); 17468c0984e5SSebastian Reichel return ret; 17478c0984e5SSebastian Reichel } 17488c0984e5SSebastian Reichel } 17498c0984e5SSebastian Reichel return ret; 17508c0984e5SSebastian Reichel } 17518c0984e5SSebastian Reichel 17528c0984e5SSebastian Reichel /** 17538c0984e5SSebastian Reichel * ab8500_charger_ac_check_enable() - enable usb charging 17548c0984e5SSebastian Reichel * @charger: pointer to the ux500_charger structure 17558c0984e5SSebastian Reichel * @vset: charging voltage 17568c0984e5SSebastian Reichel * @iset: charger output current 17578c0984e5SSebastian Reichel * 17588c0984e5SSebastian Reichel * Check if the AC charger has been disconnected and reconnected without 17598c0984e5SSebastian Reichel * AB8500 rising an interrupt. Returns 0 on success. 17608c0984e5SSebastian Reichel */ 17618c0984e5SSebastian Reichel static int ab8500_charger_ac_check_enable(struct ux500_charger *charger, 17628c0984e5SSebastian Reichel int vset, int iset) 17638c0984e5SSebastian Reichel { 17648c0984e5SSebastian Reichel u8 mainch_ctrl1 = 0; 17658c0984e5SSebastian Reichel int ret = 0; 17668c0984e5SSebastian Reichel 17678c0984e5SSebastian Reichel struct ab8500_charger *di = to_ab8500_charger_ac_device_info(charger); 17688c0984e5SSebastian Reichel 17698c0984e5SSebastian Reichel if (!di->ac.charger_connected) 17708c0984e5SSebastian Reichel return ret; 17718c0984e5SSebastian Reichel 17728c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 17738c0984e5SSebastian Reichel AB8500_MCH_CTRL1, &mainch_ctrl1); 17748c0984e5SSebastian Reichel if (ret < 0) { 17758c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 read failed %d\n", __LINE__); 17768c0984e5SSebastian Reichel return ret; 17778c0984e5SSebastian Reichel } 17788c0984e5SSebastian Reichel dev_dbg(di->dev, "AC charger ctrl: 0x%02x\n", mainch_ctrl1); 17798c0984e5SSebastian Reichel 17808c0984e5SSebastian Reichel if (!(mainch_ctrl1 & MAIN_CH_ENA)) { 17818c0984e5SSebastian Reichel dev_info(di->dev, "Charging has been disabled abnormally and will be re-enabled\n"); 17828c0984e5SSebastian Reichel 17838c0984e5SSebastian Reichel ret = abx500_mask_and_set_register_interruptible(di->dev, 17848c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CHARGER_CTRL, 17858c0984e5SSebastian Reichel DROP_COUNT_RESET, DROP_COUNT_RESET); 17868c0984e5SSebastian Reichel 17878c0984e5SSebastian Reichel if (ret < 0) { 17888c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 write failed %d\n", __LINE__); 17898c0984e5SSebastian Reichel return ret; 17908c0984e5SSebastian Reichel } 17918c0984e5SSebastian Reichel 17928c0984e5SSebastian Reichel ret = ab8500_charger_ac_en(&di->usb_chg, true, vset, iset); 17938c0984e5SSebastian Reichel if (ret < 0) { 17948c0984e5SSebastian Reichel dev_err(di->dev, "failed to enable AC charger %d\n", 17958c0984e5SSebastian Reichel __LINE__); 17968c0984e5SSebastian Reichel return ret; 17978c0984e5SSebastian Reichel } 17988c0984e5SSebastian Reichel } 17998c0984e5SSebastian Reichel return ret; 18008c0984e5SSebastian Reichel } 18018c0984e5SSebastian Reichel 18028c0984e5SSebastian Reichel /** 18038c0984e5SSebastian Reichel * ab8500_charger_watchdog_kick() - kick charger watchdog 18048c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 18058c0984e5SSebastian Reichel * 18068c0984e5SSebastian Reichel * Kick charger watchdog 18078c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 18088c0984e5SSebastian Reichel */ 18098c0984e5SSebastian Reichel static int ab8500_charger_watchdog_kick(struct ux500_charger *charger) 18108c0984e5SSebastian Reichel { 18118c0984e5SSebastian Reichel int ret; 18128c0984e5SSebastian Reichel struct ab8500_charger *di; 18138c0984e5SSebastian Reichel 18148c0984e5SSebastian Reichel if (charger->psy->desc->type == POWER_SUPPLY_TYPE_MAINS) 18158c0984e5SSebastian Reichel di = to_ab8500_charger_ac_device_info(charger); 18168c0984e5SSebastian Reichel else if (charger->psy->desc->type == POWER_SUPPLY_TYPE_USB) 18178c0984e5SSebastian Reichel di = to_ab8500_charger_usb_device_info(charger); 18188c0984e5SSebastian Reichel else 18198c0984e5SSebastian Reichel return -ENXIO; 18208c0984e5SSebastian Reichel 18218c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 18228c0984e5SSebastian Reichel AB8500_CHARG_WD_CTRL, CHARG_WD_KICK); 18238c0984e5SSebastian Reichel if (ret) 18248c0984e5SSebastian Reichel dev_err(di->dev, "Failed to kick WD!\n"); 18258c0984e5SSebastian Reichel 18268c0984e5SSebastian Reichel return ret; 18278c0984e5SSebastian Reichel } 18288c0984e5SSebastian Reichel 18298c0984e5SSebastian Reichel /** 18308c0984e5SSebastian Reichel * ab8500_charger_update_charger_current() - update charger current 18318c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 18328c0984e5SSebastian Reichel * 18338c0984e5SSebastian Reichel * Update the charger output current for the specified charger 18348c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 18358c0984e5SSebastian Reichel */ 18368c0984e5SSebastian Reichel static int ab8500_charger_update_charger_current(struct ux500_charger *charger, 18378c0984e5SSebastian Reichel int ich_out) 18388c0984e5SSebastian Reichel { 18398c0984e5SSebastian Reichel int ret; 18408c0984e5SSebastian Reichel struct ab8500_charger *di; 18418c0984e5SSebastian Reichel 18428c0984e5SSebastian Reichel if (charger->psy->desc->type == POWER_SUPPLY_TYPE_MAINS) 18438c0984e5SSebastian Reichel di = to_ab8500_charger_ac_device_info(charger); 18448c0984e5SSebastian Reichel else if (charger->psy->desc->type == POWER_SUPPLY_TYPE_USB) 18458c0984e5SSebastian Reichel di = to_ab8500_charger_usb_device_info(charger); 18468c0984e5SSebastian Reichel else 18478c0984e5SSebastian Reichel return -ENXIO; 18488c0984e5SSebastian Reichel 18498c0984e5SSebastian Reichel ret = ab8500_charger_set_output_curr(di, ich_out); 18508c0984e5SSebastian Reichel if (ret) { 18518c0984e5SSebastian Reichel dev_err(di->dev, "%s " 18528c0984e5SSebastian Reichel "Failed to set ChOutputCurentLevel\n", 18538c0984e5SSebastian Reichel __func__); 18548c0984e5SSebastian Reichel return ret; 18558c0984e5SSebastian Reichel } 18568c0984e5SSebastian Reichel 18578c0984e5SSebastian Reichel /* Reset the main and usb drop input current measurement counter */ 18588c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 18598c0984e5SSebastian Reichel AB8500_CHARGER_CTRL, DROP_COUNT_RESET); 18608c0984e5SSebastian Reichel if (ret) { 18618c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 18628c0984e5SSebastian Reichel return ret; 18638c0984e5SSebastian Reichel } 18648c0984e5SSebastian Reichel 18658c0984e5SSebastian Reichel return ret; 18668c0984e5SSebastian Reichel } 18678c0984e5SSebastian Reichel 18688c0984e5SSebastian Reichel /** 18698c0984e5SSebastian Reichel * ab8540_charger_power_path_enable() - enable usb power path mode 18708c0984e5SSebastian Reichel * @charger: pointer to the ux500_charger structure 18718c0984e5SSebastian Reichel * @enable: enable/disable flag 18728c0984e5SSebastian Reichel * 18738c0984e5SSebastian Reichel * Enable or disable the power path for usb mode 18748c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 18758c0984e5SSebastian Reichel */ 18768c0984e5SSebastian Reichel static int ab8540_charger_power_path_enable(struct ux500_charger *charger, 18778c0984e5SSebastian Reichel bool enable) 18788c0984e5SSebastian Reichel { 18798c0984e5SSebastian Reichel int ret; 18808c0984e5SSebastian Reichel struct ab8500_charger *di; 18818c0984e5SSebastian Reichel 18828c0984e5SSebastian Reichel if (charger->psy->desc->type == POWER_SUPPLY_TYPE_USB) 18838c0984e5SSebastian Reichel di = to_ab8500_charger_usb_device_info(charger); 18848c0984e5SSebastian Reichel else 18858c0984e5SSebastian Reichel return -ENXIO; 18868c0984e5SSebastian Reichel 18878c0984e5SSebastian Reichel ret = abx500_mask_and_set_register_interruptible(di->dev, 18888c0984e5SSebastian Reichel AB8500_CHARGER, AB8540_USB_PP_MODE_REG, 18898c0984e5SSebastian Reichel BUS_POWER_PATH_MODE_ENA, enable); 18908c0984e5SSebastian Reichel if (ret) { 18918c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 18928c0984e5SSebastian Reichel return ret; 18938c0984e5SSebastian Reichel } 18948c0984e5SSebastian Reichel 18958c0984e5SSebastian Reichel return ret; 18968c0984e5SSebastian Reichel } 18978c0984e5SSebastian Reichel 18988c0984e5SSebastian Reichel 18998c0984e5SSebastian Reichel /** 19008c0984e5SSebastian Reichel * ab8540_charger_usb_pre_chg_enable() - enable usb pre change 19018c0984e5SSebastian Reichel * @charger: pointer to the ux500_charger structure 19028c0984e5SSebastian Reichel * @enable: enable/disable flag 19038c0984e5SSebastian Reichel * 19048c0984e5SSebastian Reichel * Enable or disable the pre-chage for usb mode 19058c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 19068c0984e5SSebastian Reichel */ 19078c0984e5SSebastian Reichel static int ab8540_charger_usb_pre_chg_enable(struct ux500_charger *charger, 19088c0984e5SSebastian Reichel bool enable) 19098c0984e5SSebastian Reichel { 19108c0984e5SSebastian Reichel int ret; 19118c0984e5SSebastian Reichel struct ab8500_charger *di; 19128c0984e5SSebastian Reichel 19138c0984e5SSebastian Reichel if (charger->psy->desc->type == POWER_SUPPLY_TYPE_USB) 19148c0984e5SSebastian Reichel di = to_ab8500_charger_usb_device_info(charger); 19158c0984e5SSebastian Reichel else 19168c0984e5SSebastian Reichel return -ENXIO; 19178c0984e5SSebastian Reichel 19188c0984e5SSebastian Reichel ret = abx500_mask_and_set_register_interruptible(di->dev, 19198c0984e5SSebastian Reichel AB8500_CHARGER, AB8540_USB_PP_CHR_REG, 19208c0984e5SSebastian Reichel BUS_POWER_PATH_PRECHG_ENA, enable); 19218c0984e5SSebastian Reichel if (ret) { 19228c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 19238c0984e5SSebastian Reichel return ret; 19248c0984e5SSebastian Reichel } 19258c0984e5SSebastian Reichel 19268c0984e5SSebastian Reichel return ret; 19278c0984e5SSebastian Reichel } 19288c0984e5SSebastian Reichel 19298c0984e5SSebastian Reichel static int ab8500_charger_get_ext_psy_data(struct device *dev, void *data) 19308c0984e5SSebastian Reichel { 19318c0984e5SSebastian Reichel struct power_supply *psy; 19328c0984e5SSebastian Reichel struct power_supply *ext = dev_get_drvdata(dev); 19338c0984e5SSebastian Reichel const char **supplicants = (const char **)ext->supplied_to; 19348c0984e5SSebastian Reichel struct ab8500_charger *di; 19358c0984e5SSebastian Reichel union power_supply_propval ret; 19368c0984e5SSebastian Reichel int j; 19378c0984e5SSebastian Reichel struct ux500_charger *usb_chg; 19388c0984e5SSebastian Reichel 19398c0984e5SSebastian Reichel usb_chg = (struct ux500_charger *)data; 19408c0984e5SSebastian Reichel psy = usb_chg->psy; 19418c0984e5SSebastian Reichel 19428c0984e5SSebastian Reichel di = to_ab8500_charger_usb_device_info(usb_chg); 19438c0984e5SSebastian Reichel 19448c0984e5SSebastian Reichel /* For all psy where the driver name appears in any supplied_to */ 19458c0984e5SSebastian Reichel j = match_string(supplicants, ext->num_supplicants, psy->desc->name); 19468c0984e5SSebastian Reichel if (j < 0) 19478c0984e5SSebastian Reichel return 0; 19488c0984e5SSebastian Reichel 19498c0984e5SSebastian Reichel /* Go through all properties for the psy */ 19508c0984e5SSebastian Reichel for (j = 0; j < ext->desc->num_properties; j++) { 19518c0984e5SSebastian Reichel enum power_supply_property prop; 19528c0984e5SSebastian Reichel prop = ext->desc->properties[j]; 19538c0984e5SSebastian Reichel 19548c0984e5SSebastian Reichel if (power_supply_get_property(ext, prop, &ret)) 19558c0984e5SSebastian Reichel continue; 19568c0984e5SSebastian Reichel 19578c0984e5SSebastian Reichel switch (prop) { 19588c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_NOW: 19598c0984e5SSebastian Reichel switch (ext->desc->type) { 19608c0984e5SSebastian Reichel case POWER_SUPPLY_TYPE_BATTERY: 19618c0984e5SSebastian Reichel di->vbat = ret.intval / 1000; 19628c0984e5SSebastian Reichel break; 19638c0984e5SSebastian Reichel default: 19648c0984e5SSebastian Reichel break; 19658c0984e5SSebastian Reichel } 19668c0984e5SSebastian Reichel break; 19678c0984e5SSebastian Reichel default: 19688c0984e5SSebastian Reichel break; 19698c0984e5SSebastian Reichel } 19708c0984e5SSebastian Reichel } 19718c0984e5SSebastian Reichel return 0; 19728c0984e5SSebastian Reichel } 19738c0984e5SSebastian Reichel 19748c0984e5SSebastian Reichel /** 19758c0984e5SSebastian Reichel * ab8500_charger_check_vbat_work() - keep vbus current within spec 19768c0984e5SSebastian Reichel * @work pointer to the work_struct structure 19778c0984e5SSebastian Reichel * 19788c0984e5SSebastian Reichel * Due to a asic bug it is necessary to lower the input current to the vbus 19798c0984e5SSebastian Reichel * charger when charging with at some specific levels. This issue is only valid 19808c0984e5SSebastian Reichel * for below a certain battery voltage. This function makes sure that the 19818c0984e5SSebastian Reichel * the allowed current limit isn't exceeded. 19828c0984e5SSebastian Reichel */ 19838c0984e5SSebastian Reichel static void ab8500_charger_check_vbat_work(struct work_struct *work) 19848c0984e5SSebastian Reichel { 19858c0984e5SSebastian Reichel int t = 10; 19868c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 19878c0984e5SSebastian Reichel struct ab8500_charger, check_vbat_work.work); 19888c0984e5SSebastian Reichel 19898c0984e5SSebastian Reichel class_for_each_device(power_supply_class, NULL, 19908c0984e5SSebastian Reichel di->usb_chg.psy, ab8500_charger_get_ext_psy_data); 19918c0984e5SSebastian Reichel 19928c0984e5SSebastian Reichel /* First run old_vbat is 0. */ 19938c0984e5SSebastian Reichel if (di->old_vbat == 0) 19948c0984e5SSebastian Reichel di->old_vbat = di->vbat; 19958c0984e5SSebastian Reichel 19968c0984e5SSebastian Reichel if (!((di->old_vbat <= VBAT_TRESH_IP_CUR_RED && 19978c0984e5SSebastian Reichel di->vbat <= VBAT_TRESH_IP_CUR_RED) || 19988c0984e5SSebastian Reichel (di->old_vbat > VBAT_TRESH_IP_CUR_RED && 19998c0984e5SSebastian Reichel di->vbat > VBAT_TRESH_IP_CUR_RED))) { 20008c0984e5SSebastian Reichel 20018c0984e5SSebastian Reichel dev_dbg(di->dev, "Vbat did cross threshold, curr: %d, new: %d," 20028c0984e5SSebastian Reichel " old: %d\n", di->max_usb_in_curr.usb_type_max, 20038c0984e5SSebastian Reichel di->vbat, di->old_vbat); 20048c0984e5SSebastian Reichel ab8500_charger_set_vbus_in_curr(di, 20058c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max); 20068c0984e5SSebastian Reichel power_supply_changed(di->usb_chg.psy); 20078c0984e5SSebastian Reichel } 20088c0984e5SSebastian Reichel 20098c0984e5SSebastian Reichel di->old_vbat = di->vbat; 20108c0984e5SSebastian Reichel 20118c0984e5SSebastian Reichel /* 20128c0984e5SSebastian Reichel * No need to check the battery voltage every second when not close to 20138c0984e5SSebastian Reichel * the threshold. 20148c0984e5SSebastian Reichel */ 20158c0984e5SSebastian Reichel if (di->vbat < (VBAT_TRESH_IP_CUR_RED + 100) && 20168c0984e5SSebastian Reichel (di->vbat > (VBAT_TRESH_IP_CUR_RED - 100))) 20178c0984e5SSebastian Reichel t = 1; 20188c0984e5SSebastian Reichel 20198c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->check_vbat_work, t * HZ); 20208c0984e5SSebastian Reichel } 20218c0984e5SSebastian Reichel 20228c0984e5SSebastian Reichel /** 20238c0984e5SSebastian Reichel * ab8500_charger_check_hw_failure_work() - check main charger failure 20248c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 20258c0984e5SSebastian Reichel * 20268c0984e5SSebastian Reichel * Work queue function for checking the main charger status 20278c0984e5SSebastian Reichel */ 20288c0984e5SSebastian Reichel static void ab8500_charger_check_hw_failure_work(struct work_struct *work) 20298c0984e5SSebastian Reichel { 20308c0984e5SSebastian Reichel int ret; 20318c0984e5SSebastian Reichel u8 reg_value; 20328c0984e5SSebastian Reichel 20338c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 20348c0984e5SSebastian Reichel struct ab8500_charger, check_hw_failure_work.work); 20358c0984e5SSebastian Reichel 20368c0984e5SSebastian Reichel /* Check if the status bits for HW failure is still active */ 20378c0984e5SSebastian Reichel if (di->flags.mainextchnotok) { 20388c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 20398c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_STATUS2_REG, ®_value); 20408c0984e5SSebastian Reichel if (ret < 0) { 20418c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 20428c0984e5SSebastian Reichel return; 20438c0984e5SSebastian Reichel } 20448c0984e5SSebastian Reichel if (!(reg_value & MAIN_CH_NOK)) { 20458c0984e5SSebastian Reichel di->flags.mainextchnotok = false; 20468c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 20478c0984e5SSebastian Reichel } 20488c0984e5SSebastian Reichel } 20498c0984e5SSebastian Reichel if (di->flags.vbus_ovv) { 20508c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 20518c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG, 20528c0984e5SSebastian Reichel ®_value); 20538c0984e5SSebastian Reichel if (ret < 0) { 20548c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 20558c0984e5SSebastian Reichel return; 20568c0984e5SSebastian Reichel } 20578c0984e5SSebastian Reichel if (!(reg_value & VBUS_OVV_TH)) { 20588c0984e5SSebastian Reichel di->flags.vbus_ovv = false; 20598c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 20608c0984e5SSebastian Reichel } 20618c0984e5SSebastian Reichel } 20628c0984e5SSebastian Reichel /* If we still have a failure, schedule a new check */ 20638c0984e5SSebastian Reichel if (di->flags.mainextchnotok || di->flags.vbus_ovv) { 20648c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 20658c0984e5SSebastian Reichel &di->check_hw_failure_work, round_jiffies(HZ)); 20668c0984e5SSebastian Reichel } 20678c0984e5SSebastian Reichel } 20688c0984e5SSebastian Reichel 20698c0984e5SSebastian Reichel /** 20708c0984e5SSebastian Reichel * ab8500_charger_kick_watchdog_work() - kick the watchdog 20718c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 20728c0984e5SSebastian Reichel * 20738c0984e5SSebastian Reichel * Work queue function for kicking the charger watchdog. 20748c0984e5SSebastian Reichel * 20758c0984e5SSebastian Reichel * For ABB revision 1.0 and 1.1 there is a bug in the watchdog 20768c0984e5SSebastian Reichel * logic. That means we have to continously kick the charger 20778c0984e5SSebastian Reichel * watchdog even when no charger is connected. This is only 20788c0984e5SSebastian Reichel * valid once the AC charger has been enabled. This is 20798c0984e5SSebastian Reichel * a bug that is not handled by the algorithm and the 20808c0984e5SSebastian Reichel * watchdog have to be kicked by the charger driver 20818c0984e5SSebastian Reichel * when the AC charger is disabled 20828c0984e5SSebastian Reichel */ 20838c0984e5SSebastian Reichel static void ab8500_charger_kick_watchdog_work(struct work_struct *work) 20848c0984e5SSebastian Reichel { 20858c0984e5SSebastian Reichel int ret; 20868c0984e5SSebastian Reichel 20878c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 20888c0984e5SSebastian Reichel struct ab8500_charger, kick_wd_work.work); 20898c0984e5SSebastian Reichel 20908c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 20918c0984e5SSebastian Reichel AB8500_CHARG_WD_CTRL, CHARG_WD_KICK); 20928c0984e5SSebastian Reichel if (ret) 20938c0984e5SSebastian Reichel dev_err(di->dev, "Failed to kick WD!\n"); 20948c0984e5SSebastian Reichel 20958c0984e5SSebastian Reichel /* Schedule a new watchdog kick */ 20968c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 20978c0984e5SSebastian Reichel &di->kick_wd_work, round_jiffies(WD_KICK_INTERVAL)); 20988c0984e5SSebastian Reichel } 20998c0984e5SSebastian Reichel 21008c0984e5SSebastian Reichel /** 21018c0984e5SSebastian Reichel * ab8500_charger_ac_work() - work to get and set main charger status 21028c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 21038c0984e5SSebastian Reichel * 21048c0984e5SSebastian Reichel * Work queue function for checking the main charger status 21058c0984e5SSebastian Reichel */ 21068c0984e5SSebastian Reichel static void ab8500_charger_ac_work(struct work_struct *work) 21078c0984e5SSebastian Reichel { 21088c0984e5SSebastian Reichel int ret; 21098c0984e5SSebastian Reichel 21108c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 21118c0984e5SSebastian Reichel struct ab8500_charger, ac_work); 21128c0984e5SSebastian Reichel 21138c0984e5SSebastian Reichel /* 21148c0984e5SSebastian Reichel * Since we can't be sure that the events are received 21158c0984e5SSebastian Reichel * synchronously, we have the check if the main charger is 21168c0984e5SSebastian Reichel * connected by reading the status register 21178c0984e5SSebastian Reichel */ 21188c0984e5SSebastian Reichel ret = ab8500_charger_detect_chargers(di, false); 21198c0984e5SSebastian Reichel if (ret < 0) 21208c0984e5SSebastian Reichel return; 21218c0984e5SSebastian Reichel 21228c0984e5SSebastian Reichel if (ret & AC_PW_CONN) { 21238c0984e5SSebastian Reichel di->ac.charger_connected = 1; 21248c0984e5SSebastian Reichel di->ac_conn = true; 21258c0984e5SSebastian Reichel } else { 21268c0984e5SSebastian Reichel di->ac.charger_connected = 0; 21278c0984e5SSebastian Reichel } 21288c0984e5SSebastian Reichel 21298c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 21308c0984e5SSebastian Reichel sysfs_notify(&di->ac_chg.psy->dev.kobj, NULL, "present"); 21318c0984e5SSebastian Reichel } 21328c0984e5SSebastian Reichel 21338c0984e5SSebastian Reichel static void ab8500_charger_usb_attached_work(struct work_struct *work) 21348c0984e5SSebastian Reichel { 21358c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 21368c0984e5SSebastian Reichel struct ab8500_charger, 21378c0984e5SSebastian Reichel usb_charger_attached_work.work); 21388c0984e5SSebastian Reichel int usbch = (USB_CH_VBUSDROP | USB_CH_VBUSDETDBNC); 21398c0984e5SSebastian Reichel int ret, i; 21408c0984e5SSebastian Reichel u8 statval; 21418c0984e5SSebastian Reichel 21428c0984e5SSebastian Reichel for (i = 0; i < 10; i++) { 21438c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 21448c0984e5SSebastian Reichel AB8500_CHARGER, 21458c0984e5SSebastian Reichel AB8500_CH_USBCH_STAT1_REG, 21468c0984e5SSebastian Reichel &statval); 21478c0984e5SSebastian Reichel if (ret < 0) { 21488c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 read failed %d\n", __LINE__); 21498c0984e5SSebastian Reichel goto reschedule; 21508c0984e5SSebastian Reichel } 21518c0984e5SSebastian Reichel if ((statval & usbch) != usbch) 21528c0984e5SSebastian Reichel goto reschedule; 21538c0984e5SSebastian Reichel 21548c0984e5SSebastian Reichel msleep(CHARGER_STATUS_POLL); 21558c0984e5SSebastian Reichel } 21568c0984e5SSebastian Reichel 21578c0984e5SSebastian Reichel ab8500_charger_usb_en(&di->usb_chg, 0, 0, 0); 21588c0984e5SSebastian Reichel 21598c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 21608c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 21618c0984e5SSebastian Reichel 21628c0984e5SSebastian Reichel return; 21638c0984e5SSebastian Reichel 21648c0984e5SSebastian Reichel reschedule: 21658c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 21668c0984e5SSebastian Reichel &di->usb_charger_attached_work, 21678c0984e5SSebastian Reichel HZ); 21688c0984e5SSebastian Reichel } 21698c0984e5SSebastian Reichel 21708c0984e5SSebastian Reichel static void ab8500_charger_ac_attached_work(struct work_struct *work) 21718c0984e5SSebastian Reichel { 21728c0984e5SSebastian Reichel 21738c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 21748c0984e5SSebastian Reichel struct ab8500_charger, 21758c0984e5SSebastian Reichel ac_charger_attached_work.work); 21768c0984e5SSebastian Reichel int mainch = (MAIN_CH_STATUS2_MAINCHGDROP | 21778c0984e5SSebastian Reichel MAIN_CH_STATUS2_MAINCHARGERDETDBNC); 21788c0984e5SSebastian Reichel int ret, i; 21798c0984e5SSebastian Reichel u8 statval; 21808c0984e5SSebastian Reichel 21818c0984e5SSebastian Reichel for (i = 0; i < 10; i++) { 21828c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 21838c0984e5SSebastian Reichel AB8500_CHARGER, 21848c0984e5SSebastian Reichel AB8500_CH_STATUS2_REG, 21858c0984e5SSebastian Reichel &statval); 21868c0984e5SSebastian Reichel if (ret < 0) { 21878c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 read failed %d\n", __LINE__); 21888c0984e5SSebastian Reichel goto reschedule; 21898c0984e5SSebastian Reichel } 21908c0984e5SSebastian Reichel 21918c0984e5SSebastian Reichel if ((statval & mainch) != mainch) 21928c0984e5SSebastian Reichel goto reschedule; 21938c0984e5SSebastian Reichel 21948c0984e5SSebastian Reichel msleep(CHARGER_STATUS_POLL); 21958c0984e5SSebastian Reichel } 21968c0984e5SSebastian Reichel 21978c0984e5SSebastian Reichel ab8500_charger_ac_en(&di->ac_chg, 0, 0, 0); 21988c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->ac_work); 21998c0984e5SSebastian Reichel 22008c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 22018c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 22028c0984e5SSebastian Reichel 22038c0984e5SSebastian Reichel return; 22048c0984e5SSebastian Reichel 22058c0984e5SSebastian Reichel reschedule: 22068c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 22078c0984e5SSebastian Reichel &di->ac_charger_attached_work, 22088c0984e5SSebastian Reichel HZ); 22098c0984e5SSebastian Reichel } 22108c0984e5SSebastian Reichel 22118c0984e5SSebastian Reichel /** 22128c0984e5SSebastian Reichel * ab8500_charger_detect_usb_type_work() - work to detect USB type 22138c0984e5SSebastian Reichel * @work: Pointer to the work_struct structure 22148c0984e5SSebastian Reichel * 22158c0984e5SSebastian Reichel * Detect the type of USB plugged 22168c0984e5SSebastian Reichel */ 22178c0984e5SSebastian Reichel static void ab8500_charger_detect_usb_type_work(struct work_struct *work) 22188c0984e5SSebastian Reichel { 22198c0984e5SSebastian Reichel int ret; 22208c0984e5SSebastian Reichel 22218c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 22228c0984e5SSebastian Reichel struct ab8500_charger, detect_usb_type_work); 22238c0984e5SSebastian Reichel 22248c0984e5SSebastian Reichel /* 22258c0984e5SSebastian Reichel * Since we can't be sure that the events are received 22268c0984e5SSebastian Reichel * synchronously, we have the check if is 22278c0984e5SSebastian Reichel * connected by reading the status register 22288c0984e5SSebastian Reichel */ 22298c0984e5SSebastian Reichel ret = ab8500_charger_detect_chargers(di, false); 22308c0984e5SSebastian Reichel if (ret < 0) 22318c0984e5SSebastian Reichel return; 22328c0984e5SSebastian Reichel 22338c0984e5SSebastian Reichel if (!(ret & USB_PW_CONN)) { 22348c0984e5SSebastian Reichel dev_dbg(di->dev, "%s di->vbus_detected = false\n", __func__); 22358c0984e5SSebastian Reichel di->vbus_detected = false; 22368c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, false); 22378c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 22388c0984e5SSebastian Reichel } else { 22398c0984e5SSebastian Reichel dev_dbg(di->dev, "%s di->vbus_detected = true\n", __func__); 22408c0984e5SSebastian Reichel di->vbus_detected = true; 22418c0984e5SSebastian Reichel 22428c0984e5SSebastian Reichel if (is_ab8500_1p1_or_earlier(di->parent)) { 22438c0984e5SSebastian Reichel ret = ab8500_charger_detect_usb_type(di); 22448c0984e5SSebastian Reichel if (!ret) { 22458c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, true); 22468c0984e5SSebastian Reichel ab8500_power_supply_changed(di, 22478c0984e5SSebastian Reichel di->usb_chg.psy); 22488c0984e5SSebastian Reichel } 22498c0984e5SSebastian Reichel } else { 22508c0984e5SSebastian Reichel /* 22518c0984e5SSebastian Reichel * For ABB cut2.0 and onwards we have an IRQ, 22528c0984e5SSebastian Reichel * USB_LINK_STATUS that will be triggered when the USB 22538c0984e5SSebastian Reichel * link status changes. The exception is USB connected 22548c0984e5SSebastian Reichel * during startup. Then we don't get a 22558c0984e5SSebastian Reichel * USB_LINK_STATUS IRQ 22568c0984e5SSebastian Reichel */ 22578c0984e5SSebastian Reichel if (di->vbus_detected_start) { 22588c0984e5SSebastian Reichel di->vbus_detected_start = false; 22598c0984e5SSebastian Reichel ret = ab8500_charger_detect_usb_type(di); 22608c0984e5SSebastian Reichel if (!ret) { 22618c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, 22628c0984e5SSebastian Reichel true); 22638c0984e5SSebastian Reichel ab8500_power_supply_changed(di, 22648c0984e5SSebastian Reichel di->usb_chg.psy); 22658c0984e5SSebastian Reichel } 22668c0984e5SSebastian Reichel } 22678c0984e5SSebastian Reichel } 22688c0984e5SSebastian Reichel } 22698c0984e5SSebastian Reichel } 22708c0984e5SSebastian Reichel 22718c0984e5SSebastian Reichel /** 22728c0984e5SSebastian Reichel * ab8500_charger_usb_link_attach_work() - work to detect USB type 22738c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 22748c0984e5SSebastian Reichel * 22758c0984e5SSebastian Reichel * Detect the type of USB plugged 22768c0984e5SSebastian Reichel */ 22778c0984e5SSebastian Reichel static void ab8500_charger_usb_link_attach_work(struct work_struct *work) 22788c0984e5SSebastian Reichel { 22798c0984e5SSebastian Reichel struct ab8500_charger *di = 22808c0984e5SSebastian Reichel container_of(work, struct ab8500_charger, attach_work.work); 22818c0984e5SSebastian Reichel int ret; 22828c0984e5SSebastian Reichel 22838c0984e5SSebastian Reichel /* Update maximum input current if USB enumeration is not detected */ 22848c0984e5SSebastian Reichel if (!di->usb.charger_online) { 22858c0984e5SSebastian Reichel ret = ab8500_charger_set_vbus_in_curr(di, 22868c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max); 22878c0984e5SSebastian Reichel if (ret) 22888c0984e5SSebastian Reichel return; 22898c0984e5SSebastian Reichel } 22908c0984e5SSebastian Reichel 22918c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, true); 22928c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 22938c0984e5SSebastian Reichel } 22948c0984e5SSebastian Reichel 22958c0984e5SSebastian Reichel /** 22968c0984e5SSebastian Reichel * ab8500_charger_usb_link_status_work() - work to detect USB type 22978c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 22988c0984e5SSebastian Reichel * 22998c0984e5SSebastian Reichel * Detect the type of USB plugged 23008c0984e5SSebastian Reichel */ 23018c0984e5SSebastian Reichel static void ab8500_charger_usb_link_status_work(struct work_struct *work) 23028c0984e5SSebastian Reichel { 23038c0984e5SSebastian Reichel int detected_chargers; 23048c0984e5SSebastian Reichel int ret; 23058c0984e5SSebastian Reichel u8 val; 23068c0984e5SSebastian Reichel u8 link_status; 23078c0984e5SSebastian Reichel 23088c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 23098c0984e5SSebastian Reichel struct ab8500_charger, usb_link_status_work); 23108c0984e5SSebastian Reichel 23118c0984e5SSebastian Reichel /* 23128c0984e5SSebastian Reichel * Since we can't be sure that the events are received 23138c0984e5SSebastian Reichel * synchronously, we have the check if is 23148c0984e5SSebastian Reichel * connected by reading the status register 23158c0984e5SSebastian Reichel */ 23168c0984e5SSebastian Reichel detected_chargers = ab8500_charger_detect_chargers(di, false); 23178c0984e5SSebastian Reichel if (detected_chargers < 0) 23188c0984e5SSebastian Reichel return; 23198c0984e5SSebastian Reichel 23208c0984e5SSebastian Reichel /* 23218c0984e5SSebastian Reichel * Some chargers that breaks the USB spec is 23228c0984e5SSebastian Reichel * identified as invalid by AB8500 and it refuse 23238c0984e5SSebastian Reichel * to start the charging process. but by jumping 23248c0984e5SSebastian Reichel * thru a few hoops it can be forced to start. 23258c0984e5SSebastian Reichel */ 23268c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 23278c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_USB, 23288c0984e5SSebastian Reichel AB8500_USB_LINE_STAT_REG, &val); 23298c0984e5SSebastian Reichel else 23308c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_USB, 23318c0984e5SSebastian Reichel AB8500_USB_LINK1_STAT_REG, &val); 23328c0984e5SSebastian Reichel 23338c0984e5SSebastian Reichel if (ret >= 0) 23348c0984e5SSebastian Reichel dev_dbg(di->dev, "UsbLineStatus register = 0x%02x\n", val); 23358c0984e5SSebastian Reichel else 23368c0984e5SSebastian Reichel dev_dbg(di->dev, "Error reading USB link status\n"); 23378c0984e5SSebastian Reichel 23388c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 23398c0984e5SSebastian Reichel link_status = AB8500_USB_LINK_STATUS; 23408c0984e5SSebastian Reichel else 23418c0984e5SSebastian Reichel link_status = AB8505_USB_LINK_STATUS; 23428c0984e5SSebastian Reichel 23438c0984e5SSebastian Reichel if (detected_chargers & USB_PW_CONN) { 23448c0984e5SSebastian Reichel if (((val & link_status) >> USB_LINK_STATUS_SHIFT) == 23458c0984e5SSebastian Reichel USB_STAT_NOT_VALID_LINK && 23468c0984e5SSebastian Reichel di->invalid_charger_detect_state == 0) { 23478c0984e5SSebastian Reichel dev_dbg(di->dev, 23488c0984e5SSebastian Reichel "Invalid charger detected, state= 0\n"); 23498c0984e5SSebastian Reichel /*Enable charger*/ 23508c0984e5SSebastian Reichel abx500_mask_and_set_register_interruptible(di->dev, 23518c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_USBCH_CTRL1_REG, 23528c0984e5SSebastian Reichel USB_CH_ENA, USB_CH_ENA); 23538c0984e5SSebastian Reichel /*Enable charger detection*/ 23548c0984e5SSebastian Reichel abx500_mask_and_set_register_interruptible(di->dev, 23558c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINE_CTRL2_REG, 23568c0984e5SSebastian Reichel USB_CH_DET, USB_CH_DET); 23578c0984e5SSebastian Reichel di->invalid_charger_detect_state = 1; 23588c0984e5SSebastian Reichel /*exit and wait for new link status interrupt.*/ 23598c0984e5SSebastian Reichel return; 23608c0984e5SSebastian Reichel 23618c0984e5SSebastian Reichel } 23628c0984e5SSebastian Reichel if (di->invalid_charger_detect_state == 1) { 23638c0984e5SSebastian Reichel dev_dbg(di->dev, 23648c0984e5SSebastian Reichel "Invalid charger detected, state= 1\n"); 23658c0984e5SSebastian Reichel /*Stop charger detection*/ 23668c0984e5SSebastian Reichel abx500_mask_and_set_register_interruptible(di->dev, 23678c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINE_CTRL2_REG, 23688c0984e5SSebastian Reichel USB_CH_DET, 0x00); 23698c0984e5SSebastian Reichel /*Check link status*/ 23708c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 23718c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 23728c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINE_STAT_REG, 23738c0984e5SSebastian Reichel &val); 23748c0984e5SSebastian Reichel else 23758c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 23768c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINK1_STAT_REG, 23778c0984e5SSebastian Reichel &val); 23788c0984e5SSebastian Reichel 23798c0984e5SSebastian Reichel dev_dbg(di->dev, "USB link status= 0x%02x\n", 23808c0984e5SSebastian Reichel (val & link_status) >> USB_LINK_STATUS_SHIFT); 23818c0984e5SSebastian Reichel di->invalid_charger_detect_state = 2; 23828c0984e5SSebastian Reichel } 23838c0984e5SSebastian Reichel } else { 23848c0984e5SSebastian Reichel di->invalid_charger_detect_state = 0; 23858c0984e5SSebastian Reichel } 23868c0984e5SSebastian Reichel 23878c0984e5SSebastian Reichel if (!(detected_chargers & USB_PW_CONN)) { 23888c0984e5SSebastian Reichel di->vbus_detected = false; 23898c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, false); 23908c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 23918c0984e5SSebastian Reichel return; 23928c0984e5SSebastian Reichel } 23938c0984e5SSebastian Reichel 23948c0984e5SSebastian Reichel dev_dbg(di->dev,"%s di->vbus_detected = true\n",__func__); 23958c0984e5SSebastian Reichel di->vbus_detected = true; 23968c0984e5SSebastian Reichel ret = ab8500_charger_read_usb_type(di); 23978c0984e5SSebastian Reichel if (ret) { 23988c0984e5SSebastian Reichel if (ret == -ENXIO) { 23998c0984e5SSebastian Reichel /* No valid charger type detected */ 24008c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, false); 24018c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 24028c0984e5SSebastian Reichel } 24038c0984e5SSebastian Reichel return; 24048c0984e5SSebastian Reichel } 24058c0984e5SSebastian Reichel 24068c0984e5SSebastian Reichel if (di->usb_device_is_unrecognised) { 24078c0984e5SSebastian Reichel dev_dbg(di->dev, 24088c0984e5SSebastian Reichel "Potential Legacy Charger device. " 24098c0984e5SSebastian Reichel "Delay work for %d msec for USB enum " 24108c0984e5SSebastian Reichel "to finish", 24118c0984e5SSebastian Reichel WAIT_ACA_RID_ENUMERATION); 24128c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 24138c0984e5SSebastian Reichel &di->attach_work, 24148c0984e5SSebastian Reichel msecs_to_jiffies(WAIT_ACA_RID_ENUMERATION)); 24158c0984e5SSebastian Reichel } else if (di->is_aca_rid == 1) { 24168c0984e5SSebastian Reichel /* Only wait once */ 24178c0984e5SSebastian Reichel di->is_aca_rid++; 24188c0984e5SSebastian Reichel dev_dbg(di->dev, 24198c0984e5SSebastian Reichel "%s Wait %d msec for USB enum to finish", 24208c0984e5SSebastian Reichel __func__, WAIT_ACA_RID_ENUMERATION); 24218c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 24228c0984e5SSebastian Reichel &di->attach_work, 24238c0984e5SSebastian Reichel msecs_to_jiffies(WAIT_ACA_RID_ENUMERATION)); 24248c0984e5SSebastian Reichel } else { 24258c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 24268c0984e5SSebastian Reichel &di->attach_work, 24278c0984e5SSebastian Reichel 0); 24288c0984e5SSebastian Reichel } 24298c0984e5SSebastian Reichel } 24308c0984e5SSebastian Reichel 24318c0984e5SSebastian Reichel static void ab8500_charger_usb_state_changed_work(struct work_struct *work) 24328c0984e5SSebastian Reichel { 24338c0984e5SSebastian Reichel int ret; 24348c0984e5SSebastian Reichel unsigned long flags; 24358c0984e5SSebastian Reichel 24368c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 24378c0984e5SSebastian Reichel struct ab8500_charger, usb_state_changed_work.work); 24388c0984e5SSebastian Reichel 24398c0984e5SSebastian Reichel if (!di->vbus_detected) { 24408c0984e5SSebastian Reichel dev_dbg(di->dev, 24418c0984e5SSebastian Reichel "%s !di->vbus_detected\n", 24428c0984e5SSebastian Reichel __func__); 24438c0984e5SSebastian Reichel return; 24448c0984e5SSebastian Reichel } 24458c0984e5SSebastian Reichel 24468c0984e5SSebastian Reichel spin_lock_irqsave(&di->usb_state.usb_lock, flags); 24478c0984e5SSebastian Reichel di->usb_state.state = di->usb_state.state_tmp; 24488c0984e5SSebastian Reichel di->usb_state.usb_current = di->usb_state.usb_current_tmp; 24498c0984e5SSebastian Reichel spin_unlock_irqrestore(&di->usb_state.usb_lock, flags); 24508c0984e5SSebastian Reichel 24518c0984e5SSebastian Reichel dev_dbg(di->dev, "%s USB state: 0x%02x mA: %d\n", 24528c0984e5SSebastian Reichel __func__, di->usb_state.state, di->usb_state.usb_current); 24538c0984e5SSebastian Reichel 24548c0984e5SSebastian Reichel switch (di->usb_state.state) { 24558c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_RESET_HS: 24568c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_RESET_FS: 24578c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_SUSPEND: 24588c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_MAX: 24598c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, false); 24608c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 24618c0984e5SSebastian Reichel break; 24628c0984e5SSebastian Reichel 24638c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_RESUME: 24648c0984e5SSebastian Reichel /* 24658c0984e5SSebastian Reichel * when suspend->resume there should be delay 24668c0984e5SSebastian Reichel * of 1sec for enabling charging 24678c0984e5SSebastian Reichel */ 24688c0984e5SSebastian Reichel msleep(1000); 24698c0984e5SSebastian Reichel /* Intentional fall through */ 24708c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_CONFIGURED: 24718c0984e5SSebastian Reichel /* 24728c0984e5SSebastian Reichel * USB is configured, enable charging with the charging 24738c0984e5SSebastian Reichel * input current obtained from USB driver 24748c0984e5SSebastian Reichel */ 24758c0984e5SSebastian Reichel if (!ab8500_charger_get_usb_cur(di)) { 24768c0984e5SSebastian Reichel /* Update maximum input current */ 24778c0984e5SSebastian Reichel ret = ab8500_charger_set_vbus_in_curr(di, 24788c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max); 24798c0984e5SSebastian Reichel if (ret) 24808c0984e5SSebastian Reichel return; 24818c0984e5SSebastian Reichel 24828c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, true); 24838c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 24848c0984e5SSebastian Reichel } 24858c0984e5SSebastian Reichel break; 24868c0984e5SSebastian Reichel 24878c0984e5SSebastian Reichel default: 24888c0984e5SSebastian Reichel break; 24898c0984e5SSebastian Reichel }; 24908c0984e5SSebastian Reichel } 24918c0984e5SSebastian Reichel 24928c0984e5SSebastian Reichel /** 24938c0984e5SSebastian Reichel * ab8500_charger_check_usbchargernotok_work() - check USB chg not ok status 24948c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 24958c0984e5SSebastian Reichel * 24968c0984e5SSebastian Reichel * Work queue function for checking the USB charger Not OK status 24978c0984e5SSebastian Reichel */ 24988c0984e5SSebastian Reichel static void ab8500_charger_check_usbchargernotok_work(struct work_struct *work) 24998c0984e5SSebastian Reichel { 25008c0984e5SSebastian Reichel int ret; 25018c0984e5SSebastian Reichel u8 reg_value; 25028c0984e5SSebastian Reichel bool prev_status; 25038c0984e5SSebastian Reichel 25048c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 25058c0984e5SSebastian Reichel struct ab8500_charger, check_usbchgnotok_work.work); 25068c0984e5SSebastian Reichel 25078c0984e5SSebastian Reichel /* Check if the status bit for usbchargernotok is still active */ 25088c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 25098c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG, ®_value); 25108c0984e5SSebastian Reichel if (ret < 0) { 25118c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 25128c0984e5SSebastian Reichel return; 25138c0984e5SSebastian Reichel } 25148c0984e5SSebastian Reichel prev_status = di->flags.usbchargernotok; 25158c0984e5SSebastian Reichel 25168c0984e5SSebastian Reichel if (reg_value & VBUS_CH_NOK) { 25178c0984e5SSebastian Reichel di->flags.usbchargernotok = true; 25188c0984e5SSebastian Reichel /* Check again in 1sec */ 25198c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 25208c0984e5SSebastian Reichel &di->check_usbchgnotok_work, HZ); 25218c0984e5SSebastian Reichel } else { 25228c0984e5SSebastian Reichel di->flags.usbchargernotok = false; 25238c0984e5SSebastian Reichel di->flags.vbus_collapse = false; 25248c0984e5SSebastian Reichel } 25258c0984e5SSebastian Reichel 25268c0984e5SSebastian Reichel if (prev_status != di->flags.usbchargernotok) 25278c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 25288c0984e5SSebastian Reichel } 25298c0984e5SSebastian Reichel 25308c0984e5SSebastian Reichel /** 25318c0984e5SSebastian Reichel * ab8500_charger_check_main_thermal_prot_work() - check main thermal status 25328c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 25338c0984e5SSebastian Reichel * 25348c0984e5SSebastian Reichel * Work queue function for checking the Main thermal prot status 25358c0984e5SSebastian Reichel */ 25368c0984e5SSebastian Reichel static void ab8500_charger_check_main_thermal_prot_work( 25378c0984e5SSebastian Reichel struct work_struct *work) 25388c0984e5SSebastian Reichel { 25398c0984e5SSebastian Reichel int ret; 25408c0984e5SSebastian Reichel u8 reg_value; 25418c0984e5SSebastian Reichel 25428c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 25438c0984e5SSebastian Reichel struct ab8500_charger, check_main_thermal_prot_work); 25448c0984e5SSebastian Reichel 25458c0984e5SSebastian Reichel /* Check if the status bit for main_thermal_prot is still active */ 25468c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 25478c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_STATUS2_REG, ®_value); 25488c0984e5SSebastian Reichel if (ret < 0) { 25498c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 25508c0984e5SSebastian Reichel return; 25518c0984e5SSebastian Reichel } 25528c0984e5SSebastian Reichel if (reg_value & MAIN_CH_TH_PROT) 25538c0984e5SSebastian Reichel di->flags.main_thermal_prot = true; 25548c0984e5SSebastian Reichel else 25558c0984e5SSebastian Reichel di->flags.main_thermal_prot = false; 25568c0984e5SSebastian Reichel 25578c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 25588c0984e5SSebastian Reichel } 25598c0984e5SSebastian Reichel 25608c0984e5SSebastian Reichel /** 25618c0984e5SSebastian Reichel * ab8500_charger_check_usb_thermal_prot_work() - check usb thermal status 25628c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 25638c0984e5SSebastian Reichel * 25648c0984e5SSebastian Reichel * Work queue function for checking the USB thermal prot status 25658c0984e5SSebastian Reichel */ 25668c0984e5SSebastian Reichel static void ab8500_charger_check_usb_thermal_prot_work( 25678c0984e5SSebastian Reichel struct work_struct *work) 25688c0984e5SSebastian Reichel { 25698c0984e5SSebastian Reichel int ret; 25708c0984e5SSebastian Reichel u8 reg_value; 25718c0984e5SSebastian Reichel 25728c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 25738c0984e5SSebastian Reichel struct ab8500_charger, check_usb_thermal_prot_work); 25748c0984e5SSebastian Reichel 25758c0984e5SSebastian Reichel /* Check if the status bit for usb_thermal_prot is still active */ 25768c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 25778c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG, ®_value); 25788c0984e5SSebastian Reichel if (ret < 0) { 25798c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 25808c0984e5SSebastian Reichel return; 25818c0984e5SSebastian Reichel } 25828c0984e5SSebastian Reichel if (reg_value & USB_CH_TH_PROT) 25838c0984e5SSebastian Reichel di->flags.usb_thermal_prot = true; 25848c0984e5SSebastian Reichel else 25858c0984e5SSebastian Reichel di->flags.usb_thermal_prot = false; 25868c0984e5SSebastian Reichel 25878c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 25888c0984e5SSebastian Reichel } 25898c0984e5SSebastian Reichel 25908c0984e5SSebastian Reichel /** 25918c0984e5SSebastian Reichel * ab8500_charger_mainchunplugdet_handler() - main charger unplugged 25928c0984e5SSebastian Reichel * @irq: interrupt number 25938c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 25948c0984e5SSebastian Reichel * 25958c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 25968c0984e5SSebastian Reichel */ 25978c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_mainchunplugdet_handler(int irq, void *_di) 25988c0984e5SSebastian Reichel { 25998c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 26008c0984e5SSebastian Reichel 26018c0984e5SSebastian Reichel dev_dbg(di->dev, "Main charger unplugged\n"); 26028c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->ac_work); 26038c0984e5SSebastian Reichel 26048c0984e5SSebastian Reichel cancel_delayed_work_sync(&di->ac_charger_attached_work); 26058c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 26068c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 26078c0984e5SSebastian Reichel 26088c0984e5SSebastian Reichel return IRQ_HANDLED; 26098c0984e5SSebastian Reichel } 26108c0984e5SSebastian Reichel 26118c0984e5SSebastian Reichel /** 26128c0984e5SSebastian Reichel * ab8500_charger_mainchplugdet_handler() - main charger plugged 26138c0984e5SSebastian Reichel * @irq: interrupt number 26148c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 26158c0984e5SSebastian Reichel * 26168c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 26178c0984e5SSebastian Reichel */ 26188c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_mainchplugdet_handler(int irq, void *_di) 26198c0984e5SSebastian Reichel { 26208c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 26218c0984e5SSebastian Reichel 26228c0984e5SSebastian Reichel dev_dbg(di->dev, "Main charger plugged\n"); 26238c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->ac_work); 26248c0984e5SSebastian Reichel 26258c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 26268c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 26278c0984e5SSebastian Reichel 26288c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 26298c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 26308c0984e5SSebastian Reichel &di->ac_charger_attached_work, 26318c0984e5SSebastian Reichel HZ); 26328c0984e5SSebastian Reichel return IRQ_HANDLED; 26338c0984e5SSebastian Reichel } 26348c0984e5SSebastian Reichel 26358c0984e5SSebastian Reichel /** 26368c0984e5SSebastian Reichel * ab8500_charger_mainextchnotok_handler() - main charger not ok 26378c0984e5SSebastian Reichel * @irq: interrupt number 26388c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 26398c0984e5SSebastian Reichel * 26408c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 26418c0984e5SSebastian Reichel */ 26428c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_mainextchnotok_handler(int irq, void *_di) 26438c0984e5SSebastian Reichel { 26448c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 26458c0984e5SSebastian Reichel 26468c0984e5SSebastian Reichel dev_dbg(di->dev, "Main charger not ok\n"); 26478c0984e5SSebastian Reichel di->flags.mainextchnotok = true; 26488c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 26498c0984e5SSebastian Reichel 26508c0984e5SSebastian Reichel /* Schedule a new HW failure check */ 26518c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->check_hw_failure_work, 0); 26528c0984e5SSebastian Reichel 26538c0984e5SSebastian Reichel return IRQ_HANDLED; 26548c0984e5SSebastian Reichel } 26558c0984e5SSebastian Reichel 26568c0984e5SSebastian Reichel /** 26578c0984e5SSebastian Reichel * ab8500_charger_mainchthprotr_handler() - Die temp is above main charger 26588c0984e5SSebastian Reichel * thermal protection threshold 26598c0984e5SSebastian Reichel * @irq: interrupt number 26608c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 26618c0984e5SSebastian Reichel * 26628c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 26638c0984e5SSebastian Reichel */ 26648c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_mainchthprotr_handler(int irq, void *_di) 26658c0984e5SSebastian Reichel { 26668c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 26678c0984e5SSebastian Reichel 26688c0984e5SSebastian Reichel dev_dbg(di->dev, 26698c0984e5SSebastian Reichel "Die temp above Main charger thermal protection threshold\n"); 26708c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->check_main_thermal_prot_work); 26718c0984e5SSebastian Reichel 26728c0984e5SSebastian Reichel return IRQ_HANDLED; 26738c0984e5SSebastian Reichel } 26748c0984e5SSebastian Reichel 26758c0984e5SSebastian Reichel /** 26768c0984e5SSebastian Reichel * ab8500_charger_mainchthprotf_handler() - Die temp is below main charger 26778c0984e5SSebastian Reichel * thermal protection threshold 26788c0984e5SSebastian Reichel * @irq: interrupt number 26798c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 26808c0984e5SSebastian Reichel * 26818c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 26828c0984e5SSebastian Reichel */ 26838c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_mainchthprotf_handler(int irq, void *_di) 26848c0984e5SSebastian Reichel { 26858c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 26868c0984e5SSebastian Reichel 26878c0984e5SSebastian Reichel dev_dbg(di->dev, 26888c0984e5SSebastian Reichel "Die temp ok for Main charger thermal protection threshold\n"); 26898c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->check_main_thermal_prot_work); 26908c0984e5SSebastian Reichel 26918c0984e5SSebastian Reichel return IRQ_HANDLED; 26928c0984e5SSebastian Reichel } 26938c0984e5SSebastian Reichel 26948c0984e5SSebastian Reichel static void ab8500_charger_vbus_drop_end_work(struct work_struct *work) 26958c0984e5SSebastian Reichel { 26968c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 26978c0984e5SSebastian Reichel struct ab8500_charger, vbus_drop_end_work.work); 26988c0984e5SSebastian Reichel int ret, curr; 26998c0984e5SSebastian Reichel u8 reg_value; 27008c0984e5SSebastian Reichel 27018c0984e5SSebastian Reichel di->flags.vbus_drop_end = false; 27028c0984e5SSebastian Reichel 27038c0984e5SSebastian Reichel /* Reset the drop counter */ 27048c0984e5SSebastian Reichel abx500_set_register_interruptible(di->dev, 27058c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CHARGER_CTRL, 0x01); 27068c0984e5SSebastian Reichel 27078c0984e5SSebastian Reichel if (is_ab8540(di->parent)) 27088c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 27098c0984e5SSebastian Reichel AB8540_CH_USBCH_STAT3_REG, ®_value); 27108c0984e5SSebastian Reichel else 27118c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 27128c0984e5SSebastian Reichel AB8500_CH_USBCH_STAT2_REG, ®_value); 27138c0984e5SSebastian Reichel if (ret < 0) { 27148c0984e5SSebastian Reichel dev_err(di->dev, "%s read failed\n", __func__); 27158c0984e5SSebastian Reichel return; 27168c0984e5SSebastian Reichel } 27178c0984e5SSebastian Reichel 27188c0984e5SSebastian Reichel if (is_ab8540(di->parent)) 27198c0984e5SSebastian Reichel curr = di->bm->chg_input_curr[ 27208c0984e5SSebastian Reichel reg_value & AB8540_AUTO_VBUS_IN_CURR_MASK]; 27218c0984e5SSebastian Reichel else 27228c0984e5SSebastian Reichel curr = di->bm->chg_input_curr[ 27238c0984e5SSebastian Reichel reg_value >> AUTO_VBUS_IN_CURR_LIM_SHIFT]; 27248c0984e5SSebastian Reichel 27258c0984e5SSebastian Reichel if (di->max_usb_in_curr.calculated_max != curr) { 27268c0984e5SSebastian Reichel /* USB source is collapsing */ 27278c0984e5SSebastian Reichel di->max_usb_in_curr.calculated_max = curr; 27288c0984e5SSebastian Reichel dev_dbg(di->dev, 27298c0984e5SSebastian Reichel "VBUS input current limiting to %d mA\n", 27308c0984e5SSebastian Reichel di->max_usb_in_curr.calculated_max); 27318c0984e5SSebastian Reichel } else { 27328c0984e5SSebastian Reichel /* 27338c0984e5SSebastian Reichel * USB source can not give more than this amount. 27348c0984e5SSebastian Reichel * Taking more will collapse the source. 27358c0984e5SSebastian Reichel */ 27368c0984e5SSebastian Reichel di->max_usb_in_curr.set_max = 27378c0984e5SSebastian Reichel di->max_usb_in_curr.calculated_max; 27388c0984e5SSebastian Reichel dev_dbg(di->dev, 27398c0984e5SSebastian Reichel "VBUS input current limited to %d mA\n", 27408c0984e5SSebastian Reichel di->max_usb_in_curr.set_max); 27418c0984e5SSebastian Reichel } 27428c0984e5SSebastian Reichel 27438c0984e5SSebastian Reichel if (di->usb.charger_connected) 27448c0984e5SSebastian Reichel ab8500_charger_set_vbus_in_curr(di, 27458c0984e5SSebastian Reichel di->max_usb_in_curr.usb_type_max); 27468c0984e5SSebastian Reichel } 27478c0984e5SSebastian Reichel 27488c0984e5SSebastian Reichel /** 27498c0984e5SSebastian Reichel * ab8500_charger_vbusdetf_handler() - VBUS falling detected 27508c0984e5SSebastian Reichel * @irq: interrupt number 27518c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 27528c0984e5SSebastian Reichel * 27538c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 27548c0984e5SSebastian Reichel */ 27558c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_vbusdetf_handler(int irq, void *_di) 27568c0984e5SSebastian Reichel { 27578c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 27588c0984e5SSebastian Reichel 27598c0984e5SSebastian Reichel di->vbus_detected = false; 27608c0984e5SSebastian Reichel dev_dbg(di->dev, "VBUS falling detected\n"); 27618c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->detect_usb_type_work); 27628c0984e5SSebastian Reichel 27638c0984e5SSebastian Reichel return IRQ_HANDLED; 27648c0984e5SSebastian Reichel } 27658c0984e5SSebastian Reichel 27668c0984e5SSebastian Reichel /** 27678c0984e5SSebastian Reichel * ab8500_charger_vbusdetr_handler() - VBUS rising detected 27688c0984e5SSebastian Reichel * @irq: interrupt number 27698c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 27708c0984e5SSebastian Reichel * 27718c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 27728c0984e5SSebastian Reichel */ 27738c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_vbusdetr_handler(int irq, void *_di) 27748c0984e5SSebastian Reichel { 27758c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 27768c0984e5SSebastian Reichel 27778c0984e5SSebastian Reichel di->vbus_detected = true; 27788c0984e5SSebastian Reichel dev_dbg(di->dev, "VBUS rising detected\n"); 27798c0984e5SSebastian Reichel 27808c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->detect_usb_type_work); 27818c0984e5SSebastian Reichel 27828c0984e5SSebastian Reichel return IRQ_HANDLED; 27838c0984e5SSebastian Reichel } 27848c0984e5SSebastian Reichel 27858c0984e5SSebastian Reichel /** 27868c0984e5SSebastian Reichel * ab8500_charger_usblinkstatus_handler() - USB link status has changed 27878c0984e5SSebastian Reichel * @irq: interrupt number 27888c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 27898c0984e5SSebastian Reichel * 27908c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 27918c0984e5SSebastian Reichel */ 27928c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_usblinkstatus_handler(int irq, void *_di) 27938c0984e5SSebastian Reichel { 27948c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 27958c0984e5SSebastian Reichel 27968c0984e5SSebastian Reichel dev_dbg(di->dev, "USB link status changed\n"); 27978c0984e5SSebastian Reichel 27988c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->usb_link_status_work); 27998c0984e5SSebastian Reichel 28008c0984e5SSebastian Reichel return IRQ_HANDLED; 28018c0984e5SSebastian Reichel } 28028c0984e5SSebastian Reichel 28038c0984e5SSebastian Reichel /** 28048c0984e5SSebastian Reichel * ab8500_charger_usbchthprotr_handler() - Die temp is above usb charger 28058c0984e5SSebastian Reichel * thermal protection threshold 28068c0984e5SSebastian Reichel * @irq: interrupt number 28078c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 28088c0984e5SSebastian Reichel * 28098c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 28108c0984e5SSebastian Reichel */ 28118c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_usbchthprotr_handler(int irq, void *_di) 28128c0984e5SSebastian Reichel { 28138c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 28148c0984e5SSebastian Reichel 28158c0984e5SSebastian Reichel dev_dbg(di->dev, 28168c0984e5SSebastian Reichel "Die temp above USB charger thermal protection threshold\n"); 28178c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->check_usb_thermal_prot_work); 28188c0984e5SSebastian Reichel 28198c0984e5SSebastian Reichel return IRQ_HANDLED; 28208c0984e5SSebastian Reichel } 28218c0984e5SSebastian Reichel 28228c0984e5SSebastian Reichel /** 28238c0984e5SSebastian Reichel * ab8500_charger_usbchthprotf_handler() - Die temp is below usb charger 28248c0984e5SSebastian Reichel * thermal protection threshold 28258c0984e5SSebastian Reichel * @irq: interrupt number 28268c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 28278c0984e5SSebastian Reichel * 28288c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 28298c0984e5SSebastian Reichel */ 28308c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_usbchthprotf_handler(int irq, void *_di) 28318c0984e5SSebastian Reichel { 28328c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 28338c0984e5SSebastian Reichel 28348c0984e5SSebastian Reichel dev_dbg(di->dev, 28358c0984e5SSebastian Reichel "Die temp ok for USB charger thermal protection threshold\n"); 28368c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->check_usb_thermal_prot_work); 28378c0984e5SSebastian Reichel 28388c0984e5SSebastian Reichel return IRQ_HANDLED; 28398c0984e5SSebastian Reichel } 28408c0984e5SSebastian Reichel 28418c0984e5SSebastian Reichel /** 28428c0984e5SSebastian Reichel * ab8500_charger_usbchargernotokr_handler() - USB charger not ok detected 28438c0984e5SSebastian Reichel * @irq: interrupt number 28448c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 28458c0984e5SSebastian Reichel * 28468c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 28478c0984e5SSebastian Reichel */ 28488c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_usbchargernotokr_handler(int irq, void *_di) 28498c0984e5SSebastian Reichel { 28508c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 28518c0984e5SSebastian Reichel 28528c0984e5SSebastian Reichel dev_dbg(di->dev, "Not allowed USB charger detected\n"); 28538c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->check_usbchgnotok_work, 0); 28548c0984e5SSebastian Reichel 28558c0984e5SSebastian Reichel return IRQ_HANDLED; 28568c0984e5SSebastian Reichel } 28578c0984e5SSebastian Reichel 28588c0984e5SSebastian Reichel /** 28598c0984e5SSebastian Reichel * ab8500_charger_chwdexp_handler() - Charger watchdog expired 28608c0984e5SSebastian Reichel * @irq: interrupt number 28618c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 28628c0984e5SSebastian Reichel * 28638c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 28648c0984e5SSebastian Reichel */ 28658c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_chwdexp_handler(int irq, void *_di) 28668c0984e5SSebastian Reichel { 28678c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 28688c0984e5SSebastian Reichel 28698c0984e5SSebastian Reichel dev_dbg(di->dev, "Charger watchdog expired\n"); 28708c0984e5SSebastian Reichel 28718c0984e5SSebastian Reichel /* 28728c0984e5SSebastian Reichel * The charger that was online when the watchdog expired 28738c0984e5SSebastian Reichel * needs to be restarted for charging to start again 28748c0984e5SSebastian Reichel */ 28758c0984e5SSebastian Reichel if (di->ac.charger_online) { 28768c0984e5SSebastian Reichel di->ac.wd_expired = true; 28778c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 28788c0984e5SSebastian Reichel } 28798c0984e5SSebastian Reichel if (di->usb.charger_online) { 28808c0984e5SSebastian Reichel di->usb.wd_expired = true; 28818c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 28828c0984e5SSebastian Reichel } 28838c0984e5SSebastian Reichel 28848c0984e5SSebastian Reichel return IRQ_HANDLED; 28858c0984e5SSebastian Reichel } 28868c0984e5SSebastian Reichel 28878c0984e5SSebastian Reichel /** 28888c0984e5SSebastian Reichel * ab8500_charger_vbuschdropend_handler() - VBUS drop removed 28898c0984e5SSebastian Reichel * @irq: interrupt number 28908c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 28918c0984e5SSebastian Reichel * 28928c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 28938c0984e5SSebastian Reichel */ 28948c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_vbuschdropend_handler(int irq, void *_di) 28958c0984e5SSebastian Reichel { 28968c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 28978c0984e5SSebastian Reichel 28988c0984e5SSebastian Reichel dev_dbg(di->dev, "VBUS charger drop ended\n"); 28998c0984e5SSebastian Reichel di->flags.vbus_drop_end = true; 29008c0984e5SSebastian Reichel 29018c0984e5SSebastian Reichel /* 29028c0984e5SSebastian Reichel * VBUS might have dropped due to bad connection. 29038c0984e5SSebastian Reichel * Schedule a new input limit set to the value SW requests. 29048c0984e5SSebastian Reichel */ 29058c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->vbus_drop_end_work, 29068c0984e5SSebastian Reichel round_jiffies(VBUS_IN_CURR_LIM_RETRY_SET_TIME * HZ)); 29078c0984e5SSebastian Reichel 29088c0984e5SSebastian Reichel return IRQ_HANDLED; 29098c0984e5SSebastian Reichel } 29108c0984e5SSebastian Reichel 29118c0984e5SSebastian Reichel /** 29128c0984e5SSebastian Reichel * ab8500_charger_vbusovv_handler() - VBUS overvoltage detected 29138c0984e5SSebastian Reichel * @irq: interrupt number 29148c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 29158c0984e5SSebastian Reichel * 29168c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 29178c0984e5SSebastian Reichel */ 29188c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_vbusovv_handler(int irq, void *_di) 29198c0984e5SSebastian Reichel { 29208c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 29218c0984e5SSebastian Reichel 29228c0984e5SSebastian Reichel dev_dbg(di->dev, "VBUS overvoltage detected\n"); 29238c0984e5SSebastian Reichel di->flags.vbus_ovv = true; 29248c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 29258c0984e5SSebastian Reichel 29268c0984e5SSebastian Reichel /* Schedule a new HW failure check */ 29278c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->check_hw_failure_work, 0); 29288c0984e5SSebastian Reichel 29298c0984e5SSebastian Reichel return IRQ_HANDLED; 29308c0984e5SSebastian Reichel } 29318c0984e5SSebastian Reichel 29328c0984e5SSebastian Reichel /** 29338c0984e5SSebastian Reichel * ab8500_charger_ac_get_property() - get the ac/mains properties 29348c0984e5SSebastian Reichel * @psy: pointer to the power_supply structure 29358c0984e5SSebastian Reichel * @psp: pointer to the power_supply_property structure 29368c0984e5SSebastian Reichel * @val: pointer to the power_supply_propval union 29378c0984e5SSebastian Reichel * 29388c0984e5SSebastian Reichel * This function gets called when an application tries to get the ac/mains 29398c0984e5SSebastian Reichel * properties by reading the sysfs files. 29408c0984e5SSebastian Reichel * AC/Mains properties are online, present and voltage. 29418c0984e5SSebastian Reichel * online: ac/mains charging is in progress or not 29428c0984e5SSebastian Reichel * present: presence of the ac/mains 29438c0984e5SSebastian Reichel * voltage: AC/Mains voltage 29448c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 29458c0984e5SSebastian Reichel */ 29468c0984e5SSebastian Reichel static int ab8500_charger_ac_get_property(struct power_supply *psy, 29478c0984e5SSebastian Reichel enum power_supply_property psp, 29488c0984e5SSebastian Reichel union power_supply_propval *val) 29498c0984e5SSebastian Reichel { 29508c0984e5SSebastian Reichel struct ab8500_charger *di; 29518c0984e5SSebastian Reichel int ret; 29528c0984e5SSebastian Reichel 29538c0984e5SSebastian Reichel di = to_ab8500_charger_ac_device_info(psy_to_ux500_charger(psy)); 29548c0984e5SSebastian Reichel 29558c0984e5SSebastian Reichel switch (psp) { 29568c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_HEALTH: 29578c0984e5SSebastian Reichel if (di->flags.mainextchnotok) 29588c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 29598c0984e5SSebastian Reichel else if (di->ac.wd_expired || di->usb.wd_expired) 29608c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_DEAD; 29618c0984e5SSebastian Reichel else if (di->flags.main_thermal_prot) 29628c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 29638c0984e5SSebastian Reichel else 29648c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_GOOD; 29658c0984e5SSebastian Reichel break; 29668c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_ONLINE: 29678c0984e5SSebastian Reichel val->intval = di->ac.charger_online; 29688c0984e5SSebastian Reichel break; 29698c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_PRESENT: 29708c0984e5SSebastian Reichel val->intval = di->ac.charger_connected; 29718c0984e5SSebastian Reichel break; 29728c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_NOW: 29738c0984e5SSebastian Reichel ret = ab8500_charger_get_ac_voltage(di); 29748c0984e5SSebastian Reichel if (ret >= 0) 29758c0984e5SSebastian Reichel di->ac.charger_voltage = ret; 29768c0984e5SSebastian Reichel /* On error, use previous value */ 29778c0984e5SSebastian Reichel val->intval = di->ac.charger_voltage * 1000; 29788c0984e5SSebastian Reichel break; 29798c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_AVG: 29808c0984e5SSebastian Reichel /* 29818c0984e5SSebastian Reichel * This property is used to indicate when CV mode is entered 29828c0984e5SSebastian Reichel * for the AC charger 29838c0984e5SSebastian Reichel */ 29848c0984e5SSebastian Reichel di->ac.cv_active = ab8500_charger_ac_cv(di); 29858c0984e5SSebastian Reichel val->intval = di->ac.cv_active; 29868c0984e5SSebastian Reichel break; 29878c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CURRENT_NOW: 29888c0984e5SSebastian Reichel ret = ab8500_charger_get_ac_current(di); 29898c0984e5SSebastian Reichel if (ret >= 0) 29908c0984e5SSebastian Reichel di->ac.charger_current = ret; 29918c0984e5SSebastian Reichel val->intval = di->ac.charger_current * 1000; 29928c0984e5SSebastian Reichel break; 29938c0984e5SSebastian Reichel default: 29948c0984e5SSebastian Reichel return -EINVAL; 29958c0984e5SSebastian Reichel } 29968c0984e5SSebastian Reichel return 0; 29978c0984e5SSebastian Reichel } 29988c0984e5SSebastian Reichel 29998c0984e5SSebastian Reichel /** 30008c0984e5SSebastian Reichel * ab8500_charger_usb_get_property() - get the usb properties 30018c0984e5SSebastian Reichel * @psy: pointer to the power_supply structure 30028c0984e5SSebastian Reichel * @psp: pointer to the power_supply_property structure 30038c0984e5SSebastian Reichel * @val: pointer to the power_supply_propval union 30048c0984e5SSebastian Reichel * 30058c0984e5SSebastian Reichel * This function gets called when an application tries to get the usb 30068c0984e5SSebastian Reichel * properties by reading the sysfs files. 30078c0984e5SSebastian Reichel * USB properties are online, present and voltage. 30088c0984e5SSebastian Reichel * online: usb charging is in progress or not 30098c0984e5SSebastian Reichel * present: presence of the usb 30108c0984e5SSebastian Reichel * voltage: vbus voltage 30118c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 30128c0984e5SSebastian Reichel */ 30138c0984e5SSebastian Reichel static int ab8500_charger_usb_get_property(struct power_supply *psy, 30148c0984e5SSebastian Reichel enum power_supply_property psp, 30158c0984e5SSebastian Reichel union power_supply_propval *val) 30168c0984e5SSebastian Reichel { 30178c0984e5SSebastian Reichel struct ab8500_charger *di; 30188c0984e5SSebastian Reichel int ret; 30198c0984e5SSebastian Reichel 30208c0984e5SSebastian Reichel di = to_ab8500_charger_usb_device_info(psy_to_ux500_charger(psy)); 30218c0984e5SSebastian Reichel 30228c0984e5SSebastian Reichel switch (psp) { 30238c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_HEALTH: 30248c0984e5SSebastian Reichel if (di->flags.usbchargernotok) 30258c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 30268c0984e5SSebastian Reichel else if (di->ac.wd_expired || di->usb.wd_expired) 30278c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_DEAD; 30288c0984e5SSebastian Reichel else if (di->flags.usb_thermal_prot) 30298c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 30308c0984e5SSebastian Reichel else if (di->flags.vbus_ovv) 30318c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 30328c0984e5SSebastian Reichel else 30338c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_GOOD; 30348c0984e5SSebastian Reichel break; 30358c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_ONLINE: 30368c0984e5SSebastian Reichel val->intval = di->usb.charger_online; 30378c0984e5SSebastian Reichel break; 30388c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_PRESENT: 30398c0984e5SSebastian Reichel val->intval = di->usb.charger_connected; 30408c0984e5SSebastian Reichel break; 30418c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_NOW: 30428c0984e5SSebastian Reichel ret = ab8500_charger_get_vbus_voltage(di); 30438c0984e5SSebastian Reichel if (ret >= 0) 30448c0984e5SSebastian Reichel di->usb.charger_voltage = ret; 30458c0984e5SSebastian Reichel val->intval = di->usb.charger_voltage * 1000; 30468c0984e5SSebastian Reichel break; 30478c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_AVG: 30488c0984e5SSebastian Reichel /* 30498c0984e5SSebastian Reichel * This property is used to indicate when CV mode is entered 30508c0984e5SSebastian Reichel * for the USB charger 30518c0984e5SSebastian Reichel */ 30528c0984e5SSebastian Reichel di->usb.cv_active = ab8500_charger_usb_cv(di); 30538c0984e5SSebastian Reichel val->intval = di->usb.cv_active; 30548c0984e5SSebastian Reichel break; 30558c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CURRENT_NOW: 30568c0984e5SSebastian Reichel ret = ab8500_charger_get_usb_current(di); 30578c0984e5SSebastian Reichel if (ret >= 0) 30588c0984e5SSebastian Reichel di->usb.charger_current = ret; 30598c0984e5SSebastian Reichel val->intval = di->usb.charger_current * 1000; 30608c0984e5SSebastian Reichel break; 30618c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CURRENT_AVG: 30628c0984e5SSebastian Reichel /* 30638c0984e5SSebastian Reichel * This property is used to indicate when VBUS has collapsed 30648c0984e5SSebastian Reichel * due to too high output current from the USB charger 30658c0984e5SSebastian Reichel */ 30668c0984e5SSebastian Reichel if (di->flags.vbus_collapse) 30678c0984e5SSebastian Reichel val->intval = 1; 30688c0984e5SSebastian Reichel else 30698c0984e5SSebastian Reichel val->intval = 0; 30708c0984e5SSebastian Reichel break; 30718c0984e5SSebastian Reichel default: 30728c0984e5SSebastian Reichel return -EINVAL; 30738c0984e5SSebastian Reichel } 30748c0984e5SSebastian Reichel return 0; 30758c0984e5SSebastian Reichel } 30768c0984e5SSebastian Reichel 30778c0984e5SSebastian Reichel /** 30788c0984e5SSebastian Reichel * ab8500_charger_init_hw_registers() - Set up charger related registers 30798c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 30808c0984e5SSebastian Reichel * 30818c0984e5SSebastian Reichel * Set up charger OVV, watchdog and maximum voltage registers as well as 30828c0984e5SSebastian Reichel * charging of the backup battery 30838c0984e5SSebastian Reichel */ 30848c0984e5SSebastian Reichel static int ab8500_charger_init_hw_registers(struct ab8500_charger *di) 30858c0984e5SSebastian Reichel { 30868c0984e5SSebastian Reichel int ret = 0; 30878c0984e5SSebastian Reichel u8 bup_vch_range = 0, vbup33_vrtcn = 0; 30888c0984e5SSebastian Reichel 30898c0984e5SSebastian Reichel /* Setup maximum charger current and voltage for ABB cut2.0 */ 30908c0984e5SSebastian Reichel if (!is_ab8500_1p1_or_earlier(di->parent)) { 30918c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 30928c0984e5SSebastian Reichel AB8500_CHARGER, 30938c0984e5SSebastian Reichel AB8500_CH_VOLT_LVL_MAX_REG, CH_VOL_LVL_4P6); 30948c0984e5SSebastian Reichel if (ret) { 30958c0984e5SSebastian Reichel dev_err(di->dev, 30968c0984e5SSebastian Reichel "failed to set CH_VOLT_LVL_MAX_REG\n"); 30978c0984e5SSebastian Reichel goto out; 30988c0984e5SSebastian Reichel } 30998c0984e5SSebastian Reichel 31008c0984e5SSebastian Reichel if (is_ab8540(di->parent)) 31018c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 31028c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_OPT_CRNTLVL_MAX_REG, 31038c0984e5SSebastian Reichel CH_OP_CUR_LVL_2P); 31048c0984e5SSebastian Reichel else 31058c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 31068c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_OPT_CRNTLVL_MAX_REG, 31078c0984e5SSebastian Reichel CH_OP_CUR_LVL_1P6); 31088c0984e5SSebastian Reichel if (ret) { 31098c0984e5SSebastian Reichel dev_err(di->dev, 31108c0984e5SSebastian Reichel "failed to set CH_OPT_CRNTLVL_MAX_REG\n"); 31118c0984e5SSebastian Reichel goto out; 31128c0984e5SSebastian Reichel } 31138c0984e5SSebastian Reichel } 31148c0984e5SSebastian Reichel 31158c0984e5SSebastian Reichel if (is_ab9540_2p0(di->parent) || is_ab9540_3p0(di->parent) 31168c0984e5SSebastian Reichel || is_ab8505_2p0(di->parent) || is_ab8540(di->parent)) 31178c0984e5SSebastian Reichel ret = abx500_mask_and_set_register_interruptible(di->dev, 31188c0984e5SSebastian Reichel AB8500_CHARGER, 31198c0984e5SSebastian Reichel AB8500_USBCH_CTRL2_REG, 31208c0984e5SSebastian Reichel VBUS_AUTO_IN_CURR_LIM_ENA, 31218c0984e5SSebastian Reichel VBUS_AUTO_IN_CURR_LIM_ENA); 31228c0984e5SSebastian Reichel else 31238c0984e5SSebastian Reichel /* 31248c0984e5SSebastian Reichel * VBUS OVV set to 6.3V and enable automatic current limitation 31258c0984e5SSebastian Reichel */ 31268c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 31278c0984e5SSebastian Reichel AB8500_CHARGER, 31288c0984e5SSebastian Reichel AB8500_USBCH_CTRL2_REG, 31298c0984e5SSebastian Reichel VBUS_OVV_SELECT_6P3V | VBUS_AUTO_IN_CURR_LIM_ENA); 31308c0984e5SSebastian Reichel if (ret) { 31318c0984e5SSebastian Reichel dev_err(di->dev, 31328c0984e5SSebastian Reichel "failed to set automatic current limitation\n"); 31338c0984e5SSebastian Reichel goto out; 31348c0984e5SSebastian Reichel } 31358c0984e5SSebastian Reichel 31368c0984e5SSebastian Reichel /* Enable main watchdog in OTP */ 31378c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 31388c0984e5SSebastian Reichel AB8500_OTP_EMUL, AB8500_OTP_CONF_15, OTP_ENABLE_WD); 31398c0984e5SSebastian Reichel if (ret) { 31408c0984e5SSebastian Reichel dev_err(di->dev, "failed to enable main WD in OTP\n"); 31418c0984e5SSebastian Reichel goto out; 31428c0984e5SSebastian Reichel } 31438c0984e5SSebastian Reichel 31448c0984e5SSebastian Reichel /* Enable main watchdog */ 31458c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 31468c0984e5SSebastian Reichel AB8500_SYS_CTRL2_BLOCK, 31478c0984e5SSebastian Reichel AB8500_MAIN_WDOG_CTRL_REG, MAIN_WDOG_ENA); 31488c0984e5SSebastian Reichel if (ret) { 31498c0984e5SSebastian Reichel dev_err(di->dev, "faile to enable main watchdog\n"); 31508c0984e5SSebastian Reichel goto out; 31518c0984e5SSebastian Reichel } 31528c0984e5SSebastian Reichel 31538c0984e5SSebastian Reichel /* 31548c0984e5SSebastian Reichel * Due to internal synchronisation, Enable and Kick watchdog bits 31558c0984e5SSebastian Reichel * cannot be enabled in a single write. 31568c0984e5SSebastian Reichel * A minimum delay of 2*32 kHz period (62.5µs) must be inserted 31578c0984e5SSebastian Reichel * between writing Enable then Kick bits. 31588c0984e5SSebastian Reichel */ 31598c0984e5SSebastian Reichel udelay(63); 31608c0984e5SSebastian Reichel 31618c0984e5SSebastian Reichel /* Kick main watchdog */ 31628c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 31638c0984e5SSebastian Reichel AB8500_SYS_CTRL2_BLOCK, 31648c0984e5SSebastian Reichel AB8500_MAIN_WDOG_CTRL_REG, 31658c0984e5SSebastian Reichel (MAIN_WDOG_ENA | MAIN_WDOG_KICK)); 31668c0984e5SSebastian Reichel if (ret) { 31678c0984e5SSebastian Reichel dev_err(di->dev, "failed to kick main watchdog\n"); 31688c0984e5SSebastian Reichel goto out; 31698c0984e5SSebastian Reichel } 31708c0984e5SSebastian Reichel 31718c0984e5SSebastian Reichel /* Disable main watchdog */ 31728c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 31738c0984e5SSebastian Reichel AB8500_SYS_CTRL2_BLOCK, 31748c0984e5SSebastian Reichel AB8500_MAIN_WDOG_CTRL_REG, MAIN_WDOG_DIS); 31758c0984e5SSebastian Reichel if (ret) { 31768c0984e5SSebastian Reichel dev_err(di->dev, "failed to disable main watchdog\n"); 31778c0984e5SSebastian Reichel goto out; 31788c0984e5SSebastian Reichel } 31798c0984e5SSebastian Reichel 31808c0984e5SSebastian Reichel /* Set watchdog timeout */ 31818c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 31828c0984e5SSebastian Reichel AB8500_CH_WD_TIMER_REG, WD_TIMER); 31838c0984e5SSebastian Reichel if (ret) { 31848c0984e5SSebastian Reichel dev_err(di->dev, "failed to set charger watchdog timeout\n"); 31858c0984e5SSebastian Reichel goto out; 31868c0984e5SSebastian Reichel } 31878c0984e5SSebastian Reichel 31888c0984e5SSebastian Reichel ret = ab8500_charger_led_en(di, false); 31898c0984e5SSebastian Reichel if (ret < 0) { 31908c0984e5SSebastian Reichel dev_err(di->dev, "failed to disable LED\n"); 31918c0984e5SSebastian Reichel goto out; 31928c0984e5SSebastian Reichel } 31938c0984e5SSebastian Reichel 31948c0984e5SSebastian Reichel /* Backup battery voltage and current */ 31958c0984e5SSebastian Reichel if (di->bm->bkup_bat_v > BUP_VCH_SEL_3P1V) 31968c0984e5SSebastian Reichel bup_vch_range = BUP_VCH_RANGE; 31978c0984e5SSebastian Reichel if (di->bm->bkup_bat_v == BUP_VCH_SEL_3P3V) 31988c0984e5SSebastian Reichel vbup33_vrtcn = VBUP33_VRTCN; 31998c0984e5SSebastian Reichel 32008c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 32018c0984e5SSebastian Reichel AB8500_RTC, 32028c0984e5SSebastian Reichel AB8500_RTC_BACKUP_CHG_REG, 32038c0984e5SSebastian Reichel (di->bm->bkup_bat_v & 0x3) | di->bm->bkup_bat_i); 32048c0984e5SSebastian Reichel if (ret) { 32058c0984e5SSebastian Reichel dev_err(di->dev, "failed to setup backup battery charging\n"); 32068c0984e5SSebastian Reichel goto out; 32078c0984e5SSebastian Reichel } 32088c0984e5SSebastian Reichel if (is_ab8540(di->parent)) { 32098c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 32108c0984e5SSebastian Reichel AB8500_RTC, 32118c0984e5SSebastian Reichel AB8500_RTC_CTRL1_REG, 32128c0984e5SSebastian Reichel bup_vch_range | vbup33_vrtcn); 32138c0984e5SSebastian Reichel if (ret) { 32148c0984e5SSebastian Reichel dev_err(di->dev, 32158c0984e5SSebastian Reichel "failed to setup backup battery charging\n"); 32168c0984e5SSebastian Reichel goto out; 32178c0984e5SSebastian Reichel } 32188c0984e5SSebastian Reichel } 32198c0984e5SSebastian Reichel 32208c0984e5SSebastian Reichel /* Enable backup battery charging */ 32218c0984e5SSebastian Reichel abx500_mask_and_set_register_interruptible(di->dev, 32228c0984e5SSebastian Reichel AB8500_RTC, AB8500_RTC_CTRL_REG, 32238c0984e5SSebastian Reichel RTC_BUP_CH_ENA, RTC_BUP_CH_ENA); 32248c0984e5SSebastian Reichel if (ret < 0) 32258c0984e5SSebastian Reichel dev_err(di->dev, "%s mask and set failed\n", __func__); 32268c0984e5SSebastian Reichel 32278c0984e5SSebastian Reichel if (is_ab8540(di->parent)) { 32288c0984e5SSebastian Reichel ret = abx500_mask_and_set_register_interruptible(di->dev, 32298c0984e5SSebastian Reichel AB8500_CHARGER, AB8540_USB_PP_MODE_REG, 32308c0984e5SSebastian Reichel BUS_VSYS_VOL_SELECT_MASK, BUS_VSYS_VOL_SELECT_3P6V); 32318c0984e5SSebastian Reichel if (ret) { 32328c0984e5SSebastian Reichel dev_err(di->dev, 32338c0984e5SSebastian Reichel "failed to setup usb power path vsys voltage\n"); 32348c0984e5SSebastian Reichel goto out; 32358c0984e5SSebastian Reichel } 32368c0984e5SSebastian Reichel ret = abx500_mask_and_set_register_interruptible(di->dev, 32378c0984e5SSebastian Reichel AB8500_CHARGER, AB8540_USB_PP_CHR_REG, 32388c0984e5SSebastian Reichel BUS_PP_PRECHG_CURRENT_MASK, 0); 32398c0984e5SSebastian Reichel if (ret) { 32408c0984e5SSebastian Reichel dev_err(di->dev, 32418c0984e5SSebastian Reichel "failed to setup usb power path prechage current\n"); 32428c0984e5SSebastian Reichel goto out; 32438c0984e5SSebastian Reichel } 32448c0984e5SSebastian Reichel } 32458c0984e5SSebastian Reichel 32468c0984e5SSebastian Reichel out: 32478c0984e5SSebastian Reichel return ret; 32488c0984e5SSebastian Reichel } 32498c0984e5SSebastian Reichel 32508c0984e5SSebastian Reichel /* 32518c0984e5SSebastian Reichel * ab8500 charger driver interrupts and their respective isr 32528c0984e5SSebastian Reichel */ 32538c0984e5SSebastian Reichel static struct ab8500_charger_interrupts ab8500_charger_irq[] = { 32548c0984e5SSebastian Reichel {"MAIN_CH_UNPLUG_DET", ab8500_charger_mainchunplugdet_handler}, 32558c0984e5SSebastian Reichel {"MAIN_CHARGE_PLUG_DET", ab8500_charger_mainchplugdet_handler}, 32568c0984e5SSebastian Reichel {"MAIN_EXT_CH_NOT_OK", ab8500_charger_mainextchnotok_handler}, 32578c0984e5SSebastian Reichel {"MAIN_CH_TH_PROT_R", ab8500_charger_mainchthprotr_handler}, 32588c0984e5SSebastian Reichel {"MAIN_CH_TH_PROT_F", ab8500_charger_mainchthprotf_handler}, 32598c0984e5SSebastian Reichel {"VBUS_DET_F", ab8500_charger_vbusdetf_handler}, 32608c0984e5SSebastian Reichel {"VBUS_DET_R", ab8500_charger_vbusdetr_handler}, 32618c0984e5SSebastian Reichel {"USB_LINK_STATUS", ab8500_charger_usblinkstatus_handler}, 32628c0984e5SSebastian Reichel {"USB_CH_TH_PROT_R", ab8500_charger_usbchthprotr_handler}, 32638c0984e5SSebastian Reichel {"USB_CH_TH_PROT_F", ab8500_charger_usbchthprotf_handler}, 32648c0984e5SSebastian Reichel {"USB_CHARGER_NOT_OKR", ab8500_charger_usbchargernotokr_handler}, 32658c0984e5SSebastian Reichel {"VBUS_OVV", ab8500_charger_vbusovv_handler}, 32668c0984e5SSebastian Reichel {"CH_WD_EXP", ab8500_charger_chwdexp_handler}, 32678c0984e5SSebastian Reichel {"VBUS_CH_DROP_END", ab8500_charger_vbuschdropend_handler}, 32688c0984e5SSebastian Reichel }; 32698c0984e5SSebastian Reichel 32708c0984e5SSebastian Reichel static int ab8500_charger_usb_notifier_call(struct notifier_block *nb, 32718c0984e5SSebastian Reichel unsigned long event, void *power) 32728c0984e5SSebastian Reichel { 32738c0984e5SSebastian Reichel struct ab8500_charger *di = 32748c0984e5SSebastian Reichel container_of(nb, struct ab8500_charger, nb); 32758c0984e5SSebastian Reichel enum ab8500_usb_state bm_usb_state; 32768c0984e5SSebastian Reichel unsigned mA = *((unsigned *)power); 32778c0984e5SSebastian Reichel 32788c0984e5SSebastian Reichel if (!di) 32798c0984e5SSebastian Reichel return NOTIFY_DONE; 32808c0984e5SSebastian Reichel 32818c0984e5SSebastian Reichel if (event != USB_EVENT_VBUS) { 32828c0984e5SSebastian Reichel dev_dbg(di->dev, "not a standard host, returning\n"); 32838c0984e5SSebastian Reichel return NOTIFY_DONE; 32848c0984e5SSebastian Reichel } 32858c0984e5SSebastian Reichel 32868c0984e5SSebastian Reichel /* TODO: State is fabricate here. See if charger really needs USB 32878c0984e5SSebastian Reichel * state or if mA is enough 32888c0984e5SSebastian Reichel */ 32898c0984e5SSebastian Reichel if ((di->usb_state.usb_current == 2) && (mA > 2)) 32908c0984e5SSebastian Reichel bm_usb_state = AB8500_BM_USB_STATE_RESUME; 32918c0984e5SSebastian Reichel else if (mA == 0) 32928c0984e5SSebastian Reichel bm_usb_state = AB8500_BM_USB_STATE_RESET_HS; 32938c0984e5SSebastian Reichel else if (mA == 2) 32948c0984e5SSebastian Reichel bm_usb_state = AB8500_BM_USB_STATE_SUSPEND; 32958c0984e5SSebastian Reichel else if (mA >= 8) /* 8, 100, 500 */ 32968c0984e5SSebastian Reichel bm_usb_state = AB8500_BM_USB_STATE_CONFIGURED; 32978c0984e5SSebastian Reichel else /* Should never occur */ 32988c0984e5SSebastian Reichel bm_usb_state = AB8500_BM_USB_STATE_RESET_FS; 32998c0984e5SSebastian Reichel 33008c0984e5SSebastian Reichel dev_dbg(di->dev, "%s usb_state: 0x%02x mA: %d\n", 33018c0984e5SSebastian Reichel __func__, bm_usb_state, mA); 33028c0984e5SSebastian Reichel 33038c0984e5SSebastian Reichel spin_lock(&di->usb_state.usb_lock); 33048c0984e5SSebastian Reichel di->usb_state.state_tmp = bm_usb_state; 33058c0984e5SSebastian Reichel di->usb_state.usb_current_tmp = mA; 33068c0984e5SSebastian Reichel spin_unlock(&di->usb_state.usb_lock); 33078c0984e5SSebastian Reichel 33088c0984e5SSebastian Reichel /* 33098c0984e5SSebastian Reichel * wait for some time until you get updates from the usb stack 33108c0984e5SSebastian Reichel * and negotiations are completed 33118c0984e5SSebastian Reichel */ 33128c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->usb_state_changed_work, HZ/2); 33138c0984e5SSebastian Reichel 33148c0984e5SSebastian Reichel return NOTIFY_OK; 33158c0984e5SSebastian Reichel } 33168c0984e5SSebastian Reichel 33178c0984e5SSebastian Reichel #if defined(CONFIG_PM) 33188c0984e5SSebastian Reichel static int ab8500_charger_resume(struct platform_device *pdev) 33198c0984e5SSebastian Reichel { 33208c0984e5SSebastian Reichel int ret; 33218c0984e5SSebastian Reichel struct ab8500_charger *di = platform_get_drvdata(pdev); 33228c0984e5SSebastian Reichel 33238c0984e5SSebastian Reichel /* 33248c0984e5SSebastian Reichel * For ABB revision 1.0 and 1.1 there is a bug in the watchdog 33258c0984e5SSebastian Reichel * logic. That means we have to continously kick the charger 33268c0984e5SSebastian Reichel * watchdog even when no charger is connected. This is only 33278c0984e5SSebastian Reichel * valid once the AC charger has been enabled. This is 33288c0984e5SSebastian Reichel * a bug that is not handled by the algorithm and the 33298c0984e5SSebastian Reichel * watchdog have to be kicked by the charger driver 33308c0984e5SSebastian Reichel * when the AC charger is disabled 33318c0984e5SSebastian Reichel */ 33328c0984e5SSebastian Reichel if (di->ac_conn && is_ab8500_1p1_or_earlier(di->parent)) { 33338c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 33348c0984e5SSebastian Reichel AB8500_CHARG_WD_CTRL, CHARG_WD_KICK); 33358c0984e5SSebastian Reichel if (ret) 33368c0984e5SSebastian Reichel dev_err(di->dev, "Failed to kick WD!\n"); 33378c0984e5SSebastian Reichel 33388c0984e5SSebastian Reichel /* If not already pending start a new timer */ 33398c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->kick_wd_work, 33408c0984e5SSebastian Reichel round_jiffies(WD_KICK_INTERVAL)); 33418c0984e5SSebastian Reichel } 33428c0984e5SSebastian Reichel 33438c0984e5SSebastian Reichel /* If we still have a HW failure, schedule a new check */ 33448c0984e5SSebastian Reichel if (di->flags.mainextchnotok || di->flags.vbus_ovv) { 33458c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 33468c0984e5SSebastian Reichel &di->check_hw_failure_work, 0); 33478c0984e5SSebastian Reichel } 33488c0984e5SSebastian Reichel 33498c0984e5SSebastian Reichel if (di->flags.vbus_drop_end) 33508c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->vbus_drop_end_work, 0); 33518c0984e5SSebastian Reichel 33528c0984e5SSebastian Reichel return 0; 33538c0984e5SSebastian Reichel } 33548c0984e5SSebastian Reichel 33558c0984e5SSebastian Reichel static int ab8500_charger_suspend(struct platform_device *pdev, 33568c0984e5SSebastian Reichel pm_message_t state) 33578c0984e5SSebastian Reichel { 33588c0984e5SSebastian Reichel struct ab8500_charger *di = platform_get_drvdata(pdev); 33598c0984e5SSebastian Reichel 33608c0984e5SSebastian Reichel /* Cancel any pending jobs */ 33618c0984e5SSebastian Reichel cancel_delayed_work(&di->check_hw_failure_work); 33628c0984e5SSebastian Reichel cancel_delayed_work(&di->vbus_drop_end_work); 33638c0984e5SSebastian Reichel 33648c0984e5SSebastian Reichel flush_delayed_work(&di->attach_work); 33658c0984e5SSebastian Reichel flush_delayed_work(&di->usb_charger_attached_work); 33668c0984e5SSebastian Reichel flush_delayed_work(&di->ac_charger_attached_work); 33678c0984e5SSebastian Reichel flush_delayed_work(&di->check_usbchgnotok_work); 33688c0984e5SSebastian Reichel flush_delayed_work(&di->check_vbat_work); 33698c0984e5SSebastian Reichel flush_delayed_work(&di->kick_wd_work); 33708c0984e5SSebastian Reichel 33718c0984e5SSebastian Reichel flush_work(&di->usb_link_status_work); 33728c0984e5SSebastian Reichel flush_work(&di->ac_work); 33738c0984e5SSebastian Reichel flush_work(&di->detect_usb_type_work); 33748c0984e5SSebastian Reichel 33758c0984e5SSebastian Reichel if (atomic_read(&di->current_stepping_sessions)) 33768c0984e5SSebastian Reichel return -EAGAIN; 33778c0984e5SSebastian Reichel 33788c0984e5SSebastian Reichel return 0; 33798c0984e5SSebastian Reichel } 33808c0984e5SSebastian Reichel #else 33818c0984e5SSebastian Reichel #define ab8500_charger_suspend NULL 33828c0984e5SSebastian Reichel #define ab8500_charger_resume NULL 33838c0984e5SSebastian Reichel #endif 33848c0984e5SSebastian Reichel 33858c0984e5SSebastian Reichel static struct notifier_block charger_nb = { 33868c0984e5SSebastian Reichel .notifier_call = ab8500_external_charger_prepare, 33878c0984e5SSebastian Reichel }; 33888c0984e5SSebastian Reichel 33898c0984e5SSebastian Reichel static int ab8500_charger_remove(struct platform_device *pdev) 33908c0984e5SSebastian Reichel { 33918c0984e5SSebastian Reichel struct ab8500_charger *di = platform_get_drvdata(pdev); 33928c0984e5SSebastian Reichel int i, irq, ret; 33938c0984e5SSebastian Reichel 33948c0984e5SSebastian Reichel /* Disable AC charging */ 33958c0984e5SSebastian Reichel ab8500_charger_ac_en(&di->ac_chg, false, 0, 0); 33968c0984e5SSebastian Reichel 33978c0984e5SSebastian Reichel /* Disable USB charging */ 33988c0984e5SSebastian Reichel ab8500_charger_usb_en(&di->usb_chg, false, 0, 0); 33998c0984e5SSebastian Reichel 34008c0984e5SSebastian Reichel /* Disable interrupts */ 34018c0984e5SSebastian Reichel for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { 34028c0984e5SSebastian Reichel irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); 34038c0984e5SSebastian Reichel free_irq(irq, di); 34048c0984e5SSebastian Reichel } 34058c0984e5SSebastian Reichel 34068c0984e5SSebastian Reichel /* Backup battery voltage and current disable */ 34078c0984e5SSebastian Reichel ret = abx500_mask_and_set_register_interruptible(di->dev, 34088c0984e5SSebastian Reichel AB8500_RTC, AB8500_RTC_CTRL_REG, RTC_BUP_CH_ENA, 0); 34098c0984e5SSebastian Reichel if (ret < 0) 34108c0984e5SSebastian Reichel dev_err(di->dev, "%s mask and set failed\n", __func__); 34118c0984e5SSebastian Reichel 34128c0984e5SSebastian Reichel usb_unregister_notifier(di->usb_phy, &di->nb); 34138c0984e5SSebastian Reichel usb_put_phy(di->usb_phy); 34148c0984e5SSebastian Reichel 34158c0984e5SSebastian Reichel /* Delete the work queue */ 34168c0984e5SSebastian Reichel destroy_workqueue(di->charger_wq); 34178c0984e5SSebastian Reichel 34188c0984e5SSebastian Reichel /* Unregister external charger enable notifier */ 34198c0984e5SSebastian Reichel if (!di->ac_chg.enabled) 34208c0984e5SSebastian Reichel blocking_notifier_chain_unregister( 34218c0984e5SSebastian Reichel &charger_notifier_list, &charger_nb); 34228c0984e5SSebastian Reichel 34238c0984e5SSebastian Reichel flush_scheduled_work(); 34248c0984e5SSebastian Reichel if (di->usb_chg.enabled) 34258c0984e5SSebastian Reichel power_supply_unregister(di->usb_chg.psy); 34268c0984e5SSebastian Reichel 34278c0984e5SSebastian Reichel if (di->ac_chg.enabled && !di->ac_chg.external) 34288c0984e5SSebastian Reichel power_supply_unregister(di->ac_chg.psy); 34298c0984e5SSebastian Reichel 34308c0984e5SSebastian Reichel return 0; 34318c0984e5SSebastian Reichel } 34328c0984e5SSebastian Reichel 34338c0984e5SSebastian Reichel static char *supply_interface[] = { 34348c0984e5SSebastian Reichel "ab8500_chargalg", 34358c0984e5SSebastian Reichel "ab8500_fg", 34368c0984e5SSebastian Reichel "ab8500_btemp", 34378c0984e5SSebastian Reichel }; 34388c0984e5SSebastian Reichel 34398c0984e5SSebastian Reichel static const struct power_supply_desc ab8500_ac_chg_desc = { 34408c0984e5SSebastian Reichel .name = "ab8500_ac", 34418c0984e5SSebastian Reichel .type = POWER_SUPPLY_TYPE_MAINS, 34428c0984e5SSebastian Reichel .properties = ab8500_charger_ac_props, 34438c0984e5SSebastian Reichel .num_properties = ARRAY_SIZE(ab8500_charger_ac_props), 34448c0984e5SSebastian Reichel .get_property = ab8500_charger_ac_get_property, 34458c0984e5SSebastian Reichel }; 34468c0984e5SSebastian Reichel 34478c0984e5SSebastian Reichel static const struct power_supply_desc ab8500_usb_chg_desc = { 34488c0984e5SSebastian Reichel .name = "ab8500_usb", 34498c0984e5SSebastian Reichel .type = POWER_SUPPLY_TYPE_USB, 34508c0984e5SSebastian Reichel .properties = ab8500_charger_usb_props, 34518c0984e5SSebastian Reichel .num_properties = ARRAY_SIZE(ab8500_charger_usb_props), 34528c0984e5SSebastian Reichel .get_property = ab8500_charger_usb_get_property, 34538c0984e5SSebastian Reichel }; 34548c0984e5SSebastian Reichel 34558c0984e5SSebastian Reichel static int ab8500_charger_probe(struct platform_device *pdev) 34568c0984e5SSebastian Reichel { 34578c0984e5SSebastian Reichel struct device_node *np = pdev->dev.of_node; 34588c0984e5SSebastian Reichel struct abx500_bm_data *plat = pdev->dev.platform_data; 34598c0984e5SSebastian Reichel struct power_supply_config ac_psy_cfg = {}, usb_psy_cfg = {}; 34608c0984e5SSebastian Reichel struct ab8500_charger *di; 34618c0984e5SSebastian Reichel int irq, i, charger_status, ret = 0, ch_stat; 34628c0984e5SSebastian Reichel 34638c0984e5SSebastian Reichel di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL); 34648c0984e5SSebastian Reichel if (!di) { 34658c0984e5SSebastian Reichel dev_err(&pdev->dev, "%s no mem for ab8500_charger\n", __func__); 34668c0984e5SSebastian Reichel return -ENOMEM; 34678c0984e5SSebastian Reichel } 34688c0984e5SSebastian Reichel 34698c0984e5SSebastian Reichel if (!plat) { 34708c0984e5SSebastian Reichel dev_err(&pdev->dev, "no battery management data supplied\n"); 34718c0984e5SSebastian Reichel return -EINVAL; 34728c0984e5SSebastian Reichel } 34738c0984e5SSebastian Reichel di->bm = plat; 34748c0984e5SSebastian Reichel 34758c0984e5SSebastian Reichel if (np) { 34768c0984e5SSebastian Reichel ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm); 34778c0984e5SSebastian Reichel if (ret) { 34788c0984e5SSebastian Reichel dev_err(&pdev->dev, "failed to get battery information\n"); 34798c0984e5SSebastian Reichel return ret; 34808c0984e5SSebastian Reichel } 34818c0984e5SSebastian Reichel di->autopower_cfg = of_property_read_bool(np, "autopower_cfg"); 34828c0984e5SSebastian Reichel } else 34838c0984e5SSebastian Reichel di->autopower_cfg = false; 34848c0984e5SSebastian Reichel 34858c0984e5SSebastian Reichel /* get parent data */ 34868c0984e5SSebastian Reichel di->dev = &pdev->dev; 34878c0984e5SSebastian Reichel di->parent = dev_get_drvdata(pdev->dev.parent); 34888c0984e5SSebastian Reichel di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); 34898c0984e5SSebastian Reichel 34908c0984e5SSebastian Reichel /* initialize lock */ 34918c0984e5SSebastian Reichel spin_lock_init(&di->usb_state.usb_lock); 34928c0984e5SSebastian Reichel mutex_init(&di->usb_ipt_crnt_lock); 34938c0984e5SSebastian Reichel 34948c0984e5SSebastian Reichel di->autopower = false; 34958c0984e5SSebastian Reichel di->invalid_charger_detect_state = 0; 34968c0984e5SSebastian Reichel 34978c0984e5SSebastian Reichel /* AC and USB supply config */ 34988c0984e5SSebastian Reichel ac_psy_cfg.supplied_to = supply_interface; 34998c0984e5SSebastian Reichel ac_psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); 35008c0984e5SSebastian Reichel ac_psy_cfg.drv_data = &di->ac_chg; 35018c0984e5SSebastian Reichel usb_psy_cfg.supplied_to = supply_interface; 35028c0984e5SSebastian Reichel usb_psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); 35038c0984e5SSebastian Reichel usb_psy_cfg.drv_data = &di->usb_chg; 35048c0984e5SSebastian Reichel 35058c0984e5SSebastian Reichel /* AC supply */ 35068c0984e5SSebastian Reichel /* ux500_charger sub-class */ 35078c0984e5SSebastian Reichel di->ac_chg.ops.enable = &ab8500_charger_ac_en; 35088c0984e5SSebastian Reichel di->ac_chg.ops.check_enable = &ab8500_charger_ac_check_enable; 35098c0984e5SSebastian Reichel di->ac_chg.ops.kick_wd = &ab8500_charger_watchdog_kick; 35108c0984e5SSebastian Reichel di->ac_chg.ops.update_curr = &ab8500_charger_update_charger_current; 35118c0984e5SSebastian Reichel di->ac_chg.max_out_volt = ab8500_charger_voltage_map[ 35128c0984e5SSebastian Reichel ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; 35138c0984e5SSebastian Reichel di->ac_chg.max_out_curr = 35148c0984e5SSebastian Reichel di->bm->chg_output_curr[di->bm->n_chg_out_curr - 1]; 35158c0984e5SSebastian Reichel di->ac_chg.wdt_refresh = CHG_WD_INTERVAL; 35168c0984e5SSebastian Reichel di->ac_chg.enabled = di->bm->ac_enabled; 35178c0984e5SSebastian Reichel di->ac_chg.external = false; 35188c0984e5SSebastian Reichel 35198c0984e5SSebastian Reichel /*notifier for external charger enabling*/ 35208c0984e5SSebastian Reichel if (!di->ac_chg.enabled) 35218c0984e5SSebastian Reichel blocking_notifier_chain_register( 35228c0984e5SSebastian Reichel &charger_notifier_list, &charger_nb); 35238c0984e5SSebastian Reichel 35248c0984e5SSebastian Reichel /* USB supply */ 35258c0984e5SSebastian Reichel /* ux500_charger sub-class */ 35268c0984e5SSebastian Reichel di->usb_chg.ops.enable = &ab8500_charger_usb_en; 35278c0984e5SSebastian Reichel di->usb_chg.ops.check_enable = &ab8500_charger_usb_check_enable; 35288c0984e5SSebastian Reichel di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick; 35298c0984e5SSebastian Reichel di->usb_chg.ops.update_curr = &ab8500_charger_update_charger_current; 35308c0984e5SSebastian Reichel di->usb_chg.ops.pp_enable = &ab8540_charger_power_path_enable; 35318c0984e5SSebastian Reichel di->usb_chg.ops.pre_chg_enable = &ab8540_charger_usb_pre_chg_enable; 35328c0984e5SSebastian Reichel di->usb_chg.max_out_volt = ab8500_charger_voltage_map[ 35338c0984e5SSebastian Reichel ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; 35348c0984e5SSebastian Reichel di->usb_chg.max_out_curr = 35358c0984e5SSebastian Reichel di->bm->chg_output_curr[di->bm->n_chg_out_curr - 1]; 35368c0984e5SSebastian Reichel di->usb_chg.wdt_refresh = CHG_WD_INTERVAL; 35378c0984e5SSebastian Reichel di->usb_chg.enabled = di->bm->usb_enabled; 35388c0984e5SSebastian Reichel di->usb_chg.external = false; 35398c0984e5SSebastian Reichel di->usb_chg.power_path = di->bm->usb_power_path; 35408c0984e5SSebastian Reichel di->usb_state.usb_current = -1; 35418c0984e5SSebastian Reichel 35428c0984e5SSebastian Reichel /* Create a work queue for the charger */ 3543*9df82628SBhaktipriya Shridhar di->charger_wq = alloc_ordered_workqueue("ab8500_charger_wq", 3544*9df82628SBhaktipriya Shridhar WQ_MEM_RECLAIM); 35458c0984e5SSebastian Reichel if (di->charger_wq == NULL) { 35468c0984e5SSebastian Reichel dev_err(di->dev, "failed to create work queue\n"); 35478c0984e5SSebastian Reichel return -ENOMEM; 35488c0984e5SSebastian Reichel } 35498c0984e5SSebastian Reichel 35508c0984e5SSebastian Reichel mutex_init(&di->charger_attached_mutex); 35518c0984e5SSebastian Reichel 35528c0984e5SSebastian Reichel /* Init work for HW failure check */ 35538c0984e5SSebastian Reichel INIT_DEFERRABLE_WORK(&di->check_hw_failure_work, 35548c0984e5SSebastian Reichel ab8500_charger_check_hw_failure_work); 35558c0984e5SSebastian Reichel INIT_DEFERRABLE_WORK(&di->check_usbchgnotok_work, 35568c0984e5SSebastian Reichel ab8500_charger_check_usbchargernotok_work); 35578c0984e5SSebastian Reichel 35588c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->ac_charger_attached_work, 35598c0984e5SSebastian Reichel ab8500_charger_ac_attached_work); 35608c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->usb_charger_attached_work, 35618c0984e5SSebastian Reichel ab8500_charger_usb_attached_work); 35628c0984e5SSebastian Reichel 35638c0984e5SSebastian Reichel /* 35648c0984e5SSebastian Reichel * For ABB revision 1.0 and 1.1 there is a bug in the watchdog 35658c0984e5SSebastian Reichel * logic. That means we have to continously kick the charger 35668c0984e5SSebastian Reichel * watchdog even when no charger is connected. This is only 35678c0984e5SSebastian Reichel * valid once the AC charger has been enabled. This is 35688c0984e5SSebastian Reichel * a bug that is not handled by the algorithm and the 35698c0984e5SSebastian Reichel * watchdog have to be kicked by the charger driver 35708c0984e5SSebastian Reichel * when the AC charger is disabled 35718c0984e5SSebastian Reichel */ 35728c0984e5SSebastian Reichel INIT_DEFERRABLE_WORK(&di->kick_wd_work, 35738c0984e5SSebastian Reichel ab8500_charger_kick_watchdog_work); 35748c0984e5SSebastian Reichel 35758c0984e5SSebastian Reichel INIT_DEFERRABLE_WORK(&di->check_vbat_work, 35768c0984e5SSebastian Reichel ab8500_charger_check_vbat_work); 35778c0984e5SSebastian Reichel 35788c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->attach_work, 35798c0984e5SSebastian Reichel ab8500_charger_usb_link_attach_work); 35808c0984e5SSebastian Reichel 35818c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->usb_state_changed_work, 35828c0984e5SSebastian Reichel ab8500_charger_usb_state_changed_work); 35838c0984e5SSebastian Reichel 35848c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->vbus_drop_end_work, 35858c0984e5SSebastian Reichel ab8500_charger_vbus_drop_end_work); 35868c0984e5SSebastian Reichel 35878c0984e5SSebastian Reichel /* Init work for charger detection */ 35888c0984e5SSebastian Reichel INIT_WORK(&di->usb_link_status_work, 35898c0984e5SSebastian Reichel ab8500_charger_usb_link_status_work); 35908c0984e5SSebastian Reichel INIT_WORK(&di->ac_work, ab8500_charger_ac_work); 35918c0984e5SSebastian Reichel INIT_WORK(&di->detect_usb_type_work, 35928c0984e5SSebastian Reichel ab8500_charger_detect_usb_type_work); 35938c0984e5SSebastian Reichel 35948c0984e5SSebastian Reichel /* Init work for checking HW status */ 35958c0984e5SSebastian Reichel INIT_WORK(&di->check_main_thermal_prot_work, 35968c0984e5SSebastian Reichel ab8500_charger_check_main_thermal_prot_work); 35978c0984e5SSebastian Reichel INIT_WORK(&di->check_usb_thermal_prot_work, 35988c0984e5SSebastian Reichel ab8500_charger_check_usb_thermal_prot_work); 35998c0984e5SSebastian Reichel 36008c0984e5SSebastian Reichel /* 36018c0984e5SSebastian Reichel * VDD ADC supply needs to be enabled from this driver when there 36028c0984e5SSebastian Reichel * is a charger connected to avoid erroneous BTEMP_HIGH/LOW 36038c0984e5SSebastian Reichel * interrupts during charging 36048c0984e5SSebastian Reichel */ 36058c0984e5SSebastian Reichel di->regu = devm_regulator_get(di->dev, "vddadc"); 36068c0984e5SSebastian Reichel if (IS_ERR(di->regu)) { 36078c0984e5SSebastian Reichel ret = PTR_ERR(di->regu); 36088c0984e5SSebastian Reichel dev_err(di->dev, "failed to get vddadc regulator\n"); 36098c0984e5SSebastian Reichel goto free_charger_wq; 36108c0984e5SSebastian Reichel } 36118c0984e5SSebastian Reichel 36128c0984e5SSebastian Reichel 36138c0984e5SSebastian Reichel /* Initialize OVV, and other registers */ 36148c0984e5SSebastian Reichel ret = ab8500_charger_init_hw_registers(di); 36158c0984e5SSebastian Reichel if (ret) { 36168c0984e5SSebastian Reichel dev_err(di->dev, "failed to initialize ABB registers\n"); 36178c0984e5SSebastian Reichel goto free_charger_wq; 36188c0984e5SSebastian Reichel } 36198c0984e5SSebastian Reichel 36208c0984e5SSebastian Reichel /* Register AC charger class */ 36218c0984e5SSebastian Reichel if (di->ac_chg.enabled) { 36228c0984e5SSebastian Reichel di->ac_chg.psy = power_supply_register(di->dev, 36238c0984e5SSebastian Reichel &ab8500_ac_chg_desc, 36248c0984e5SSebastian Reichel &ac_psy_cfg); 36258c0984e5SSebastian Reichel if (IS_ERR(di->ac_chg.psy)) { 36268c0984e5SSebastian Reichel dev_err(di->dev, "failed to register AC charger\n"); 36278c0984e5SSebastian Reichel ret = PTR_ERR(di->ac_chg.psy); 36288c0984e5SSebastian Reichel goto free_charger_wq; 36298c0984e5SSebastian Reichel } 36308c0984e5SSebastian Reichel } 36318c0984e5SSebastian Reichel 36328c0984e5SSebastian Reichel /* Register USB charger class */ 36338c0984e5SSebastian Reichel if (di->usb_chg.enabled) { 36348c0984e5SSebastian Reichel di->usb_chg.psy = power_supply_register(di->dev, 36358c0984e5SSebastian Reichel &ab8500_usb_chg_desc, 36368c0984e5SSebastian Reichel &usb_psy_cfg); 36378c0984e5SSebastian Reichel if (IS_ERR(di->usb_chg.psy)) { 36388c0984e5SSebastian Reichel dev_err(di->dev, "failed to register USB charger\n"); 36398c0984e5SSebastian Reichel ret = PTR_ERR(di->usb_chg.psy); 36408c0984e5SSebastian Reichel goto free_ac; 36418c0984e5SSebastian Reichel } 36428c0984e5SSebastian Reichel } 36438c0984e5SSebastian Reichel 36448c0984e5SSebastian Reichel di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2); 36458c0984e5SSebastian Reichel if (IS_ERR_OR_NULL(di->usb_phy)) { 36468c0984e5SSebastian Reichel dev_err(di->dev, "failed to get usb transceiver\n"); 36478c0984e5SSebastian Reichel ret = -EINVAL; 36488c0984e5SSebastian Reichel goto free_usb; 36498c0984e5SSebastian Reichel } 36508c0984e5SSebastian Reichel di->nb.notifier_call = ab8500_charger_usb_notifier_call; 36518c0984e5SSebastian Reichel ret = usb_register_notifier(di->usb_phy, &di->nb); 36528c0984e5SSebastian Reichel if (ret) { 36538c0984e5SSebastian Reichel dev_err(di->dev, "failed to register usb notifier\n"); 36548c0984e5SSebastian Reichel goto put_usb_phy; 36558c0984e5SSebastian Reichel } 36568c0984e5SSebastian Reichel 36578c0984e5SSebastian Reichel /* Identify the connected charger types during startup */ 36588c0984e5SSebastian Reichel charger_status = ab8500_charger_detect_chargers(di, true); 36598c0984e5SSebastian Reichel if (charger_status & AC_PW_CONN) { 36608c0984e5SSebastian Reichel di->ac.charger_connected = 1; 36618c0984e5SSebastian Reichel di->ac_conn = true; 36628c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 36638c0984e5SSebastian Reichel sysfs_notify(&di->ac_chg.psy->dev.kobj, NULL, "present"); 36648c0984e5SSebastian Reichel } 36658c0984e5SSebastian Reichel 36668c0984e5SSebastian Reichel if (charger_status & USB_PW_CONN) { 36678c0984e5SSebastian Reichel di->vbus_detected = true; 36688c0984e5SSebastian Reichel di->vbus_detected_start = true; 36698c0984e5SSebastian Reichel queue_work(di->charger_wq, 36708c0984e5SSebastian Reichel &di->detect_usb_type_work); 36718c0984e5SSebastian Reichel } 36728c0984e5SSebastian Reichel 36738c0984e5SSebastian Reichel /* Register interrupts */ 36748c0984e5SSebastian Reichel for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { 36758c0984e5SSebastian Reichel irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); 36768c0984e5SSebastian Reichel ret = request_threaded_irq(irq, NULL, ab8500_charger_irq[i].isr, 36778c0984e5SSebastian Reichel IRQF_SHARED | IRQF_NO_SUSPEND, 36788c0984e5SSebastian Reichel ab8500_charger_irq[i].name, di); 36798c0984e5SSebastian Reichel 36808c0984e5SSebastian Reichel if (ret != 0) { 36818c0984e5SSebastian Reichel dev_err(di->dev, "failed to request %s IRQ %d: %d\n" 36828c0984e5SSebastian Reichel , ab8500_charger_irq[i].name, irq, ret); 36838c0984e5SSebastian Reichel goto free_irq; 36848c0984e5SSebastian Reichel } 36858c0984e5SSebastian Reichel dev_dbg(di->dev, "Requested %s IRQ %d: %d\n", 36868c0984e5SSebastian Reichel ab8500_charger_irq[i].name, irq, ret); 36878c0984e5SSebastian Reichel } 36888c0984e5SSebastian Reichel 36898c0984e5SSebastian Reichel platform_set_drvdata(pdev, di); 36908c0984e5SSebastian Reichel 36918c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 36928c0984e5SSebastian Reichel 36938c0984e5SSebastian Reichel ch_stat = ab8500_charger_detect_chargers(di, false); 36948c0984e5SSebastian Reichel 36958c0984e5SSebastian Reichel if ((ch_stat & AC_PW_CONN) == AC_PW_CONN) { 36968c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 36978c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 36988c0984e5SSebastian Reichel &di->ac_charger_attached_work, 36998c0984e5SSebastian Reichel HZ); 37008c0984e5SSebastian Reichel } 37018c0984e5SSebastian Reichel if ((ch_stat & USB_PW_CONN) == USB_PW_CONN) { 37028c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 37038c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 37048c0984e5SSebastian Reichel &di->usb_charger_attached_work, 37058c0984e5SSebastian Reichel HZ); 37068c0984e5SSebastian Reichel } 37078c0984e5SSebastian Reichel 37088c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 37098c0984e5SSebastian Reichel 37108c0984e5SSebastian Reichel return ret; 37118c0984e5SSebastian Reichel 37128c0984e5SSebastian Reichel free_irq: 37138c0984e5SSebastian Reichel usb_unregister_notifier(di->usb_phy, &di->nb); 37148c0984e5SSebastian Reichel 37158c0984e5SSebastian Reichel /* We also have to free all successfully registered irqs */ 37168c0984e5SSebastian Reichel for (i = i - 1; i >= 0; i--) { 37178c0984e5SSebastian Reichel irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); 37188c0984e5SSebastian Reichel free_irq(irq, di); 37198c0984e5SSebastian Reichel } 37208c0984e5SSebastian Reichel put_usb_phy: 37218c0984e5SSebastian Reichel usb_put_phy(di->usb_phy); 37228c0984e5SSebastian Reichel free_usb: 37238c0984e5SSebastian Reichel if (di->usb_chg.enabled) 37248c0984e5SSebastian Reichel power_supply_unregister(di->usb_chg.psy); 37258c0984e5SSebastian Reichel free_ac: 37268c0984e5SSebastian Reichel if (di->ac_chg.enabled) 37278c0984e5SSebastian Reichel power_supply_unregister(di->ac_chg.psy); 37288c0984e5SSebastian Reichel free_charger_wq: 37298c0984e5SSebastian Reichel destroy_workqueue(di->charger_wq); 37308c0984e5SSebastian Reichel return ret; 37318c0984e5SSebastian Reichel } 37328c0984e5SSebastian Reichel 37338c0984e5SSebastian Reichel static const struct of_device_id ab8500_charger_match[] = { 37348c0984e5SSebastian Reichel { .compatible = "stericsson,ab8500-charger", }, 37358c0984e5SSebastian Reichel { }, 37368c0984e5SSebastian Reichel }; 37378c0984e5SSebastian Reichel 37388c0984e5SSebastian Reichel static struct platform_driver ab8500_charger_driver = { 37398c0984e5SSebastian Reichel .probe = ab8500_charger_probe, 37408c0984e5SSebastian Reichel .remove = ab8500_charger_remove, 37418c0984e5SSebastian Reichel .suspend = ab8500_charger_suspend, 37428c0984e5SSebastian Reichel .resume = ab8500_charger_resume, 37438c0984e5SSebastian Reichel .driver = { 37448c0984e5SSebastian Reichel .name = "ab8500-charger", 37458c0984e5SSebastian Reichel .of_match_table = ab8500_charger_match, 37468c0984e5SSebastian Reichel }, 37478c0984e5SSebastian Reichel }; 37488c0984e5SSebastian Reichel 37498c0984e5SSebastian Reichel static int __init ab8500_charger_init(void) 37508c0984e5SSebastian Reichel { 37518c0984e5SSebastian Reichel return platform_driver_register(&ab8500_charger_driver); 37528c0984e5SSebastian Reichel } 37538c0984e5SSebastian Reichel 37548c0984e5SSebastian Reichel static void __exit ab8500_charger_exit(void) 37558c0984e5SSebastian Reichel { 37568c0984e5SSebastian Reichel platform_driver_unregister(&ab8500_charger_driver); 37578c0984e5SSebastian Reichel } 37588c0984e5SSebastian Reichel 37598c0984e5SSebastian Reichel subsys_initcall_sync(ab8500_charger_init); 37608c0984e5SSebastian Reichel module_exit(ab8500_charger_exit); 37618c0984e5SSebastian Reichel 37628c0984e5SSebastian Reichel MODULE_LICENSE("GPL v2"); 37638c0984e5SSebastian Reichel MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy"); 37648c0984e5SSebastian Reichel MODULE_ALIAS("platform:ab8500-charger"); 37658c0984e5SSebastian Reichel MODULE_DESCRIPTION("AB8500 charger management driver"); 3766