10376148fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 28c0984e5SSebastian Reichel /* 38c0984e5SSebastian Reichel * Copyright (C) ST-Ericsson SA 2012 48c0984e5SSebastian Reichel * 58c0984e5SSebastian Reichel * Charger driver for AB8500 68c0984e5SSebastian Reichel * 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> 161c1f13a0SLinus Walleij #include <linux/component.h> 178c0984e5SSebastian Reichel #include <linux/interrupt.h> 188c0984e5SSebastian Reichel #include <linux/delay.h> 198c0984e5SSebastian Reichel #include <linux/notifier.h> 208c0984e5SSebastian Reichel #include <linux/slab.h> 218c0984e5SSebastian Reichel #include <linux/platform_device.h> 228c0984e5SSebastian Reichel #include <linux/power_supply.h> 238c0984e5SSebastian Reichel #include <linux/completion.h> 248c0984e5SSebastian Reichel #include <linux/regulator/consumer.h> 258c0984e5SSebastian Reichel #include <linux/err.h> 268c0984e5SSebastian Reichel #include <linux/workqueue.h> 278c0984e5SSebastian Reichel #include <linux/kobject.h> 288c0984e5SSebastian Reichel #include <linux/of.h> 298c0984e5SSebastian Reichel #include <linux/mfd/core.h> 308c0984e5SSebastian Reichel #include <linux/mfd/abx500/ab8500.h> 318c0984e5SSebastian Reichel #include <linux/mfd/abx500.h> 328c0984e5SSebastian Reichel #include <linux/usb/otg.h> 338c0984e5SSebastian Reichel #include <linux/mutex.h> 3497ab78baSLinus Walleij #include <linux/iio/consumer.h> 358c0984e5SSebastian Reichel 36417c0fc2SLinus Walleij #include "ab8500-bm.h" 37a65aa0ceSLinus Walleij #include "ab8500-chargalg.h" 38417c0fc2SLinus Walleij 398c0984e5SSebastian Reichel /* Charger constants */ 408c0984e5SSebastian Reichel #define NO_PW_CONN 0 418c0984e5SSebastian Reichel #define AC_PW_CONN 1 428c0984e5SSebastian Reichel #define USB_PW_CONN 2 438c0984e5SSebastian Reichel 448c0984e5SSebastian Reichel #define MAIN_WDOG_ENA 0x01 458c0984e5SSebastian Reichel #define MAIN_WDOG_KICK 0x02 468c0984e5SSebastian Reichel #define MAIN_WDOG_DIS 0x00 478c0984e5SSebastian Reichel #define CHARG_WD_KICK 0x01 488c0984e5SSebastian Reichel #define MAIN_CH_ENA 0x01 498c0984e5SSebastian Reichel #define MAIN_CH_NO_OVERSHOOT_ENA_N 0x02 508c0984e5SSebastian Reichel #define USB_CH_ENA 0x01 518c0984e5SSebastian Reichel #define USB_CHG_NO_OVERSHOOT_ENA_N 0x02 528c0984e5SSebastian Reichel #define MAIN_CH_DET 0x01 538c0984e5SSebastian Reichel #define MAIN_CH_CV_ON 0x04 548c0984e5SSebastian Reichel #define USB_CH_CV_ON 0x08 558c0984e5SSebastian Reichel #define VBUS_DET_DBNC100 0x02 568c0984e5SSebastian Reichel #define VBUS_DET_DBNC1 0x01 578c0984e5SSebastian Reichel #define OTP_ENABLE_WD 0x01 588c0984e5SSebastian Reichel #define DROP_COUNT_RESET 0x01 598c0984e5SSebastian Reichel #define USB_CH_DET 0x01 608c0984e5SSebastian Reichel 618c0984e5SSebastian Reichel #define MAIN_CH_INPUT_CURR_SHIFT 4 628c0984e5SSebastian Reichel #define VBUS_IN_CURR_LIM_SHIFT 4 638c0984e5SSebastian Reichel #define AUTO_VBUS_IN_CURR_LIM_SHIFT 4 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 14883e5aa77SLinus Walleij /* VBUS input current limits supported in AB8500 in uA */ 14983e5aa77SLinus Walleij #define USB_CH_IP_CUR_LVL_0P05 50000 15083e5aa77SLinus Walleij #define USB_CH_IP_CUR_LVL_0P09 98000 15183e5aa77SLinus Walleij #define USB_CH_IP_CUR_LVL_0P19 193000 15283e5aa77SLinus Walleij #define USB_CH_IP_CUR_LVL_0P29 290000 15383e5aa77SLinus Walleij #define USB_CH_IP_CUR_LVL_0P38 380000 15483e5aa77SLinus Walleij #define USB_CH_IP_CUR_LVL_0P45 450000 15583e5aa77SLinus Walleij #define USB_CH_IP_CUR_LVL_0P5 500000 15683e5aa77SLinus Walleij #define USB_CH_IP_CUR_LVL_0P6 600000 15783e5aa77SLinus Walleij #define USB_CH_IP_CUR_LVL_0P7 700000 15883e5aa77SLinus Walleij #define USB_CH_IP_CUR_LVL_0P8 800000 15983e5aa77SLinus Walleij #define USB_CH_IP_CUR_LVL_0P9 900000 16083e5aa77SLinus Walleij #define USB_CH_IP_CUR_LVL_1P0 1000000 16183e5aa77SLinus Walleij #define USB_CH_IP_CUR_LVL_1P1 1100000 16283e5aa77SLinus Walleij #define USB_CH_IP_CUR_LVL_1P3 1300000 16383e5aa77SLinus Walleij #define USB_CH_IP_CUR_LVL_1P4 1400000 16483e5aa77SLinus Walleij #define USB_CH_IP_CUR_LVL_1P5 1500000 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; 186bc6e0287SLinus Walleij int charger_voltage_uv; 1878c0984e5SSebastian Reichel int cv_active; 1888c0984e5SSebastian Reichel bool wd_expired; 18983e5aa77SLinus Walleij int charger_current_ua; 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 { 20483e5aa77SLinus Walleij int usb_current_ua; 20583e5aa77SLinus Walleij int usb_current_tmp_ua; 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 { 21283e5aa77SLinus Walleij int usb_type_max_ua; 21383e5aa77SLinus Walleij int set_max_ua; 21483e5aa77SLinus Walleij int calculated_max_ua; 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 23897ab78baSLinus Walleij * @adc_main_charger_v ADC channel for main charger voltage 23997ab78baSLinus Walleij * @adc_main_charger_c ADC channel for main charger current 24097ab78baSLinus Walleij * @adc_vbus_v ADC channel for USB charger voltage 24197ab78baSLinus Walleij * @adc_usb_charger_c ADC channel for USB charger current 2428c0984e5SSebastian Reichel * @bm: Platform specific battery management information 2438c0984e5SSebastian Reichel * @flags: Structure for information about events triggered 2448c0984e5SSebastian Reichel * @usb_state: Structure for usb stack information 2458c0984e5SSebastian Reichel * @max_usb_in_curr: Max USB charger input current 2468c0984e5SSebastian Reichel * @ac_chg: AC charger power supply 2478c0984e5SSebastian Reichel * @usb_chg: USB charger power supply 2488c0984e5SSebastian Reichel * @ac: Structure that holds the AC charger properties 2498c0984e5SSebastian Reichel * @usb: Structure that holds the USB charger properties 2508c0984e5SSebastian Reichel * @regu: Pointer to the struct regulator 2518c0984e5SSebastian Reichel * @charger_wq: Work queue for the IRQs and checking HW state 2528c0984e5SSebastian Reichel * @usb_ipt_crnt_lock: Lock to protect VBUS input current setting from mutuals 2538c0984e5SSebastian Reichel * @pm_lock: Lock to prevent system to suspend 2548c0984e5SSebastian Reichel * @check_vbat_work Work for checking vbat threshold to adjust vbus current 2558c0984e5SSebastian Reichel * @check_hw_failure_work: Work for checking HW state 2568c0984e5SSebastian Reichel * @check_usbchgnotok_work: Work for checking USB charger not ok status 2578c0984e5SSebastian Reichel * @kick_wd_work: Work for kicking the charger watchdog in case 2588c0984e5SSebastian Reichel * of ABB rev 1.* due to the watchog logic bug 2598c0984e5SSebastian Reichel * @ac_charger_attached_work: Work for checking if AC charger is still 2608c0984e5SSebastian Reichel * connected 2618c0984e5SSebastian Reichel * @usb_charger_attached_work: Work for checking if USB charger is still 2628c0984e5SSebastian Reichel * connected 2638c0984e5SSebastian Reichel * @ac_work: Work for checking AC charger connection 2648c0984e5SSebastian Reichel * @detect_usb_type_work: Work for detecting the USB type connected 2658c0984e5SSebastian Reichel * @usb_link_status_work: Work for checking the new USB link status 2668c0984e5SSebastian Reichel * @usb_state_changed_work: Work for checking USB state 2678c0984e5SSebastian Reichel * @attach_work: Work for detecting USB type 2688c0984e5SSebastian Reichel * @vbus_drop_end_work: Work for detecting VBUS drop end 2698c0984e5SSebastian Reichel * @check_main_thermal_prot_work: 2708c0984e5SSebastian Reichel * Work for checking Main thermal status 2718c0984e5SSebastian Reichel * @check_usb_thermal_prot_work: 2728c0984e5SSebastian Reichel * Work for checking USB thermal status 2738c0984e5SSebastian Reichel * @charger_attached_mutex: For controlling the wakelock 2748c0984e5SSebastian Reichel */ 2758c0984e5SSebastian Reichel struct ab8500_charger { 2768c0984e5SSebastian Reichel struct device *dev; 2778c0984e5SSebastian Reichel bool vbus_detected; 2788c0984e5SSebastian Reichel bool vbus_detected_start; 2798c0984e5SSebastian Reichel bool ac_conn; 2808c0984e5SSebastian Reichel bool vddadc_en_ac; 2818c0984e5SSebastian Reichel bool vddadc_en_usb; 2828c0984e5SSebastian Reichel int vbat; 2838c0984e5SSebastian Reichel int old_vbat; 2848c0984e5SSebastian Reichel bool usb_device_is_unrecognised; 2858c0984e5SSebastian Reichel bool autopower; 2868c0984e5SSebastian Reichel bool autopower_cfg; 2878c0984e5SSebastian Reichel int invalid_charger_detect_state; 2888c0984e5SSebastian Reichel int is_aca_rid; 2898c0984e5SSebastian Reichel atomic_t current_stepping_sessions; 2908c0984e5SSebastian Reichel struct ab8500 *parent; 29197ab78baSLinus Walleij struct iio_channel *adc_main_charger_v; 29297ab78baSLinus Walleij struct iio_channel *adc_main_charger_c; 29397ab78baSLinus Walleij struct iio_channel *adc_vbus_v; 29497ab78baSLinus Walleij struct iio_channel *adc_usb_charger_c; 295484a9cc3SLinus Walleij struct ab8500_bm_data *bm; 2968c0984e5SSebastian Reichel struct ab8500_charger_event_flags flags; 2978c0984e5SSebastian Reichel struct ab8500_charger_usb_state usb_state; 2988c0984e5SSebastian Reichel struct ab8500_charger_max_usb_in_curr max_usb_in_curr; 2998c0984e5SSebastian Reichel struct ux500_charger ac_chg; 3008c0984e5SSebastian Reichel struct ux500_charger usb_chg; 3018c0984e5SSebastian Reichel struct ab8500_charger_info ac; 3028c0984e5SSebastian Reichel struct ab8500_charger_info usb; 3038c0984e5SSebastian Reichel struct regulator *regu; 3048c0984e5SSebastian Reichel struct workqueue_struct *charger_wq; 3058c0984e5SSebastian Reichel struct mutex usb_ipt_crnt_lock; 3068c0984e5SSebastian Reichel struct delayed_work check_vbat_work; 3078c0984e5SSebastian Reichel struct delayed_work check_hw_failure_work; 3088c0984e5SSebastian Reichel struct delayed_work check_usbchgnotok_work; 3098c0984e5SSebastian Reichel struct delayed_work kick_wd_work; 3108c0984e5SSebastian Reichel struct delayed_work usb_state_changed_work; 3118c0984e5SSebastian Reichel struct delayed_work attach_work; 3128c0984e5SSebastian Reichel struct delayed_work ac_charger_attached_work; 3138c0984e5SSebastian Reichel struct delayed_work usb_charger_attached_work; 3148c0984e5SSebastian Reichel struct delayed_work vbus_drop_end_work; 3158c0984e5SSebastian Reichel struct work_struct ac_work; 3168c0984e5SSebastian Reichel struct work_struct detect_usb_type_work; 3178c0984e5SSebastian Reichel struct work_struct usb_link_status_work; 3188c0984e5SSebastian Reichel struct work_struct check_main_thermal_prot_work; 3198c0984e5SSebastian Reichel struct work_struct check_usb_thermal_prot_work; 3208c0984e5SSebastian Reichel struct usb_phy *usb_phy; 3218c0984e5SSebastian Reichel struct notifier_block nb; 3228c0984e5SSebastian Reichel struct mutex charger_attached_mutex; 3238c0984e5SSebastian Reichel }; 3248c0984e5SSebastian Reichel 3258c0984e5SSebastian Reichel /* AC properties */ 3268c0984e5SSebastian Reichel static enum power_supply_property ab8500_charger_ac_props[] = { 3278c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 3288c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 3298c0984e5SSebastian Reichel POWER_SUPPLY_PROP_ONLINE, 3308c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 3318c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_AVG, 3328c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 3338c0984e5SSebastian Reichel }; 3348c0984e5SSebastian Reichel 3358c0984e5SSebastian Reichel /* USB properties */ 3368c0984e5SSebastian Reichel static enum power_supply_property ab8500_charger_usb_props[] = { 3378c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 3388c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_AVG, 3398c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 3408c0984e5SSebastian Reichel POWER_SUPPLY_PROP_ONLINE, 3418c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 3428c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_AVG, 3438c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 3448c0984e5SSebastian Reichel }; 3458c0984e5SSebastian Reichel 3468c0984e5SSebastian Reichel /* 3478c0984e5SSebastian Reichel * Function for enabling and disabling sw fallback mode 3488c0984e5SSebastian Reichel * should always be disabled when no charger is connected. 3498c0984e5SSebastian Reichel */ 3508c0984e5SSebastian Reichel static void ab8500_enable_disable_sw_fallback(struct ab8500_charger *di, 3518c0984e5SSebastian Reichel bool fallback) 3528c0984e5SSebastian Reichel { 3538c0984e5SSebastian Reichel u8 val; 3548c0984e5SSebastian Reichel u8 reg; 3558c0984e5SSebastian Reichel u8 bank; 3568c0984e5SSebastian Reichel u8 bit; 3578c0984e5SSebastian Reichel int ret; 3588c0984e5SSebastian Reichel 3598c0984e5SSebastian Reichel dev_dbg(di->dev, "SW Fallback: %d\n", fallback); 3608c0984e5SSebastian Reichel 3618c0984e5SSebastian Reichel if (is_ab8500(di->parent)) { 3628c0984e5SSebastian Reichel bank = 0x15; 3638c0984e5SSebastian Reichel reg = 0x0; 3648c0984e5SSebastian Reichel bit = 3; 3658c0984e5SSebastian Reichel } else { 3668c0984e5SSebastian Reichel bank = AB8500_SYS_CTRL1_BLOCK; 3678c0984e5SSebastian Reichel reg = AB8500_SW_CONTROL_FALLBACK; 3688c0984e5SSebastian Reichel bit = 0; 3698c0984e5SSebastian Reichel } 3708c0984e5SSebastian Reichel 3718c0984e5SSebastian Reichel /* read the register containing fallback bit */ 3728c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, bank, reg, &val); 3738c0984e5SSebastian Reichel if (ret < 0) { 3748c0984e5SSebastian Reichel dev_err(di->dev, "%d read failed\n", __LINE__); 3758c0984e5SSebastian Reichel return; 3768c0984e5SSebastian Reichel } 3778c0984e5SSebastian Reichel 3788c0984e5SSebastian Reichel if (is_ab8500(di->parent)) { 3798c0984e5SSebastian Reichel /* enable the OPT emulation registers */ 3808c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x2); 3818c0984e5SSebastian Reichel if (ret) { 3828c0984e5SSebastian Reichel dev_err(di->dev, "%d write failed\n", __LINE__); 3838c0984e5SSebastian Reichel goto disable_otp; 3848c0984e5SSebastian Reichel } 3858c0984e5SSebastian Reichel } 3868c0984e5SSebastian Reichel 3878c0984e5SSebastian Reichel if (fallback) 3888c0984e5SSebastian Reichel val |= (1 << bit); 3898c0984e5SSebastian Reichel else 3908c0984e5SSebastian Reichel val &= ~(1 << bit); 3918c0984e5SSebastian Reichel 3928c0984e5SSebastian Reichel /* write back the changed fallback bit value to register */ 3938c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, bank, reg, val); 3948c0984e5SSebastian Reichel if (ret) { 3958c0984e5SSebastian Reichel dev_err(di->dev, "%d write failed\n", __LINE__); 3968c0984e5SSebastian Reichel } 3978c0984e5SSebastian Reichel 3988c0984e5SSebastian Reichel disable_otp: 3998c0984e5SSebastian Reichel if (is_ab8500(di->parent)) { 4008c0984e5SSebastian Reichel /* disable the set OTP registers again */ 4018c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x0); 4028c0984e5SSebastian Reichel if (ret) { 4038c0984e5SSebastian Reichel dev_err(di->dev, "%d write failed\n", __LINE__); 4048c0984e5SSebastian Reichel } 4058c0984e5SSebastian Reichel } 4068c0984e5SSebastian Reichel } 4078c0984e5SSebastian Reichel 4088c0984e5SSebastian Reichel /** 409ddb74e98SAshish Chavan * ab8500_power_supply_changed - a wrapper with local extensions for 4108c0984e5SSebastian Reichel * power_supply_changed 4118c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 4128c0984e5SSebastian Reichel * @psy: pointer to power_supply_that have changed. 4138c0984e5SSebastian Reichel * 4148c0984e5SSebastian Reichel */ 4158c0984e5SSebastian Reichel static void ab8500_power_supply_changed(struct ab8500_charger *di, 4168c0984e5SSebastian Reichel struct power_supply *psy) 4178c0984e5SSebastian Reichel { 4185bcb5087SLinus Walleij /* 4195bcb5087SLinus Walleij * This happens if we get notifications or interrupts and 4205bcb5087SLinus Walleij * the platform has been configured not to support one or 4215bcb5087SLinus Walleij * other type of charging. 4225bcb5087SLinus Walleij */ 4235bcb5087SLinus Walleij if (!psy) 4245bcb5087SLinus Walleij return; 4255bcb5087SLinus Walleij 4268c0984e5SSebastian Reichel if (di->autopower_cfg) { 4278c0984e5SSebastian Reichel if (!di->usb.charger_connected && 4288c0984e5SSebastian Reichel !di->ac.charger_connected && 4298c0984e5SSebastian Reichel di->autopower) { 4308c0984e5SSebastian Reichel di->autopower = false; 4318c0984e5SSebastian Reichel ab8500_enable_disable_sw_fallback(di, false); 4328c0984e5SSebastian Reichel } else if (!di->autopower && 4338c0984e5SSebastian Reichel (di->ac.charger_connected || 4348c0984e5SSebastian Reichel di->usb.charger_connected)) { 4358c0984e5SSebastian Reichel di->autopower = true; 4368c0984e5SSebastian Reichel ab8500_enable_disable_sw_fallback(di, true); 4378c0984e5SSebastian Reichel } 4388c0984e5SSebastian Reichel } 4398c0984e5SSebastian Reichel power_supply_changed(psy); 4408c0984e5SSebastian Reichel } 4418c0984e5SSebastian Reichel 4428c0984e5SSebastian Reichel static void ab8500_charger_set_usb_connected(struct ab8500_charger *di, 4438c0984e5SSebastian Reichel bool connected) 4448c0984e5SSebastian Reichel { 4458c0984e5SSebastian Reichel if (connected != di->usb.charger_connected) { 4468c0984e5SSebastian Reichel dev_dbg(di->dev, "USB connected:%i\n", connected); 4478c0984e5SSebastian Reichel di->usb.charger_connected = connected; 4488c0984e5SSebastian Reichel 4498c0984e5SSebastian Reichel if (!connected) 4508c0984e5SSebastian Reichel di->flags.vbus_drop_end = false; 4518c0984e5SSebastian Reichel 4525bcb5087SLinus Walleij /* 4535bcb5087SLinus Walleij * Sometimes the platform is configured not to support 4545bcb5087SLinus Walleij * USB charging and no psy has been created, but we still 4555bcb5087SLinus Walleij * will get these notifications. 4565bcb5087SLinus Walleij */ 4575bcb5087SLinus Walleij if (di->usb_chg.psy) { 4585bcb5087SLinus Walleij sysfs_notify(&di->usb_chg.psy->dev.kobj, NULL, 4595bcb5087SLinus Walleij "present"); 4605bcb5087SLinus Walleij } 4618c0984e5SSebastian Reichel 4628c0984e5SSebastian Reichel if (connected) { 4638c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 4648c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 4658c0984e5SSebastian Reichel 4668c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 4678c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 4688c0984e5SSebastian Reichel &di->usb_charger_attached_work, 4698c0984e5SSebastian Reichel HZ); 4708c0984e5SSebastian Reichel } else { 4718c0984e5SSebastian Reichel cancel_delayed_work_sync(&di->usb_charger_attached_work); 4728c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 4738c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 4748c0984e5SSebastian Reichel } 4758c0984e5SSebastian Reichel } 4768c0984e5SSebastian Reichel } 4778c0984e5SSebastian Reichel 4788c0984e5SSebastian Reichel /** 4798c0984e5SSebastian Reichel * ab8500_charger_get_ac_voltage() - get ac charger voltage 4808c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 4818c0984e5SSebastian Reichel * 482bc6e0287SLinus Walleij * Returns ac charger voltage in microvolt (on success) 4838c0984e5SSebastian Reichel */ 4848c0984e5SSebastian Reichel static int ab8500_charger_get_ac_voltage(struct ab8500_charger *di) 4858c0984e5SSebastian Reichel { 48697ab78baSLinus Walleij int vch, ret; 4878c0984e5SSebastian Reichel 4888c0984e5SSebastian Reichel /* Only measure voltage if the charger is connected */ 4898c0984e5SSebastian Reichel if (di->ac.charger_connected) { 49097ab78baSLinus Walleij ret = iio_read_channel_processed(di->adc_main_charger_v, &vch); 49197ab78baSLinus Walleij if (ret < 0) 49297ab78baSLinus Walleij dev_err(di->dev, "%s ADC conv failed,\n", __func__); 4938c0984e5SSebastian Reichel } else { 4948c0984e5SSebastian Reichel vch = 0; 4958c0984e5SSebastian Reichel } 496bc6e0287SLinus Walleij /* Convert to microvolt, IIO returns millivolt */ 497bc6e0287SLinus Walleij return vch * 1000; 4988c0984e5SSebastian Reichel } 4998c0984e5SSebastian Reichel 5008c0984e5SSebastian Reichel /** 5018c0984e5SSebastian Reichel * ab8500_charger_ac_cv() - check if the main charger is in CV mode 5028c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 5038c0984e5SSebastian Reichel * 5048c0984e5SSebastian Reichel * Returns ac charger CV mode (on success) else error code 5058c0984e5SSebastian Reichel */ 5068c0984e5SSebastian Reichel static int ab8500_charger_ac_cv(struct ab8500_charger *di) 5078c0984e5SSebastian Reichel { 5088c0984e5SSebastian Reichel u8 val; 5098c0984e5SSebastian Reichel int ret = 0; 5108c0984e5SSebastian Reichel 5118c0984e5SSebastian Reichel /* Only check CV mode if the charger is online */ 5128c0984e5SSebastian Reichel if (di->ac.charger_online) { 5138c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 5148c0984e5SSebastian Reichel AB8500_CH_STATUS1_REG, &val); 5158c0984e5SSebastian Reichel if (ret < 0) { 5168c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 5178c0984e5SSebastian Reichel return 0; 5188c0984e5SSebastian Reichel } 5198c0984e5SSebastian Reichel 5208c0984e5SSebastian Reichel if (val & MAIN_CH_CV_ON) 5218c0984e5SSebastian Reichel ret = 1; 5228c0984e5SSebastian Reichel else 5238c0984e5SSebastian Reichel ret = 0; 5248c0984e5SSebastian Reichel } 5258c0984e5SSebastian Reichel 5268c0984e5SSebastian Reichel return ret; 5278c0984e5SSebastian Reichel } 5288c0984e5SSebastian Reichel 5298c0984e5SSebastian Reichel /** 5308c0984e5SSebastian Reichel * ab8500_charger_get_vbus_voltage() - get vbus voltage 5318c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 5328c0984e5SSebastian Reichel * 5338c0984e5SSebastian Reichel * This function returns the vbus voltage. 534bc6e0287SLinus Walleij * Returns vbus voltage in microvolt (on success) 5358c0984e5SSebastian Reichel */ 5368c0984e5SSebastian Reichel static int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di) 5378c0984e5SSebastian Reichel { 53897ab78baSLinus Walleij int vch, ret; 5398c0984e5SSebastian Reichel 5408c0984e5SSebastian Reichel /* Only measure voltage if the charger is connected */ 5418c0984e5SSebastian Reichel if (di->usb.charger_connected) { 54297ab78baSLinus Walleij ret = iio_read_channel_processed(di->adc_vbus_v, &vch); 54397ab78baSLinus Walleij if (ret < 0) 54497ab78baSLinus Walleij dev_err(di->dev, "%s ADC conv failed,\n", __func__); 5458c0984e5SSebastian Reichel } else { 5468c0984e5SSebastian Reichel vch = 0; 5478c0984e5SSebastian Reichel } 548bc6e0287SLinus Walleij /* Convert to microvolt, IIO returns millivolt */ 549bc6e0287SLinus Walleij return vch * 1000; 5508c0984e5SSebastian Reichel } 5518c0984e5SSebastian Reichel 5528c0984e5SSebastian Reichel /** 5538c0984e5SSebastian Reichel * ab8500_charger_get_usb_current() - get usb charger current 5548c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 5558c0984e5SSebastian Reichel * 5568c0984e5SSebastian Reichel * This function returns the usb charger current. 55783e5aa77SLinus Walleij * Returns usb current in microamperes (on success) and error code on failure 5588c0984e5SSebastian Reichel */ 5598c0984e5SSebastian Reichel static int ab8500_charger_get_usb_current(struct ab8500_charger *di) 5608c0984e5SSebastian Reichel { 56197ab78baSLinus Walleij int ich, ret; 5628c0984e5SSebastian Reichel 5638c0984e5SSebastian Reichel /* Only measure current if the charger is online */ 5648c0984e5SSebastian Reichel if (di->usb.charger_online) { 56597ab78baSLinus Walleij ret = iio_read_channel_processed(di->adc_usb_charger_c, &ich); 56697ab78baSLinus Walleij if (ret < 0) 56797ab78baSLinus Walleij dev_err(di->dev, "%s ADC conv failed,\n", __func__); 5688c0984e5SSebastian Reichel } else { 5698c0984e5SSebastian Reichel ich = 0; 5708c0984e5SSebastian Reichel } 57183e5aa77SLinus Walleij /* Return microamperes */ 57283e5aa77SLinus Walleij return ich * 1000; 5738c0984e5SSebastian Reichel } 5748c0984e5SSebastian Reichel 5758c0984e5SSebastian Reichel /** 5768c0984e5SSebastian Reichel * ab8500_charger_get_ac_current() - get ac charger current 5778c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 5788c0984e5SSebastian Reichel * 5798c0984e5SSebastian Reichel * This function returns the ac charger current. 58083e5aa77SLinus Walleij * Returns ac current in microamperes (on success) and error code on failure. 5818c0984e5SSebastian Reichel */ 5828c0984e5SSebastian Reichel static int ab8500_charger_get_ac_current(struct ab8500_charger *di) 5838c0984e5SSebastian Reichel { 58497ab78baSLinus Walleij int ich, ret; 5858c0984e5SSebastian Reichel 5868c0984e5SSebastian Reichel /* Only measure current if the charger is online */ 5878c0984e5SSebastian Reichel if (di->ac.charger_online) { 58897ab78baSLinus Walleij ret = iio_read_channel_processed(di->adc_main_charger_c, &ich); 58997ab78baSLinus Walleij if (ret < 0) 59097ab78baSLinus Walleij dev_err(di->dev, "%s ADC conv failed,\n", __func__); 5918c0984e5SSebastian Reichel } else { 5928c0984e5SSebastian Reichel ich = 0; 5938c0984e5SSebastian Reichel } 59483e5aa77SLinus Walleij /* Return microamperes */ 59583e5aa77SLinus Walleij return ich * 1000; 5968c0984e5SSebastian Reichel } 5978c0984e5SSebastian Reichel 5988c0984e5SSebastian Reichel /** 5998c0984e5SSebastian Reichel * ab8500_charger_usb_cv() - check if the usb charger is in CV mode 6008c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 6018c0984e5SSebastian Reichel * 6028c0984e5SSebastian Reichel * Returns ac charger CV mode (on success) else error code 6038c0984e5SSebastian Reichel */ 6048c0984e5SSebastian Reichel static int ab8500_charger_usb_cv(struct ab8500_charger *di) 6058c0984e5SSebastian Reichel { 6068c0984e5SSebastian Reichel int ret; 6078c0984e5SSebastian Reichel u8 val; 6088c0984e5SSebastian Reichel 6098c0984e5SSebastian Reichel /* Only check CV mode if the charger is online */ 6108c0984e5SSebastian Reichel if (di->usb.charger_online) { 6118c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 6128c0984e5SSebastian Reichel AB8500_CH_USBCH_STAT1_REG, &val); 6138c0984e5SSebastian Reichel if (ret < 0) { 6148c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 6158c0984e5SSebastian Reichel return 0; 6168c0984e5SSebastian Reichel } 6178c0984e5SSebastian Reichel 6188c0984e5SSebastian Reichel if (val & USB_CH_CV_ON) 6198c0984e5SSebastian Reichel ret = 1; 6208c0984e5SSebastian Reichel else 6218c0984e5SSebastian Reichel ret = 0; 6228c0984e5SSebastian Reichel } else { 6238c0984e5SSebastian Reichel ret = 0; 6248c0984e5SSebastian Reichel } 6258c0984e5SSebastian Reichel 6268c0984e5SSebastian Reichel return ret; 6278c0984e5SSebastian Reichel } 6288c0984e5SSebastian Reichel 6298c0984e5SSebastian Reichel /** 6308c0984e5SSebastian Reichel * ab8500_charger_detect_chargers() - Detect the connected chargers 6318c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 6328c0984e5SSebastian Reichel * @probe: if probe, don't delay and wait for HW 6338c0984e5SSebastian Reichel * 6348c0984e5SSebastian Reichel * Returns the type of charger connected. 6358c0984e5SSebastian Reichel * For USB it will not mean we can actually charge from it 6368c0984e5SSebastian Reichel * but that there is a USB cable connected that we have to 6378c0984e5SSebastian Reichel * identify. This is used during startup when we don't get 6388c0984e5SSebastian Reichel * interrupts of the charger detection 6398c0984e5SSebastian Reichel * 6408c0984e5SSebastian Reichel * Returns an integer value, that means, 6418c0984e5SSebastian Reichel * NO_PW_CONN no power supply is connected 6428c0984e5SSebastian Reichel * AC_PW_CONN if the AC power supply is connected 6438c0984e5SSebastian Reichel * USB_PW_CONN if the USB power supply is connected 6448c0984e5SSebastian Reichel * AC_PW_CONN + USB_PW_CONN if USB and AC power supplies are both connected 6458c0984e5SSebastian Reichel */ 6468c0984e5SSebastian Reichel static int ab8500_charger_detect_chargers(struct ab8500_charger *di, bool probe) 6478c0984e5SSebastian Reichel { 6488c0984e5SSebastian Reichel int result = NO_PW_CONN; 6498c0984e5SSebastian Reichel int ret; 6508c0984e5SSebastian Reichel u8 val; 6518c0984e5SSebastian Reichel 6528c0984e5SSebastian Reichel /* Check for AC charger */ 6538c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 6548c0984e5SSebastian Reichel AB8500_CH_STATUS1_REG, &val); 6558c0984e5SSebastian Reichel if (ret < 0) { 6568c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 6578c0984e5SSebastian Reichel return ret; 6588c0984e5SSebastian Reichel } 6598c0984e5SSebastian Reichel 6608c0984e5SSebastian Reichel if (val & MAIN_CH_DET) 6618c0984e5SSebastian Reichel result = AC_PW_CONN; 6628c0984e5SSebastian Reichel 6638c0984e5SSebastian Reichel /* Check for USB charger */ 6648c0984e5SSebastian Reichel 6658c0984e5SSebastian Reichel if (!probe) { 6668c0984e5SSebastian Reichel /* 6678c0984e5SSebastian Reichel * AB8500 says VBUS_DET_DBNC1 & VBUS_DET_DBNC100 6688c0984e5SSebastian Reichel * when disconnecting ACA even though no 6698c0984e5SSebastian Reichel * charger was connected. Try waiting a little 6708c0984e5SSebastian Reichel * longer than the 100 ms of VBUS_DET_DBNC100... 6718c0984e5SSebastian Reichel */ 6728c0984e5SSebastian Reichel msleep(110); 6738c0984e5SSebastian Reichel } 6748c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 6758c0984e5SSebastian Reichel AB8500_CH_USBCH_STAT1_REG, &val); 6768c0984e5SSebastian Reichel if (ret < 0) { 6778c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 6788c0984e5SSebastian Reichel return ret; 6798c0984e5SSebastian Reichel } 6808c0984e5SSebastian Reichel dev_dbg(di->dev, 6818c0984e5SSebastian Reichel "%s AB8500_CH_USBCH_STAT1_REG %x\n", __func__, 6828c0984e5SSebastian Reichel val); 6838c0984e5SSebastian Reichel if ((val & VBUS_DET_DBNC1) && (val & VBUS_DET_DBNC100)) 6848c0984e5SSebastian Reichel result |= USB_PW_CONN; 6858c0984e5SSebastian Reichel 6868c0984e5SSebastian Reichel return result; 6878c0984e5SSebastian Reichel } 6888c0984e5SSebastian Reichel 6898c0984e5SSebastian Reichel /** 6908c0984e5SSebastian Reichel * ab8500_charger_max_usb_curr() - get the max curr for the USB type 6918c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 6928c0984e5SSebastian Reichel * @link_status: the identified USB type 6938c0984e5SSebastian Reichel * 6948c0984e5SSebastian Reichel * Get the maximum current that is allowed to be drawn from the host 6958c0984e5SSebastian Reichel * based on the USB type. 6968c0984e5SSebastian Reichel * Returns error code in case of failure else 0 on success 6978c0984e5SSebastian Reichel */ 6988c0984e5SSebastian Reichel static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, 6998c0984e5SSebastian Reichel enum ab8500_charger_link_status link_status) 7008c0984e5SSebastian Reichel { 7018c0984e5SSebastian Reichel int ret = 0; 7028c0984e5SSebastian Reichel 7038c0984e5SSebastian Reichel di->usb_device_is_unrecognised = false; 7048c0984e5SSebastian Reichel 7058c0984e5SSebastian Reichel /* 7068c0984e5SSebastian Reichel * Platform only supports USB 2.0. 7078c0984e5SSebastian Reichel * This means that charging current from USB source 708ddb74e98SAshish Chavan * is maximum 500 mA. Every occurrence of USB_STAT_*_HOST_* 7098c0984e5SSebastian Reichel * should set USB_CH_IP_CUR_LVL_0P5. 7108c0984e5SSebastian Reichel */ 7118c0984e5SSebastian Reichel 7128c0984e5SSebastian Reichel switch (link_status) { 7138c0984e5SSebastian Reichel case USB_STAT_STD_HOST_NC: 7148c0984e5SSebastian Reichel case USB_STAT_STD_HOST_C_NS: 7158c0984e5SSebastian Reichel case USB_STAT_STD_HOST_C_S: 7168c0984e5SSebastian Reichel dev_dbg(di->dev, "USB Type - Standard host is " 7178c0984e5SSebastian Reichel "detected through USB driver\n"); 71883e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; 7198c0984e5SSebastian Reichel di->is_aca_rid = 0; 7208c0984e5SSebastian Reichel break; 7218c0984e5SSebastian Reichel case USB_STAT_HOST_CHG_HS_CHIRP: 72283e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; 7238c0984e5SSebastian Reichel di->is_aca_rid = 0; 7248c0984e5SSebastian Reichel break; 7258c0984e5SSebastian Reichel case USB_STAT_HOST_CHG_HS: 72683e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; 7278c0984e5SSebastian Reichel di->is_aca_rid = 0; 7288c0984e5SSebastian Reichel break; 7298c0984e5SSebastian Reichel case USB_STAT_ACA_RID_C_HS: 73083e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P9; 7318c0984e5SSebastian Reichel di->is_aca_rid = 0; 7328c0984e5SSebastian Reichel break; 7338c0984e5SSebastian Reichel case USB_STAT_ACA_RID_A: 7348c0984e5SSebastian Reichel /* 7358c0984e5SSebastian Reichel * Dedicated charger level minus maximum current accessory 7368c0984e5SSebastian Reichel * can consume (900mA). Closest level is 500mA 7378c0984e5SSebastian Reichel */ 7388c0984e5SSebastian Reichel dev_dbg(di->dev, "USB_STAT_ACA_RID_A detected\n"); 73983e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; 7408c0984e5SSebastian Reichel di->is_aca_rid = 1; 7418c0984e5SSebastian Reichel break; 7428c0984e5SSebastian Reichel case USB_STAT_ACA_RID_B: 7438c0984e5SSebastian Reichel /* 7448c0984e5SSebastian Reichel * Dedicated charger level minus 120mA (20mA for ACA and 7458c0984e5SSebastian Reichel * 100mA for potential accessory). Closest level is 1300mA 7468c0984e5SSebastian Reichel */ 74783e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_1P3; 7488c0984e5SSebastian Reichel dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status, 74983e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua); 7508c0984e5SSebastian Reichel di->is_aca_rid = 1; 7518c0984e5SSebastian Reichel break; 7528c0984e5SSebastian Reichel case USB_STAT_HOST_CHG_NM: 75383e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; 7548c0984e5SSebastian Reichel di->is_aca_rid = 0; 7558c0984e5SSebastian Reichel break; 7568c0984e5SSebastian Reichel case USB_STAT_DEDICATED_CHG: 75783e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_1P5; 7588c0984e5SSebastian Reichel di->is_aca_rid = 0; 7598c0984e5SSebastian Reichel break; 7608c0984e5SSebastian Reichel case USB_STAT_ACA_RID_C_HS_CHIRP: 7618c0984e5SSebastian Reichel case USB_STAT_ACA_RID_C_NM: 76283e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_1P5; 7638c0984e5SSebastian Reichel di->is_aca_rid = 1; 7648c0984e5SSebastian Reichel break; 7658c0984e5SSebastian Reichel case USB_STAT_NOT_CONFIGURED: 7668c0984e5SSebastian Reichel if (di->vbus_detected) { 7678c0984e5SSebastian Reichel di->usb_device_is_unrecognised = true; 7688c0984e5SSebastian Reichel dev_dbg(di->dev, "USB Type - Legacy charger.\n"); 76983e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = 7708c0984e5SSebastian Reichel USB_CH_IP_CUR_LVL_1P5; 7718c0984e5SSebastian Reichel break; 7728c0984e5SSebastian Reichel } 773df561f66SGustavo A. R. Silva fallthrough; 7748c0984e5SSebastian Reichel case USB_STAT_HM_IDGND: 7758c0984e5SSebastian Reichel dev_err(di->dev, "USB Type - Charging not allowed\n"); 77683e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P05; 7778c0984e5SSebastian Reichel ret = -ENXIO; 7788c0984e5SSebastian Reichel break; 7798c0984e5SSebastian Reichel case USB_STAT_RESERVED: 7808c0984e5SSebastian Reichel if (is_ab8500(di->parent)) { 7818c0984e5SSebastian Reichel di->flags.vbus_collapse = true; 7828c0984e5SSebastian Reichel dev_err(di->dev, "USB Type - USB_STAT_RESERVED " 7838c0984e5SSebastian Reichel "VBUS has collapsed\n"); 7848c0984e5SSebastian Reichel ret = -ENXIO; 7858c0984e5SSebastian Reichel break; 7868c0984e5SSebastian Reichel } else { 7878c0984e5SSebastian Reichel dev_dbg(di->dev, "USB Type - Charging not allowed\n"); 78883e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = 7898c0984e5SSebastian Reichel USB_CH_IP_CUR_LVL_0P05; 7908c0984e5SSebastian Reichel dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", 7918c0984e5SSebastian Reichel link_status, 79283e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua); 7938c0984e5SSebastian Reichel ret = -ENXIO; 7948c0984e5SSebastian Reichel break; 7958c0984e5SSebastian Reichel } 7968c0984e5SSebastian Reichel case USB_STAT_CARKIT_1: 7978c0984e5SSebastian Reichel case USB_STAT_CARKIT_2: 7988c0984e5SSebastian Reichel case USB_STAT_ACA_DOCK_CHARGER: 7998c0984e5SSebastian Reichel case USB_STAT_CHARGER_LINE_1: 80083e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; 8018c0984e5SSebastian Reichel dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status, 80283e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua); 8038c0984e5SSebastian Reichel break; 8048c0984e5SSebastian Reichel case USB_STAT_NOT_VALID_LINK: 8058c0984e5SSebastian Reichel dev_err(di->dev, "USB Type invalid - try charging anyway\n"); 80683e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; 8078c0984e5SSebastian Reichel break; 8088c0984e5SSebastian Reichel 8098c0984e5SSebastian Reichel default: 8108c0984e5SSebastian Reichel dev_err(di->dev, "USB Type - Unknown\n"); 81183e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P05; 8128c0984e5SSebastian Reichel ret = -ENXIO; 8138c0984e5SSebastian Reichel break; 814e15c54d2SMa Feng } 8158c0984e5SSebastian Reichel 81683e5aa77SLinus Walleij di->max_usb_in_curr.set_max_ua = di->max_usb_in_curr.usb_type_max_ua; 8178c0984e5SSebastian Reichel dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", 81883e5aa77SLinus Walleij link_status, di->max_usb_in_curr.set_max_ua); 8198c0984e5SSebastian Reichel 8208c0984e5SSebastian Reichel return ret; 8218c0984e5SSebastian Reichel } 8228c0984e5SSebastian Reichel 8238c0984e5SSebastian Reichel /** 8248c0984e5SSebastian Reichel * ab8500_charger_read_usb_type() - read the type of usb connected 8258c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 8268c0984e5SSebastian Reichel * 8278c0984e5SSebastian Reichel * Detect the type of the plugged USB 8288c0984e5SSebastian Reichel * Returns error code in case of failure else 0 on success 8298c0984e5SSebastian Reichel */ 8308c0984e5SSebastian Reichel static int ab8500_charger_read_usb_type(struct ab8500_charger *di) 8318c0984e5SSebastian Reichel { 8328c0984e5SSebastian Reichel int ret; 8338c0984e5SSebastian Reichel u8 val; 8348c0984e5SSebastian Reichel 8358c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 8368c0984e5SSebastian Reichel AB8500_INTERRUPT, AB8500_IT_SOURCE21_REG, &val); 8378c0984e5SSebastian Reichel if (ret < 0) { 8388c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 8398c0984e5SSebastian Reichel return ret; 8408c0984e5SSebastian Reichel } 8418c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 8428c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_USB, 8438c0984e5SSebastian Reichel AB8500_USB_LINE_STAT_REG, &val); 8448c0984e5SSebastian Reichel else 8458c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 8468c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val); 8478c0984e5SSebastian Reichel if (ret < 0) { 8488c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 8498c0984e5SSebastian Reichel return ret; 8508c0984e5SSebastian Reichel } 8518c0984e5SSebastian Reichel 8528c0984e5SSebastian Reichel /* get the USB type */ 8538c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 8548c0984e5SSebastian Reichel val = (val & AB8500_USB_LINK_STATUS) >> USB_LINK_STATUS_SHIFT; 8558c0984e5SSebastian Reichel else 8568c0984e5SSebastian Reichel val = (val & AB8505_USB_LINK_STATUS) >> USB_LINK_STATUS_SHIFT; 8578c0984e5SSebastian Reichel ret = ab8500_charger_max_usb_curr(di, 8588c0984e5SSebastian Reichel (enum ab8500_charger_link_status) val); 8598c0984e5SSebastian Reichel 8608c0984e5SSebastian Reichel return ret; 8618c0984e5SSebastian Reichel } 8628c0984e5SSebastian Reichel 8638c0984e5SSebastian Reichel /** 8648c0984e5SSebastian Reichel * ab8500_charger_detect_usb_type() - get the type of usb connected 8658c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 8668c0984e5SSebastian Reichel * 8678c0984e5SSebastian Reichel * Detect the type of the plugged USB 8688c0984e5SSebastian Reichel * Returns error code in case of failure else 0 on success 8698c0984e5SSebastian Reichel */ 8708c0984e5SSebastian Reichel static int ab8500_charger_detect_usb_type(struct ab8500_charger *di) 8718c0984e5SSebastian Reichel { 8728c0984e5SSebastian Reichel int i, ret; 8738c0984e5SSebastian Reichel u8 val; 8748c0984e5SSebastian Reichel 8758c0984e5SSebastian Reichel /* 8768c0984e5SSebastian Reichel * On getting the VBUS rising edge detect interrupt there 8778c0984e5SSebastian Reichel * is a 250ms delay after which the register UsbLineStatus 8788c0984e5SSebastian Reichel * is filled with valid data. 8798c0984e5SSebastian Reichel */ 8808c0984e5SSebastian Reichel for (i = 0; i < 10; i++) { 8818c0984e5SSebastian Reichel msleep(250); 8828c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 8838c0984e5SSebastian Reichel AB8500_INTERRUPT, AB8500_IT_SOURCE21_REG, 8848c0984e5SSebastian Reichel &val); 8858c0984e5SSebastian Reichel dev_dbg(di->dev, "%s AB8500_IT_SOURCE21_REG %x\n", 8868c0984e5SSebastian Reichel __func__, val); 8878c0984e5SSebastian Reichel if (ret < 0) { 8888c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 8898c0984e5SSebastian Reichel return ret; 8908c0984e5SSebastian Reichel } 8918c0984e5SSebastian Reichel 8928c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 8938c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 8948c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINE_STAT_REG, &val); 8958c0984e5SSebastian Reichel else 8968c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 8978c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val); 8988c0984e5SSebastian Reichel if (ret < 0) { 8998c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 9008c0984e5SSebastian Reichel return ret; 9018c0984e5SSebastian Reichel } 9028c0984e5SSebastian Reichel dev_dbg(di->dev, "%s AB8500_USB_LINE_STAT_REG %x\n", __func__, 9038c0984e5SSebastian Reichel val); 9048c0984e5SSebastian Reichel /* 9058c0984e5SSebastian Reichel * Until the IT source register is read the UsbLineStatus 9068c0984e5SSebastian Reichel * register is not updated, hence doing the same 9078c0984e5SSebastian Reichel * Revisit this: 9088c0984e5SSebastian Reichel */ 9098c0984e5SSebastian Reichel 9108c0984e5SSebastian Reichel /* get the USB type */ 9118c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 9128c0984e5SSebastian Reichel val = (val & AB8500_USB_LINK_STATUS) >> 9138c0984e5SSebastian Reichel USB_LINK_STATUS_SHIFT; 9148c0984e5SSebastian Reichel else 9158c0984e5SSebastian Reichel val = (val & AB8505_USB_LINK_STATUS) >> 9168c0984e5SSebastian Reichel USB_LINK_STATUS_SHIFT; 9178c0984e5SSebastian Reichel if (val) 9188c0984e5SSebastian Reichel break; 9198c0984e5SSebastian Reichel } 9208c0984e5SSebastian Reichel ret = ab8500_charger_max_usb_curr(di, 9218c0984e5SSebastian Reichel (enum ab8500_charger_link_status) val); 9228c0984e5SSebastian Reichel 9238c0984e5SSebastian Reichel return ret; 9248c0984e5SSebastian Reichel } 9258c0984e5SSebastian Reichel 9268c0984e5SSebastian Reichel /* 9278c0984e5SSebastian Reichel * This array maps the raw hex value to charger voltage used by the AB8500 928bc6e0287SLinus Walleij * Values taken from the UM0836, in microvolt. 9298c0984e5SSebastian Reichel */ 9308c0984e5SSebastian Reichel static int ab8500_charger_voltage_map[] = { 931bc6e0287SLinus Walleij 3500000, 932bc6e0287SLinus Walleij 3525000, 933bc6e0287SLinus Walleij 3550000, 934bc6e0287SLinus Walleij 3575000, 935bc6e0287SLinus Walleij 3600000, 936bc6e0287SLinus Walleij 3625000, 937bc6e0287SLinus Walleij 3650000, 938bc6e0287SLinus Walleij 3675000, 939bc6e0287SLinus Walleij 3700000, 940bc6e0287SLinus Walleij 3725000, 941bc6e0287SLinus Walleij 3750000, 942bc6e0287SLinus Walleij 3775000, 943bc6e0287SLinus Walleij 3800000, 944bc6e0287SLinus Walleij 3825000, 945bc6e0287SLinus Walleij 3850000, 946bc6e0287SLinus Walleij 3875000, 947bc6e0287SLinus Walleij 3900000, 948bc6e0287SLinus Walleij 3925000, 949bc6e0287SLinus Walleij 3950000, 950bc6e0287SLinus Walleij 3975000, 951bc6e0287SLinus Walleij 4000000, 952bc6e0287SLinus Walleij 4025000, 953bc6e0287SLinus Walleij 4050000, 954bc6e0287SLinus Walleij 4060000, 955bc6e0287SLinus Walleij 4070000, 956bc6e0287SLinus Walleij 4080000, 957bc6e0287SLinus Walleij 4090000, 958bc6e0287SLinus Walleij 4100000, 959bc6e0287SLinus Walleij 4110000, 960bc6e0287SLinus Walleij 4120000, 961bc6e0287SLinus Walleij 4130000, 962bc6e0287SLinus Walleij 4140000, 963bc6e0287SLinus Walleij 4150000, 964bc6e0287SLinus Walleij 4160000, 965bc6e0287SLinus Walleij 4170000, 966bc6e0287SLinus Walleij 4180000, 967bc6e0287SLinus Walleij 4190000, 968bc6e0287SLinus Walleij 4200000, 969bc6e0287SLinus Walleij 4210000, 970bc6e0287SLinus Walleij 4220000, 971bc6e0287SLinus Walleij 4230000, 972bc6e0287SLinus Walleij 4240000, 973bc6e0287SLinus Walleij 4250000, 974bc6e0287SLinus Walleij 4260000, 975bc6e0287SLinus Walleij 4270000, 976bc6e0287SLinus Walleij 4280000, 977bc6e0287SLinus Walleij 4290000, 978bc6e0287SLinus Walleij 4300000, 979bc6e0287SLinus Walleij 4310000, 980bc6e0287SLinus Walleij 4320000, 981bc6e0287SLinus Walleij 4330000, 982bc6e0287SLinus Walleij 4340000, 983bc6e0287SLinus Walleij 4350000, 984bc6e0287SLinus Walleij 4360000, 985bc6e0287SLinus Walleij 4370000, 986bc6e0287SLinus Walleij 4380000, 987bc6e0287SLinus Walleij 4390000, 988bc6e0287SLinus Walleij 4400000, 989bc6e0287SLinus Walleij 4410000, 990bc6e0287SLinus Walleij 4420000, 991bc6e0287SLinus Walleij 4430000, 992bc6e0287SLinus Walleij 4440000, 993bc6e0287SLinus Walleij 4450000, 994bc6e0287SLinus Walleij 4460000, 995bc6e0287SLinus Walleij 4470000, 996bc6e0287SLinus Walleij 4480000, 997bc6e0287SLinus Walleij 4490000, 998bc6e0287SLinus Walleij 4500000, 999bc6e0287SLinus Walleij 4510000, 1000bc6e0287SLinus Walleij 4520000, 1001bc6e0287SLinus Walleij 4530000, 1002bc6e0287SLinus Walleij 4540000, 1003bc6e0287SLinus Walleij 4550000, 1004bc6e0287SLinus Walleij 4560000, 1005bc6e0287SLinus Walleij 4570000, 1006bc6e0287SLinus Walleij 4580000, 1007bc6e0287SLinus Walleij 4590000, 1008bc6e0287SLinus Walleij 4600000, 10098c0984e5SSebastian Reichel }; 10108c0984e5SSebastian Reichel 1011bc6e0287SLinus Walleij static int ab8500_voltage_to_regval(int voltage_uv) 10128c0984e5SSebastian Reichel { 10138c0984e5SSebastian Reichel int i; 10148c0984e5SSebastian Reichel 10158c0984e5SSebastian Reichel /* Special case for voltage below 3.5V */ 1016bc6e0287SLinus Walleij if (voltage_uv < ab8500_charger_voltage_map[0]) 10178c0984e5SSebastian Reichel return LOW_VOLT_REG; 10188c0984e5SSebastian Reichel 10198c0984e5SSebastian Reichel for (i = 1; i < ARRAY_SIZE(ab8500_charger_voltage_map); i++) { 1020bc6e0287SLinus Walleij if (voltage_uv < ab8500_charger_voltage_map[i]) 10218c0984e5SSebastian Reichel return i - 1; 10228c0984e5SSebastian Reichel } 10238c0984e5SSebastian Reichel 10248c0984e5SSebastian Reichel /* If not last element, return error */ 10258c0984e5SSebastian Reichel i = ARRAY_SIZE(ab8500_charger_voltage_map) - 1; 1026bc6e0287SLinus Walleij if (voltage_uv == ab8500_charger_voltage_map[i]) 10278c0984e5SSebastian Reichel return i; 10288c0984e5SSebastian Reichel else 10298c0984e5SSebastian Reichel return -1; 10308c0984e5SSebastian Reichel } 10318c0984e5SSebastian Reichel 10323aca6ecdSLinus Walleij /* This array maps the raw register value to charger input current */ 10333aca6ecdSLinus Walleij static int ab8500_charge_input_curr_map[] = { 103483e5aa77SLinus Walleij 50000, 98000, 193000, 290000, 380000, 450000, 500000, 600000, 103583e5aa77SLinus Walleij 700000, 800000, 900000, 1000000, 1100000, 1300000, 1400000, 1500000, 10363aca6ecdSLinus Walleij }; 10373aca6ecdSLinus Walleij 10383aca6ecdSLinus Walleij /* This array maps the raw register value to charger output current */ 10393aca6ecdSLinus Walleij static int ab8500_charge_output_curr_map[] = { 104083e5aa77SLinus Walleij 100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 104183e5aa77SLinus Walleij 900000, 1000000, 1100000, 1200000, 1300000, 1400000, 1500000, 1500000, 10423aca6ecdSLinus Walleij }; 10433aca6ecdSLinus Walleij 104483e5aa77SLinus Walleij static int ab8500_current_to_regval(struct ab8500_charger *di, int curr_ua) 10458c0984e5SSebastian Reichel { 10468c0984e5SSebastian Reichel int i; 10478c0984e5SSebastian Reichel 104883e5aa77SLinus Walleij if (curr_ua < ab8500_charge_output_curr_map[0]) 10498c0984e5SSebastian Reichel return 0; 10508c0984e5SSebastian Reichel 10513aca6ecdSLinus Walleij for (i = 0; i < ARRAY_SIZE(ab8500_charge_output_curr_map); i++) { 105283e5aa77SLinus Walleij if (curr_ua < ab8500_charge_output_curr_map[i]) 10538c0984e5SSebastian Reichel return i - 1; 10548c0984e5SSebastian Reichel } 10558c0984e5SSebastian Reichel 10568c0984e5SSebastian Reichel /* If not last element, return error */ 10573aca6ecdSLinus Walleij i = ARRAY_SIZE(ab8500_charge_output_curr_map) - 1; 105883e5aa77SLinus Walleij if (curr_ua == ab8500_charge_output_curr_map[i]) 10598c0984e5SSebastian Reichel return i; 10608c0984e5SSebastian Reichel else 10618c0984e5SSebastian Reichel return -1; 10628c0984e5SSebastian Reichel } 10638c0984e5SSebastian Reichel 106483e5aa77SLinus Walleij static int ab8500_vbus_in_curr_to_regval(struct ab8500_charger *di, int curr_ua) 10658c0984e5SSebastian Reichel { 10668c0984e5SSebastian Reichel int i; 10678c0984e5SSebastian Reichel 106883e5aa77SLinus Walleij if (curr_ua < ab8500_charge_input_curr_map[0]) 10698c0984e5SSebastian Reichel return 0; 10708c0984e5SSebastian Reichel 10713aca6ecdSLinus Walleij for (i = 0; i < ARRAY_SIZE(ab8500_charge_input_curr_map); i++) { 107283e5aa77SLinus Walleij if (curr_ua < ab8500_charge_input_curr_map[i]) 10738c0984e5SSebastian Reichel return i - 1; 10748c0984e5SSebastian Reichel } 10758c0984e5SSebastian Reichel 10768c0984e5SSebastian Reichel /* If not last element, return error */ 10773aca6ecdSLinus Walleij i = ARRAY_SIZE(ab8500_charge_input_curr_map) - 1; 107883e5aa77SLinus Walleij if (curr_ua == ab8500_charge_input_curr_map[i]) 10798c0984e5SSebastian Reichel return i; 10808c0984e5SSebastian Reichel else 10818c0984e5SSebastian Reichel return -1; 10828c0984e5SSebastian Reichel } 10838c0984e5SSebastian Reichel 10848c0984e5SSebastian Reichel /** 10858c0984e5SSebastian Reichel * ab8500_charger_get_usb_cur() - get usb current 10868c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structre 10878c0984e5SSebastian Reichel * 10888c0984e5SSebastian Reichel * The usb stack provides the maximum current that can be drawn from 108983e5aa77SLinus Walleij * the standard usb host. This will be in uA. 109083e5aa77SLinus Walleij * This function converts current in uA to a value that can be written 10918c0984e5SSebastian Reichel * to the register. Returns -1 if charging is not allowed 10928c0984e5SSebastian Reichel */ 10938c0984e5SSebastian Reichel static int ab8500_charger_get_usb_cur(struct ab8500_charger *di) 10948c0984e5SSebastian Reichel { 10958c0984e5SSebastian Reichel int ret = 0; 109683e5aa77SLinus Walleij switch (di->usb_state.usb_current_ua) { 109783e5aa77SLinus Walleij case 100000: 109883e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P09; 10998c0984e5SSebastian Reichel break; 110083e5aa77SLinus Walleij case 200000: 110183e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P19; 11028c0984e5SSebastian Reichel break; 110383e5aa77SLinus Walleij case 300000: 110483e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P29; 11058c0984e5SSebastian Reichel break; 110683e5aa77SLinus Walleij case 400000: 110783e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P38; 11088c0984e5SSebastian Reichel break; 110983e5aa77SLinus Walleij case 500000: 111083e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; 11118c0984e5SSebastian Reichel break; 11128c0984e5SSebastian Reichel default: 111383e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P05; 11148c0984e5SSebastian Reichel ret = -EPERM; 11158c0984e5SSebastian Reichel break; 1116e15c54d2SMa Feng } 111783e5aa77SLinus Walleij di->max_usb_in_curr.set_max_ua = di->max_usb_in_curr.usb_type_max_ua; 11188c0984e5SSebastian Reichel return ret; 11198c0984e5SSebastian Reichel } 11208c0984e5SSebastian Reichel 11218c0984e5SSebastian Reichel /** 11228c0984e5SSebastian Reichel * ab8500_charger_check_continue_stepping() - Check to allow stepping 11238c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 11248c0984e5SSebastian Reichel * @reg: select what charger register to check 11258c0984e5SSebastian Reichel * 11268c0984e5SSebastian Reichel * Check if current stepping should be allowed to continue. 11278c0984e5SSebastian Reichel * Checks if charger source has not collapsed. If it has, further stepping 11288c0984e5SSebastian Reichel * is not allowed. 11298c0984e5SSebastian Reichel */ 11308c0984e5SSebastian Reichel static bool ab8500_charger_check_continue_stepping(struct ab8500_charger *di, 11318c0984e5SSebastian Reichel int reg) 11328c0984e5SSebastian Reichel { 11338c0984e5SSebastian Reichel if (reg == AB8500_USBCH_IPT_CRNTLVL_REG) 11348c0984e5SSebastian Reichel return !di->flags.vbus_drop_end; 11358c0984e5SSebastian Reichel else 11368c0984e5SSebastian Reichel return true; 11378c0984e5SSebastian Reichel } 11388c0984e5SSebastian Reichel 11398c0984e5SSebastian Reichel /** 11408c0984e5SSebastian Reichel * ab8500_charger_set_current() - set charger current 11418c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 114283e5aa77SLinus Walleij * @ich_ua: charger current, in uA 11438c0984e5SSebastian Reichel * @reg: select what charger register to set 11448c0984e5SSebastian Reichel * 11458c0984e5SSebastian Reichel * Set charger current. 11468c0984e5SSebastian Reichel * There is no state machine in the AB to step up/down the charger 11478c0984e5SSebastian Reichel * current to avoid dips and spikes on MAIN, VBUS and VBAT when 11488c0984e5SSebastian Reichel * charging is started. Instead we need to implement 11498c0984e5SSebastian Reichel * this charger current step-up/down here. 11508c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 11518c0984e5SSebastian Reichel */ 11528c0984e5SSebastian Reichel static int ab8500_charger_set_current(struct ab8500_charger *di, 115383e5aa77SLinus Walleij int ich_ua, int reg) 11548c0984e5SSebastian Reichel { 11558c0984e5SSebastian Reichel int ret = 0; 11568c0984e5SSebastian Reichel int curr_index, prev_curr_index, shift_value, i; 11578c0984e5SSebastian Reichel u8 reg_value; 11588c0984e5SSebastian Reichel u32 step_udelay; 11598c0984e5SSebastian Reichel bool no_stepping = false; 11608c0984e5SSebastian Reichel 11618c0984e5SSebastian Reichel atomic_inc(&di->current_stepping_sessions); 11628c0984e5SSebastian Reichel 11638c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 11648c0984e5SSebastian Reichel reg, ®_value); 11658c0984e5SSebastian Reichel if (ret < 0) { 11668c0984e5SSebastian Reichel dev_err(di->dev, "%s read failed\n", __func__); 11678c0984e5SSebastian Reichel goto exit_set_current; 11688c0984e5SSebastian Reichel } 11698c0984e5SSebastian Reichel 11708c0984e5SSebastian Reichel switch (reg) { 11718c0984e5SSebastian Reichel case AB8500_MCH_IPT_CURLVL_REG: 11728c0984e5SSebastian Reichel shift_value = MAIN_CH_INPUT_CURR_SHIFT; 11738c0984e5SSebastian Reichel prev_curr_index = (reg_value >> shift_value); 117483e5aa77SLinus Walleij curr_index = ab8500_current_to_regval(di, ich_ua); 11758c0984e5SSebastian Reichel step_udelay = STEP_UDELAY; 11768c0984e5SSebastian Reichel if (!di->ac.charger_connected) 11778c0984e5SSebastian Reichel no_stepping = true; 11788c0984e5SSebastian Reichel break; 11798c0984e5SSebastian Reichel case AB8500_USBCH_IPT_CRNTLVL_REG: 11808c0984e5SSebastian Reichel shift_value = VBUS_IN_CURR_LIM_SHIFT; 11818c0984e5SSebastian Reichel prev_curr_index = (reg_value >> shift_value); 118283e5aa77SLinus Walleij curr_index = ab8500_vbus_in_curr_to_regval(di, ich_ua); 11838c0984e5SSebastian Reichel step_udelay = STEP_UDELAY * 100; 11848c0984e5SSebastian Reichel 11858c0984e5SSebastian Reichel if (!di->usb.charger_connected) 11868c0984e5SSebastian Reichel no_stepping = true; 11878c0984e5SSebastian Reichel break; 11888c0984e5SSebastian Reichel case AB8500_CH_OPT_CRNTLVL_REG: 11898c0984e5SSebastian Reichel shift_value = 0; 11908c0984e5SSebastian Reichel prev_curr_index = (reg_value >> shift_value); 119183e5aa77SLinus Walleij curr_index = ab8500_current_to_regval(di, ich_ua); 11928c0984e5SSebastian Reichel step_udelay = STEP_UDELAY; 11938c0984e5SSebastian Reichel if (curr_index && (curr_index - prev_curr_index) > 1) 11948c0984e5SSebastian Reichel step_udelay *= 100; 11958c0984e5SSebastian Reichel 11968c0984e5SSebastian Reichel if (!di->usb.charger_connected && !di->ac.charger_connected) 11978c0984e5SSebastian Reichel no_stepping = true; 11988c0984e5SSebastian Reichel 11998c0984e5SSebastian Reichel break; 12008c0984e5SSebastian Reichel default: 12018c0984e5SSebastian Reichel dev_err(di->dev, "%s current register not valid\n", __func__); 12028c0984e5SSebastian Reichel ret = -ENXIO; 12038c0984e5SSebastian Reichel goto exit_set_current; 12048c0984e5SSebastian Reichel } 12058c0984e5SSebastian Reichel 12068c0984e5SSebastian Reichel if (curr_index < 0) { 12078c0984e5SSebastian Reichel dev_err(di->dev, "requested current limit out-of-range\n"); 12088c0984e5SSebastian Reichel ret = -ENXIO; 12098c0984e5SSebastian Reichel goto exit_set_current; 12108c0984e5SSebastian Reichel } 12118c0984e5SSebastian Reichel 12128c0984e5SSebastian Reichel /* only update current if it's been changed */ 12138c0984e5SSebastian Reichel if (prev_curr_index == curr_index) { 12148c0984e5SSebastian Reichel dev_dbg(di->dev, "%s current not changed for reg: 0x%02x\n", 12158c0984e5SSebastian Reichel __func__, reg); 12168c0984e5SSebastian Reichel ret = 0; 12178c0984e5SSebastian Reichel goto exit_set_current; 12188c0984e5SSebastian Reichel } 12198c0984e5SSebastian Reichel 122083e5aa77SLinus Walleij dev_dbg(di->dev, "%s set charger current: %d uA for reg: 0x%02x\n", 122183e5aa77SLinus Walleij __func__, ich_ua, reg); 12228c0984e5SSebastian Reichel 12238c0984e5SSebastian Reichel if (no_stepping) { 12248c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 12258c0984e5SSebastian Reichel reg, (u8)curr_index << shift_value); 12268c0984e5SSebastian Reichel if (ret) 12278c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 12288c0984e5SSebastian Reichel } else if (prev_curr_index > curr_index) { 12298c0984e5SSebastian Reichel for (i = prev_curr_index - 1; i >= curr_index; i--) { 12308c0984e5SSebastian Reichel dev_dbg(di->dev, "curr change_1 to: %x for 0x%02x\n", 12318c0984e5SSebastian Reichel (u8) i << shift_value, reg); 12328c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 12338c0984e5SSebastian Reichel AB8500_CHARGER, reg, (u8)i << shift_value); 12348c0984e5SSebastian Reichel if (ret) { 12358c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 12368c0984e5SSebastian Reichel goto exit_set_current; 12378c0984e5SSebastian Reichel } 12388c0984e5SSebastian Reichel if (i != curr_index) 12398c0984e5SSebastian Reichel usleep_range(step_udelay, step_udelay * 2); 12408c0984e5SSebastian Reichel } 12418c0984e5SSebastian Reichel } else { 12428c0984e5SSebastian Reichel bool allow = true; 12438c0984e5SSebastian Reichel for (i = prev_curr_index + 1; i <= curr_index && allow; i++) { 12448c0984e5SSebastian Reichel dev_dbg(di->dev, "curr change_2 to: %x for 0x%02x\n", 12458c0984e5SSebastian Reichel (u8)i << shift_value, reg); 12468c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 12478c0984e5SSebastian Reichel AB8500_CHARGER, reg, (u8)i << shift_value); 12488c0984e5SSebastian Reichel if (ret) { 12498c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 12508c0984e5SSebastian Reichel goto exit_set_current; 12518c0984e5SSebastian Reichel } 12528c0984e5SSebastian Reichel if (i != curr_index) 12538c0984e5SSebastian Reichel usleep_range(step_udelay, step_udelay * 2); 12548c0984e5SSebastian Reichel 12558c0984e5SSebastian Reichel allow = ab8500_charger_check_continue_stepping(di, reg); 12568c0984e5SSebastian Reichel } 12578c0984e5SSebastian Reichel } 12588c0984e5SSebastian Reichel 12598c0984e5SSebastian Reichel exit_set_current: 12608c0984e5SSebastian Reichel atomic_dec(&di->current_stepping_sessions); 12618c0984e5SSebastian Reichel 12628c0984e5SSebastian Reichel return ret; 12638c0984e5SSebastian Reichel } 12648c0984e5SSebastian Reichel 12658c0984e5SSebastian Reichel /** 12668c0984e5SSebastian Reichel * ab8500_charger_set_vbus_in_curr() - set VBUS input current limit 12678c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 126883e5aa77SLinus Walleij * @ich_in_ua: charger input current limit in microampere 12698c0984e5SSebastian Reichel * 12708c0984e5SSebastian Reichel * Sets the current that can be drawn from the USB host 12718c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 12728c0984e5SSebastian Reichel */ 12738c0984e5SSebastian Reichel static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, 127483e5aa77SLinus Walleij int ich_in_ua) 12758c0984e5SSebastian Reichel { 12768c0984e5SSebastian Reichel int min_value; 12778c0984e5SSebastian Reichel int ret; 12788c0984e5SSebastian Reichel 12798c0984e5SSebastian Reichel /* We should always use to lowest current limit */ 128083e5aa77SLinus Walleij min_value = min(di->bm->chg_params->usb_curr_max_ua, ich_in_ua); 128183e5aa77SLinus Walleij if (di->max_usb_in_curr.set_max_ua > 0) 128283e5aa77SLinus Walleij min_value = min(di->max_usb_in_curr.set_max_ua, min_value); 12838c0984e5SSebastian Reichel 128483e5aa77SLinus Walleij if (di->usb_state.usb_current_ua >= 0) 128583e5aa77SLinus Walleij min_value = min(di->usb_state.usb_current_ua, min_value); 12868c0984e5SSebastian Reichel 12878c0984e5SSebastian Reichel switch (min_value) { 128883e5aa77SLinus Walleij case 100000: 12898c0984e5SSebastian Reichel if (di->vbat < VBAT_TRESH_IP_CUR_RED) 12908c0984e5SSebastian Reichel min_value = USB_CH_IP_CUR_LVL_0P05; 12918c0984e5SSebastian Reichel break; 129283e5aa77SLinus Walleij case 500000: 12938c0984e5SSebastian Reichel if (di->vbat < VBAT_TRESH_IP_CUR_RED) 12948c0984e5SSebastian Reichel min_value = USB_CH_IP_CUR_LVL_0P45; 12958c0984e5SSebastian Reichel break; 12968c0984e5SSebastian Reichel default: 12978c0984e5SSebastian Reichel break; 12988c0984e5SSebastian Reichel } 12998c0984e5SSebastian Reichel 130083e5aa77SLinus Walleij dev_info(di->dev, "VBUS input current limit set to %d uA\n", min_value); 13018c0984e5SSebastian Reichel 13028c0984e5SSebastian Reichel mutex_lock(&di->usb_ipt_crnt_lock); 13038c0984e5SSebastian Reichel ret = ab8500_charger_set_current(di, min_value, 13048c0984e5SSebastian Reichel AB8500_USBCH_IPT_CRNTLVL_REG); 13058c0984e5SSebastian Reichel mutex_unlock(&di->usb_ipt_crnt_lock); 13068c0984e5SSebastian Reichel 13078c0984e5SSebastian Reichel return ret; 13088c0984e5SSebastian Reichel } 13098c0984e5SSebastian Reichel 13108c0984e5SSebastian Reichel /** 13118c0984e5SSebastian Reichel * ab8500_charger_set_main_in_curr() - set main charger input current 13128c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 131383e5aa77SLinus Walleij * @ich_in_ua: input charger current, in uA 13148c0984e5SSebastian Reichel * 13158c0984e5SSebastian Reichel * Set main charger input current. 13168c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 13178c0984e5SSebastian Reichel */ 13188c0984e5SSebastian Reichel static int ab8500_charger_set_main_in_curr(struct ab8500_charger *di, 131983e5aa77SLinus Walleij int ich_in_ua) 13208c0984e5SSebastian Reichel { 132183e5aa77SLinus Walleij return ab8500_charger_set_current(di, ich_in_ua, 13228c0984e5SSebastian Reichel AB8500_MCH_IPT_CURLVL_REG); 13238c0984e5SSebastian Reichel } 13248c0984e5SSebastian Reichel 13258c0984e5SSebastian Reichel /** 13268c0984e5SSebastian Reichel * ab8500_charger_set_output_curr() - set charger output current 13278c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 132883e5aa77SLinus Walleij * @ich_out_ua: output charger current, in uA 13298c0984e5SSebastian Reichel * 13308c0984e5SSebastian Reichel * Set charger output current. 13318c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 13328c0984e5SSebastian Reichel */ 13338c0984e5SSebastian Reichel static int ab8500_charger_set_output_curr(struct ab8500_charger *di, 133483e5aa77SLinus Walleij int ich_out_ua) 13358c0984e5SSebastian Reichel { 133683e5aa77SLinus Walleij return ab8500_charger_set_current(di, ich_out_ua, 13378c0984e5SSebastian Reichel AB8500_CH_OPT_CRNTLVL_REG); 13388c0984e5SSebastian Reichel } 13398c0984e5SSebastian Reichel 13408c0984e5SSebastian Reichel /** 13418c0984e5SSebastian Reichel * ab8500_charger_led_en() - turn on/off chargign led 13428c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 13438c0984e5SSebastian Reichel * @on: flag to turn on/off the chargign led 13448c0984e5SSebastian Reichel * 13458c0984e5SSebastian Reichel * Power ON/OFF charging LED indication 13468c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 13478c0984e5SSebastian Reichel */ 13488c0984e5SSebastian Reichel static int ab8500_charger_led_en(struct ab8500_charger *di, int on) 13498c0984e5SSebastian Reichel { 13508c0984e5SSebastian Reichel int ret; 13518c0984e5SSebastian Reichel 13528c0984e5SSebastian Reichel if (on) { 13538c0984e5SSebastian Reichel /* Power ON charging LED indicator, set LED current to 5mA */ 13548c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 13558c0984e5SSebastian Reichel AB8500_LED_INDICATOR_PWM_CTRL, 13568c0984e5SSebastian Reichel (LED_IND_CUR_5MA | LED_INDICATOR_PWM_ENA)); 13578c0984e5SSebastian Reichel if (ret) { 13588c0984e5SSebastian Reichel dev_err(di->dev, "Power ON LED failed\n"); 13598c0984e5SSebastian Reichel return ret; 13608c0984e5SSebastian Reichel } 13618c0984e5SSebastian Reichel /* LED indicator PWM duty cycle 252/256 */ 13628c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 13638c0984e5SSebastian Reichel AB8500_LED_INDICATOR_PWM_DUTY, 13648c0984e5SSebastian Reichel LED_INDICATOR_PWM_DUTY_252_256); 13658c0984e5SSebastian Reichel if (ret) { 13668c0984e5SSebastian Reichel dev_err(di->dev, "Set LED PWM duty cycle failed\n"); 13678c0984e5SSebastian Reichel return ret; 13688c0984e5SSebastian Reichel } 13698c0984e5SSebastian Reichel } else { 13708c0984e5SSebastian Reichel /* Power off charging LED indicator */ 13718c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 13728c0984e5SSebastian Reichel AB8500_LED_INDICATOR_PWM_CTRL, 13738c0984e5SSebastian Reichel LED_INDICATOR_PWM_DIS); 13748c0984e5SSebastian Reichel if (ret) { 13758c0984e5SSebastian Reichel dev_err(di->dev, "Power-off LED failed\n"); 13768c0984e5SSebastian Reichel return ret; 13778c0984e5SSebastian Reichel } 13788c0984e5SSebastian Reichel } 13798c0984e5SSebastian Reichel 13808c0984e5SSebastian Reichel return ret; 13818c0984e5SSebastian Reichel } 13828c0984e5SSebastian Reichel 13838c0984e5SSebastian Reichel /** 13848c0984e5SSebastian Reichel * ab8500_charger_ac_en() - enable or disable ac charging 13858c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 13868c0984e5SSebastian Reichel * @enable: enable/disable flag 1387bc6e0287SLinus Walleij * @vset_uv: charging voltage in microvolt 138883e5aa77SLinus Walleij * @iset_ua: charging current in microampere 13898c0984e5SSebastian Reichel * 13908c0984e5SSebastian Reichel * Enable/Disable AC/Mains charging and turns on/off the charging led 13918c0984e5SSebastian Reichel * respectively. 13928c0984e5SSebastian Reichel **/ 13938c0984e5SSebastian Reichel static int ab8500_charger_ac_en(struct ux500_charger *charger, 1394bc6e0287SLinus Walleij int enable, int vset_uv, int iset_ua) 13958c0984e5SSebastian Reichel { 13968c0984e5SSebastian Reichel int ret; 13978c0984e5SSebastian Reichel int volt_index; 13988c0984e5SSebastian Reichel int curr_index; 13998c0984e5SSebastian Reichel int input_curr_index; 14008c0984e5SSebastian Reichel u8 overshoot = 0; 14018c0984e5SSebastian Reichel 14028c0984e5SSebastian Reichel struct ab8500_charger *di = to_ab8500_charger_ac_device_info(charger); 14038c0984e5SSebastian Reichel 14048c0984e5SSebastian Reichel if (enable) { 14058c0984e5SSebastian Reichel /* Check if AC is connected */ 14068c0984e5SSebastian Reichel if (!di->ac.charger_connected) { 14078c0984e5SSebastian Reichel dev_err(di->dev, "AC charger not connected\n"); 14088c0984e5SSebastian Reichel return -ENXIO; 14098c0984e5SSebastian Reichel } 14108c0984e5SSebastian Reichel 14118c0984e5SSebastian Reichel /* Enable AC charging */ 1412bc6e0287SLinus Walleij dev_dbg(di->dev, "Enable AC: %duV %duA\n", vset_uv, iset_ua); 14138c0984e5SSebastian Reichel 14148c0984e5SSebastian Reichel /* 14158c0984e5SSebastian Reichel * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts 14168c0984e5SSebastian Reichel * will be triggered every time we enable the VDD ADC supply. 14178c0984e5SSebastian Reichel * This will turn off charging for a short while. 14188c0984e5SSebastian Reichel * It can be avoided by having the supply on when 14198c0984e5SSebastian Reichel * there is a charger enabled. Normally the VDD ADC supply 1420ddb74e98SAshish Chavan * is enabled every time a GPADC conversion is triggered. 1421ddb74e98SAshish Chavan * We will force it to be enabled from this driver to have 1422ddb74e98SAshish Chavan * the GPADC module independent of the AB8500 chargers 14238c0984e5SSebastian Reichel */ 14248c0984e5SSebastian Reichel if (!di->vddadc_en_ac) { 14258c0984e5SSebastian Reichel ret = regulator_enable(di->regu); 14268c0984e5SSebastian Reichel if (ret) 14278c0984e5SSebastian Reichel dev_warn(di->dev, 14288c0984e5SSebastian Reichel "Failed to enable regulator\n"); 14298c0984e5SSebastian Reichel else 14308c0984e5SSebastian Reichel di->vddadc_en_ac = true; 14318c0984e5SSebastian Reichel } 14328c0984e5SSebastian Reichel 14338c0984e5SSebastian Reichel /* Check if the requested voltage or current is valid */ 1434bc6e0287SLinus Walleij volt_index = ab8500_voltage_to_regval(vset_uv); 143583e5aa77SLinus Walleij curr_index = ab8500_current_to_regval(di, iset_ua); 14368c0984e5SSebastian Reichel input_curr_index = ab8500_current_to_regval(di, 143783e5aa77SLinus Walleij di->bm->chg_params->ac_curr_max_ua); 14388c0984e5SSebastian Reichel if (volt_index < 0 || curr_index < 0 || input_curr_index < 0) { 14398c0984e5SSebastian Reichel dev_err(di->dev, 14408c0984e5SSebastian Reichel "Charger voltage or current too high, " 14418c0984e5SSebastian Reichel "charging not started\n"); 14428c0984e5SSebastian Reichel return -ENXIO; 14438c0984e5SSebastian Reichel } 14448c0984e5SSebastian Reichel 14458c0984e5SSebastian Reichel /* ChVoltLevel: maximum battery charging voltage */ 14468c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 14478c0984e5SSebastian Reichel AB8500_CH_VOLT_LVL_REG, (u8) volt_index); 14488c0984e5SSebastian Reichel if (ret) { 14498c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 14508c0984e5SSebastian Reichel return ret; 14518c0984e5SSebastian Reichel } 14528c0984e5SSebastian Reichel /* MainChInputCurr: current that can be drawn from the charger*/ 14538c0984e5SSebastian Reichel ret = ab8500_charger_set_main_in_curr(di, 145483e5aa77SLinus Walleij di->bm->chg_params->ac_curr_max_ua); 14558c0984e5SSebastian Reichel if (ret) { 14568c0984e5SSebastian Reichel dev_err(di->dev, "%s Failed to set MainChInputCurr\n", 14578c0984e5SSebastian Reichel __func__); 14588c0984e5SSebastian Reichel return ret; 14598c0984e5SSebastian Reichel } 14608c0984e5SSebastian Reichel /* ChOutputCurentLevel: protected output current */ 146183e5aa77SLinus Walleij ret = ab8500_charger_set_output_curr(di, iset_ua); 14628c0984e5SSebastian Reichel if (ret) { 14638c0984e5SSebastian Reichel dev_err(di->dev, "%s " 14648c0984e5SSebastian Reichel "Failed to set ChOutputCurentLevel\n", 14658c0984e5SSebastian Reichel __func__); 14668c0984e5SSebastian Reichel return ret; 14678c0984e5SSebastian Reichel } 14688c0984e5SSebastian Reichel 14698c0984e5SSebastian Reichel /* Check if VBAT overshoot control should be enabled */ 14708c0984e5SSebastian Reichel if (!di->bm->enable_overshoot) 14718c0984e5SSebastian Reichel overshoot = MAIN_CH_NO_OVERSHOOT_ENA_N; 14728c0984e5SSebastian Reichel 14738c0984e5SSebastian Reichel /* Enable Main Charger */ 14748c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 14758c0984e5SSebastian Reichel AB8500_MCH_CTRL1, MAIN_CH_ENA | overshoot); 14768c0984e5SSebastian Reichel if (ret) { 14778c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 14788c0984e5SSebastian Reichel return ret; 14798c0984e5SSebastian Reichel } 14808c0984e5SSebastian Reichel 14818c0984e5SSebastian Reichel /* Power on charging LED indication */ 14828c0984e5SSebastian Reichel ret = ab8500_charger_led_en(di, true); 14838c0984e5SSebastian Reichel if (ret < 0) 14848c0984e5SSebastian Reichel dev_err(di->dev, "failed to enable LED\n"); 14858c0984e5SSebastian Reichel 14868c0984e5SSebastian Reichel di->ac.charger_online = 1; 14878c0984e5SSebastian Reichel } else { 14888c0984e5SSebastian Reichel /* Disable AC charging */ 14898c0984e5SSebastian Reichel if (is_ab8500_1p1_or_earlier(di->parent)) { 14908c0984e5SSebastian Reichel /* 14918c0984e5SSebastian Reichel * For ABB revision 1.0 and 1.1 there is a bug in the 1492ddb74e98SAshish Chavan * watchdog logic. That means we have to continuously 14938c0984e5SSebastian Reichel * kick the charger watchdog even when no charger is 14948c0984e5SSebastian Reichel * connected. This is only valid once the AC charger 14958c0984e5SSebastian Reichel * has been enabled. This is a bug that is not handled 14968c0984e5SSebastian Reichel * by the algorithm and the watchdog have to be kicked 14978c0984e5SSebastian Reichel * by the charger driver when the AC charger 14988c0984e5SSebastian Reichel * is disabled 14998c0984e5SSebastian Reichel */ 15008c0984e5SSebastian Reichel if (di->ac_conn) { 15018c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 15028c0984e5SSebastian Reichel &di->kick_wd_work, 15038c0984e5SSebastian Reichel round_jiffies(WD_KICK_INTERVAL)); 15048c0984e5SSebastian Reichel } 15058c0984e5SSebastian Reichel 15068c0984e5SSebastian Reichel /* 15078c0984e5SSebastian Reichel * We can't turn off charging completely 15088c0984e5SSebastian Reichel * due to a bug in AB8500 cut1. 15098c0984e5SSebastian Reichel * If we do, charging will not start again. 15108c0984e5SSebastian Reichel * That is why we set the lowest voltage 15118c0984e5SSebastian Reichel * and current possible 15128c0984e5SSebastian Reichel */ 15138c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 15148c0984e5SSebastian Reichel AB8500_CHARGER, 15158c0984e5SSebastian Reichel AB8500_CH_VOLT_LVL_REG, CH_VOL_LVL_3P5); 15168c0984e5SSebastian Reichel if (ret) { 15178c0984e5SSebastian Reichel dev_err(di->dev, 15188c0984e5SSebastian Reichel "%s write failed\n", __func__); 15198c0984e5SSebastian Reichel return ret; 15208c0984e5SSebastian Reichel } 15218c0984e5SSebastian Reichel 15228c0984e5SSebastian Reichel ret = ab8500_charger_set_output_curr(di, 0); 15238c0984e5SSebastian Reichel if (ret) { 15248c0984e5SSebastian Reichel dev_err(di->dev, "%s " 15258c0984e5SSebastian Reichel "Failed to set ChOutputCurentLevel\n", 15268c0984e5SSebastian Reichel __func__); 15278c0984e5SSebastian Reichel return ret; 15288c0984e5SSebastian Reichel } 15298c0984e5SSebastian Reichel } else { 15308c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 15318c0984e5SSebastian Reichel AB8500_CHARGER, 15328c0984e5SSebastian Reichel AB8500_MCH_CTRL1, 0); 15338c0984e5SSebastian Reichel if (ret) { 15348c0984e5SSebastian Reichel dev_err(di->dev, 15358c0984e5SSebastian Reichel "%s write failed\n", __func__); 15368c0984e5SSebastian Reichel return ret; 15378c0984e5SSebastian Reichel } 15388c0984e5SSebastian Reichel } 15398c0984e5SSebastian Reichel 15408c0984e5SSebastian Reichel ret = ab8500_charger_led_en(di, false); 15418c0984e5SSebastian Reichel if (ret < 0) 15428c0984e5SSebastian Reichel dev_err(di->dev, "failed to disable LED\n"); 15438c0984e5SSebastian Reichel 15448c0984e5SSebastian Reichel di->ac.charger_online = 0; 15458c0984e5SSebastian Reichel di->ac.wd_expired = false; 15468c0984e5SSebastian Reichel 15478c0984e5SSebastian Reichel /* Disable regulator if enabled */ 15488c0984e5SSebastian Reichel if (di->vddadc_en_ac) { 15498c0984e5SSebastian Reichel regulator_disable(di->regu); 15508c0984e5SSebastian Reichel di->vddadc_en_ac = false; 15518c0984e5SSebastian Reichel } 15528c0984e5SSebastian Reichel 15538c0984e5SSebastian Reichel dev_dbg(di->dev, "%s Disabled AC charging\n", __func__); 15548c0984e5SSebastian Reichel } 15558c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 15568c0984e5SSebastian Reichel 15578c0984e5SSebastian Reichel return ret; 15588c0984e5SSebastian Reichel } 15598c0984e5SSebastian Reichel 15608c0984e5SSebastian Reichel /** 15618c0984e5SSebastian Reichel * ab8500_charger_usb_en() - enable usb charging 15628c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 15638c0984e5SSebastian Reichel * @enable: enable/disable flag 1564bc6e0287SLinus Walleij * @vset_uv: charging voltage in microvolt 156583e5aa77SLinus Walleij * @ich_out_ua: charger output current in microampere 15668c0984e5SSebastian Reichel * 15678c0984e5SSebastian Reichel * Enable/Disable USB charging and turns on/off the charging led respectively. 15688c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 15698c0984e5SSebastian Reichel */ 15708c0984e5SSebastian Reichel static int ab8500_charger_usb_en(struct ux500_charger *charger, 1571bc6e0287SLinus Walleij int enable, int vset_uv, int ich_out_ua) 15728c0984e5SSebastian Reichel { 15738c0984e5SSebastian Reichel int ret; 15748c0984e5SSebastian Reichel int volt_index; 15758c0984e5SSebastian Reichel int curr_index; 15768c0984e5SSebastian Reichel u8 overshoot = 0; 15778c0984e5SSebastian Reichel 15788c0984e5SSebastian Reichel struct ab8500_charger *di = to_ab8500_charger_usb_device_info(charger); 15798c0984e5SSebastian Reichel 15808c0984e5SSebastian Reichel if (enable) { 15818c0984e5SSebastian Reichel /* Check if USB is connected */ 15828c0984e5SSebastian Reichel if (!di->usb.charger_connected) { 15838c0984e5SSebastian Reichel dev_err(di->dev, "USB charger not connected\n"); 15848c0984e5SSebastian Reichel return -ENXIO; 15858c0984e5SSebastian Reichel } 15868c0984e5SSebastian Reichel 15878c0984e5SSebastian Reichel /* 15888c0984e5SSebastian Reichel * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts 15898c0984e5SSebastian Reichel * will be triggered every time we enable the VDD ADC supply. 15908c0984e5SSebastian Reichel * This will turn off charging for a short while. 15918c0984e5SSebastian Reichel * It can be avoided by having the supply on when 15928c0984e5SSebastian Reichel * there is a charger enabled. Normally the VDD ADC supply 1593ddb74e98SAshish Chavan * is enabled every time a GPADC conversion is triggered. 1594ddb74e98SAshish Chavan * We will force it to be enabled from this driver to have 1595ddb74e98SAshish Chavan * the GPADC module independent of the AB8500 chargers 15968c0984e5SSebastian Reichel */ 15978c0984e5SSebastian Reichel if (!di->vddadc_en_usb) { 15988c0984e5SSebastian Reichel ret = regulator_enable(di->regu); 15998c0984e5SSebastian Reichel if (ret) 16008c0984e5SSebastian Reichel dev_warn(di->dev, 16018c0984e5SSebastian Reichel "Failed to enable regulator\n"); 16028c0984e5SSebastian Reichel else 16038c0984e5SSebastian Reichel di->vddadc_en_usb = true; 16048c0984e5SSebastian Reichel } 16058c0984e5SSebastian Reichel 16068c0984e5SSebastian Reichel /* Enable USB charging */ 1607bc6e0287SLinus Walleij dev_dbg(di->dev, "Enable USB: %d uV %d uA\n", vset_uv, ich_out_ua); 16088c0984e5SSebastian Reichel 16098c0984e5SSebastian Reichel /* Check if the requested voltage or current is valid */ 1610bc6e0287SLinus Walleij volt_index = ab8500_voltage_to_regval(vset_uv); 161183e5aa77SLinus Walleij curr_index = ab8500_current_to_regval(di, ich_out_ua); 16128c0984e5SSebastian Reichel if (volt_index < 0 || curr_index < 0) { 16138c0984e5SSebastian Reichel dev_err(di->dev, 16148c0984e5SSebastian Reichel "Charger voltage or current too high, " 16158c0984e5SSebastian Reichel "charging not started\n"); 16168c0984e5SSebastian Reichel return -ENXIO; 16178c0984e5SSebastian Reichel } 16188c0984e5SSebastian Reichel 1619ddb74e98SAshish Chavan /* 1620ddb74e98SAshish Chavan * ChVoltLevel: max voltage up to which battery can be 1621ddb74e98SAshish Chavan * charged 1622ddb74e98SAshish Chavan */ 16238c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 16248c0984e5SSebastian Reichel AB8500_CH_VOLT_LVL_REG, (u8) volt_index); 16258c0984e5SSebastian Reichel if (ret) { 16268c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 16278c0984e5SSebastian Reichel return ret; 16288c0984e5SSebastian Reichel } 16298c0984e5SSebastian Reichel /* Check if VBAT overshoot control should be enabled */ 16308c0984e5SSebastian Reichel if (!di->bm->enable_overshoot) 16318c0984e5SSebastian Reichel overshoot = USB_CHG_NO_OVERSHOOT_ENA_N; 16328c0984e5SSebastian Reichel 16338c0984e5SSebastian Reichel /* Enable USB Charger */ 16348c0984e5SSebastian Reichel dev_dbg(di->dev, 16358c0984e5SSebastian Reichel "Enabling USB with write to AB8500_USBCH_CTRL1_REG\n"); 16368c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 16378c0984e5SSebastian Reichel AB8500_USBCH_CTRL1_REG, USB_CH_ENA | overshoot); 16388c0984e5SSebastian Reichel if (ret) { 16398c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 16408c0984e5SSebastian Reichel return ret; 16418c0984e5SSebastian Reichel } 16428c0984e5SSebastian Reichel 16438c0984e5SSebastian Reichel /* If success power on charging LED indication */ 16448c0984e5SSebastian Reichel ret = ab8500_charger_led_en(di, true); 16458c0984e5SSebastian Reichel if (ret < 0) 16468c0984e5SSebastian Reichel dev_err(di->dev, "failed to enable LED\n"); 16478c0984e5SSebastian Reichel 16488c0984e5SSebastian Reichel di->usb.charger_online = 1; 16498c0984e5SSebastian Reichel 16508c0984e5SSebastian Reichel /* USBChInputCurr: current that can be drawn from the usb */ 16518c0984e5SSebastian Reichel ret = ab8500_charger_set_vbus_in_curr(di, 165283e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua); 16538c0984e5SSebastian Reichel if (ret) { 16548c0984e5SSebastian Reichel dev_err(di->dev, "setting USBChInputCurr failed\n"); 16558c0984e5SSebastian Reichel return ret; 16568c0984e5SSebastian Reichel } 16578c0984e5SSebastian Reichel 16588c0984e5SSebastian Reichel /* ChOutputCurentLevel: protected output current */ 165983e5aa77SLinus Walleij ret = ab8500_charger_set_output_curr(di, ich_out_ua); 16608c0984e5SSebastian Reichel if (ret) { 16618c0984e5SSebastian Reichel dev_err(di->dev, "%s " 16628c0984e5SSebastian Reichel "Failed to set ChOutputCurentLevel\n", 16638c0984e5SSebastian Reichel __func__); 16648c0984e5SSebastian Reichel return ret; 16658c0984e5SSebastian Reichel } 16668c0984e5SSebastian Reichel 16678c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->check_vbat_work, HZ); 16688c0984e5SSebastian Reichel 16698c0984e5SSebastian Reichel } else { 16708c0984e5SSebastian Reichel /* Disable USB charging */ 16718c0984e5SSebastian Reichel dev_dbg(di->dev, "%s Disabled USB charging\n", __func__); 16728c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 16738c0984e5SSebastian Reichel AB8500_CHARGER, 16748c0984e5SSebastian Reichel AB8500_USBCH_CTRL1_REG, 0); 16758c0984e5SSebastian Reichel if (ret) { 16768c0984e5SSebastian Reichel dev_err(di->dev, 16778c0984e5SSebastian Reichel "%s write failed\n", __func__); 16788c0984e5SSebastian Reichel return ret; 16798c0984e5SSebastian Reichel } 16808c0984e5SSebastian Reichel 16818c0984e5SSebastian Reichel ret = ab8500_charger_led_en(di, false); 16828c0984e5SSebastian Reichel if (ret < 0) 16838c0984e5SSebastian Reichel dev_err(di->dev, "failed to disable LED\n"); 16848c0984e5SSebastian Reichel /* USBChInputCurr: current that can be drawn from the usb */ 16858c0984e5SSebastian Reichel ret = ab8500_charger_set_vbus_in_curr(di, 0); 16868c0984e5SSebastian Reichel if (ret) { 16878c0984e5SSebastian Reichel dev_err(di->dev, "setting USBChInputCurr failed\n"); 16888c0984e5SSebastian Reichel return ret; 16898c0984e5SSebastian Reichel } 16908c0984e5SSebastian Reichel 16918c0984e5SSebastian Reichel /* ChOutputCurentLevel: protected output current */ 16928c0984e5SSebastian Reichel ret = ab8500_charger_set_output_curr(di, 0); 16938c0984e5SSebastian Reichel if (ret) { 16948c0984e5SSebastian Reichel dev_err(di->dev, "%s " 16958c0984e5SSebastian Reichel "Failed to reset ChOutputCurentLevel\n", 16968c0984e5SSebastian Reichel __func__); 16978c0984e5SSebastian Reichel return ret; 16988c0984e5SSebastian Reichel } 16998c0984e5SSebastian Reichel di->usb.charger_online = 0; 17008c0984e5SSebastian Reichel di->usb.wd_expired = false; 17018c0984e5SSebastian Reichel 17028c0984e5SSebastian Reichel /* Disable regulator if enabled */ 17038c0984e5SSebastian Reichel if (di->vddadc_en_usb) { 17048c0984e5SSebastian Reichel regulator_disable(di->regu); 17058c0984e5SSebastian Reichel di->vddadc_en_usb = false; 17068c0984e5SSebastian Reichel } 17078c0984e5SSebastian Reichel 17088c0984e5SSebastian Reichel dev_dbg(di->dev, "%s Disabled USB charging\n", __func__); 17098c0984e5SSebastian Reichel 17108c0984e5SSebastian Reichel /* Cancel any pending Vbat check work */ 17118c0984e5SSebastian Reichel cancel_delayed_work(&di->check_vbat_work); 17128c0984e5SSebastian Reichel 17138c0984e5SSebastian Reichel } 17148c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 17158c0984e5SSebastian Reichel 17168c0984e5SSebastian Reichel return ret; 17178c0984e5SSebastian Reichel } 17188c0984e5SSebastian Reichel 17198c0984e5SSebastian Reichel static int ab8500_external_charger_prepare(struct notifier_block *charger_nb, 17208c0984e5SSebastian Reichel unsigned long event, void *data) 17218c0984e5SSebastian Reichel { 17228c0984e5SSebastian Reichel int ret; 17238c0984e5SSebastian Reichel struct device *dev = data; 17248c0984e5SSebastian Reichel /*Toggle External charger control pin*/ 17258c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK, 17268c0984e5SSebastian Reichel AB8500_SYS_CHARGER_CONTROL_REG, 17278c0984e5SSebastian Reichel EXTERNAL_CHARGER_DISABLE_REG_VAL); 17288c0984e5SSebastian Reichel if (ret < 0) { 17298c0984e5SSebastian Reichel dev_err(dev, "write reg failed %d\n", ret); 17308c0984e5SSebastian Reichel goto out; 17318c0984e5SSebastian Reichel } 17328c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK, 17338c0984e5SSebastian Reichel AB8500_SYS_CHARGER_CONTROL_REG, 17348c0984e5SSebastian Reichel EXTERNAL_CHARGER_ENABLE_REG_VAL); 17358c0984e5SSebastian Reichel if (ret < 0) 17368c0984e5SSebastian Reichel dev_err(dev, "Write reg failed %d\n", ret); 17378c0984e5SSebastian Reichel 17388c0984e5SSebastian Reichel out: 17398c0984e5SSebastian Reichel return ret; 17408c0984e5SSebastian Reichel } 17418c0984e5SSebastian Reichel 17428c0984e5SSebastian Reichel /** 17438c0984e5SSebastian Reichel * ab8500_charger_usb_check_enable() - enable usb charging 17448c0984e5SSebastian Reichel * @charger: pointer to the ux500_charger structure 1745bc6e0287SLinus Walleij * @vset_uv: charging voltage in microvolt 174683e5aa77SLinus Walleij * @iset_ua: charger output current in microampere 17478c0984e5SSebastian Reichel * 17488c0984e5SSebastian Reichel * Check if the VBUS charger has been disconnected and reconnected without 17498c0984e5SSebastian Reichel * AB8500 rising an interrupt. Returns 0 on success. 17508c0984e5SSebastian Reichel */ 17518c0984e5SSebastian Reichel static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, 1752bc6e0287SLinus Walleij int vset_uv, int iset_ua) 17538c0984e5SSebastian Reichel { 17548c0984e5SSebastian Reichel u8 usbch_ctrl1 = 0; 17558c0984e5SSebastian Reichel int ret = 0; 17568c0984e5SSebastian Reichel 17578c0984e5SSebastian Reichel struct ab8500_charger *di = to_ab8500_charger_usb_device_info(charger); 17588c0984e5SSebastian Reichel 17598c0984e5SSebastian Reichel if (!di->usb.charger_connected) 17608c0984e5SSebastian Reichel return ret; 17618c0984e5SSebastian Reichel 17628c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 17638c0984e5SSebastian Reichel AB8500_USBCH_CTRL1_REG, &usbch_ctrl1); 17648c0984e5SSebastian Reichel if (ret < 0) { 17658c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 read failed %d\n", __LINE__); 17668c0984e5SSebastian Reichel return ret; 17678c0984e5SSebastian Reichel } 17688c0984e5SSebastian Reichel dev_dbg(di->dev, "USB charger ctrl: 0x%02x\n", usbch_ctrl1); 17698c0984e5SSebastian Reichel 17708c0984e5SSebastian Reichel if (!(usbch_ctrl1 & USB_CH_ENA)) { 17718c0984e5SSebastian Reichel dev_info(di->dev, "Charging has been disabled abnormally and will be re-enabled\n"); 17728c0984e5SSebastian Reichel 17738c0984e5SSebastian Reichel ret = abx500_mask_and_set_register_interruptible(di->dev, 17748c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CHARGER_CTRL, 17758c0984e5SSebastian Reichel DROP_COUNT_RESET, DROP_COUNT_RESET); 17768c0984e5SSebastian Reichel if (ret < 0) { 17778c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 write failed %d\n", __LINE__); 17788c0984e5SSebastian Reichel return ret; 17798c0984e5SSebastian Reichel } 17808c0984e5SSebastian Reichel 1781bc6e0287SLinus Walleij ret = ab8500_charger_usb_en(&di->usb_chg, true, vset_uv, iset_ua); 17828c0984e5SSebastian Reichel if (ret < 0) { 17838c0984e5SSebastian Reichel dev_err(di->dev, "Failed to enable VBUS charger %d\n", 17848c0984e5SSebastian Reichel __LINE__); 17858c0984e5SSebastian Reichel return ret; 17868c0984e5SSebastian Reichel } 17878c0984e5SSebastian Reichel } 17888c0984e5SSebastian Reichel return ret; 17898c0984e5SSebastian Reichel } 17908c0984e5SSebastian Reichel 17918c0984e5SSebastian Reichel /** 17928c0984e5SSebastian Reichel * ab8500_charger_ac_check_enable() - enable usb charging 17938c0984e5SSebastian Reichel * @charger: pointer to the ux500_charger structure 1794bc6e0287SLinus Walleij * @vset_uv: charging voltage in microvolt 179583e5aa77SLinus Walleij * @iset_ua: charger output current in micrompere 17968c0984e5SSebastian Reichel * 17978c0984e5SSebastian Reichel * Check if the AC charger has been disconnected and reconnected without 17988c0984e5SSebastian Reichel * AB8500 rising an interrupt. Returns 0 on success. 17998c0984e5SSebastian Reichel */ 18008c0984e5SSebastian Reichel static int ab8500_charger_ac_check_enable(struct ux500_charger *charger, 1801bc6e0287SLinus Walleij int vset_uv, int iset_ua) 18028c0984e5SSebastian Reichel { 18038c0984e5SSebastian Reichel u8 mainch_ctrl1 = 0; 18048c0984e5SSebastian Reichel int ret = 0; 18058c0984e5SSebastian Reichel 18068c0984e5SSebastian Reichel struct ab8500_charger *di = to_ab8500_charger_ac_device_info(charger); 18078c0984e5SSebastian Reichel 18088c0984e5SSebastian Reichel if (!di->ac.charger_connected) 18098c0984e5SSebastian Reichel return ret; 18108c0984e5SSebastian Reichel 18118c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 18128c0984e5SSebastian Reichel AB8500_MCH_CTRL1, &mainch_ctrl1); 18138c0984e5SSebastian Reichel if (ret < 0) { 18148c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 read failed %d\n", __LINE__); 18158c0984e5SSebastian Reichel return ret; 18168c0984e5SSebastian Reichel } 18178c0984e5SSebastian Reichel dev_dbg(di->dev, "AC charger ctrl: 0x%02x\n", mainch_ctrl1); 18188c0984e5SSebastian Reichel 18198c0984e5SSebastian Reichel if (!(mainch_ctrl1 & MAIN_CH_ENA)) { 18208c0984e5SSebastian Reichel dev_info(di->dev, "Charging has been disabled abnormally and will be re-enabled\n"); 18218c0984e5SSebastian Reichel 18228c0984e5SSebastian Reichel ret = abx500_mask_and_set_register_interruptible(di->dev, 18238c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CHARGER_CTRL, 18248c0984e5SSebastian Reichel DROP_COUNT_RESET, DROP_COUNT_RESET); 18258c0984e5SSebastian Reichel 18268c0984e5SSebastian Reichel if (ret < 0) { 18278c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 write failed %d\n", __LINE__); 18288c0984e5SSebastian Reichel return ret; 18298c0984e5SSebastian Reichel } 18308c0984e5SSebastian Reichel 1831bc6e0287SLinus Walleij ret = ab8500_charger_ac_en(&di->usb_chg, true, vset_uv, iset_ua); 18328c0984e5SSebastian Reichel if (ret < 0) { 18338c0984e5SSebastian Reichel dev_err(di->dev, "failed to enable AC charger %d\n", 18348c0984e5SSebastian Reichel __LINE__); 18358c0984e5SSebastian Reichel return ret; 18368c0984e5SSebastian Reichel } 18378c0984e5SSebastian Reichel } 18388c0984e5SSebastian Reichel return ret; 18398c0984e5SSebastian Reichel } 18408c0984e5SSebastian Reichel 18418c0984e5SSebastian Reichel /** 18428c0984e5SSebastian Reichel * ab8500_charger_watchdog_kick() - kick charger watchdog 18438c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 18448c0984e5SSebastian Reichel * 18458c0984e5SSebastian Reichel * Kick charger watchdog 18468c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 18478c0984e5SSebastian Reichel */ 18488c0984e5SSebastian Reichel static int ab8500_charger_watchdog_kick(struct ux500_charger *charger) 18498c0984e5SSebastian Reichel { 18508c0984e5SSebastian Reichel int ret; 18518c0984e5SSebastian Reichel struct ab8500_charger *di; 18528c0984e5SSebastian Reichel 18538c0984e5SSebastian Reichel if (charger->psy->desc->type == POWER_SUPPLY_TYPE_MAINS) 18548c0984e5SSebastian Reichel di = to_ab8500_charger_ac_device_info(charger); 18558c0984e5SSebastian Reichel else if (charger->psy->desc->type == POWER_SUPPLY_TYPE_USB) 18568c0984e5SSebastian Reichel di = to_ab8500_charger_usb_device_info(charger); 18578c0984e5SSebastian Reichel else 18588c0984e5SSebastian Reichel return -ENXIO; 18598c0984e5SSebastian Reichel 18608c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 18618c0984e5SSebastian Reichel AB8500_CHARG_WD_CTRL, CHARG_WD_KICK); 18628c0984e5SSebastian Reichel if (ret) 18638c0984e5SSebastian Reichel dev_err(di->dev, "Failed to kick WD!\n"); 18648c0984e5SSebastian Reichel 18658c0984e5SSebastian Reichel return ret; 18668c0984e5SSebastian Reichel } 18678c0984e5SSebastian Reichel 18688c0984e5SSebastian Reichel /** 18698c0984e5SSebastian Reichel * ab8500_charger_update_charger_current() - update charger current 187083e5aa77SLinus Walleij * @charger: pointer to the ab8500_charger structure 187183e5aa77SLinus Walleij * @ich_out_ua: desired output current in microampere 18728c0984e5SSebastian Reichel * 18738c0984e5SSebastian Reichel * Update the charger output current for the specified charger 18748c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 18758c0984e5SSebastian Reichel */ 18768c0984e5SSebastian Reichel static int ab8500_charger_update_charger_current(struct ux500_charger *charger, 187783e5aa77SLinus Walleij int ich_out_ua) 18788c0984e5SSebastian Reichel { 18798c0984e5SSebastian Reichel int ret; 18808c0984e5SSebastian Reichel struct ab8500_charger *di; 18818c0984e5SSebastian Reichel 18828c0984e5SSebastian Reichel if (charger->psy->desc->type == POWER_SUPPLY_TYPE_MAINS) 18838c0984e5SSebastian Reichel di = to_ab8500_charger_ac_device_info(charger); 18848c0984e5SSebastian Reichel else if (charger->psy->desc->type == POWER_SUPPLY_TYPE_USB) 18858c0984e5SSebastian Reichel di = to_ab8500_charger_usb_device_info(charger); 18868c0984e5SSebastian Reichel else 18878c0984e5SSebastian Reichel return -ENXIO; 18888c0984e5SSebastian Reichel 188983e5aa77SLinus Walleij ret = ab8500_charger_set_output_curr(di, ich_out_ua); 18908c0984e5SSebastian Reichel if (ret) { 18918c0984e5SSebastian Reichel dev_err(di->dev, "%s " 18928c0984e5SSebastian Reichel "Failed to set ChOutputCurentLevel\n", 18938c0984e5SSebastian Reichel __func__); 18948c0984e5SSebastian Reichel return ret; 18958c0984e5SSebastian Reichel } 18968c0984e5SSebastian Reichel 18978c0984e5SSebastian Reichel /* Reset the main and usb drop input current measurement counter */ 18988c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 18998c0984e5SSebastian Reichel AB8500_CHARGER_CTRL, DROP_COUNT_RESET); 19008c0984e5SSebastian Reichel if (ret) { 19018c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 19028c0984e5SSebastian Reichel return ret; 19038c0984e5SSebastian Reichel } 19048c0984e5SSebastian Reichel 19058c0984e5SSebastian Reichel return ret; 19068c0984e5SSebastian Reichel } 19078c0984e5SSebastian Reichel 19088c0984e5SSebastian Reichel static int ab8500_charger_get_ext_psy_data(struct device *dev, void *data) 19098c0984e5SSebastian Reichel { 19108c0984e5SSebastian Reichel struct power_supply *psy; 19118c0984e5SSebastian Reichel struct power_supply *ext = dev_get_drvdata(dev); 19128c0984e5SSebastian Reichel const char **supplicants = (const char **)ext->supplied_to; 19138c0984e5SSebastian Reichel struct ab8500_charger *di; 19148c0984e5SSebastian Reichel union power_supply_propval ret; 19158c0984e5SSebastian Reichel int j; 19168c0984e5SSebastian Reichel struct ux500_charger *usb_chg; 19178c0984e5SSebastian Reichel 19188c0984e5SSebastian Reichel usb_chg = (struct ux500_charger *)data; 19198c0984e5SSebastian Reichel psy = usb_chg->psy; 19208c0984e5SSebastian Reichel 19218c0984e5SSebastian Reichel di = to_ab8500_charger_usb_device_info(usb_chg); 19228c0984e5SSebastian Reichel 19238c0984e5SSebastian Reichel /* For all psy where the driver name appears in any supplied_to */ 19248c0984e5SSebastian Reichel j = match_string(supplicants, ext->num_supplicants, psy->desc->name); 19258c0984e5SSebastian Reichel if (j < 0) 19268c0984e5SSebastian Reichel return 0; 19278c0984e5SSebastian Reichel 19288c0984e5SSebastian Reichel /* Go through all properties for the psy */ 19298c0984e5SSebastian Reichel for (j = 0; j < ext->desc->num_properties; j++) { 19308c0984e5SSebastian Reichel enum power_supply_property prop; 19318c0984e5SSebastian Reichel prop = ext->desc->properties[j]; 19328c0984e5SSebastian Reichel 19338c0984e5SSebastian Reichel if (power_supply_get_property(ext, prop, &ret)) 19348c0984e5SSebastian Reichel continue; 19358c0984e5SSebastian Reichel 19368c0984e5SSebastian Reichel switch (prop) { 19378c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_NOW: 19388c0984e5SSebastian Reichel switch (ext->desc->type) { 19398c0984e5SSebastian Reichel case POWER_SUPPLY_TYPE_BATTERY: 19408c0984e5SSebastian Reichel di->vbat = ret.intval / 1000; 19418c0984e5SSebastian Reichel break; 19428c0984e5SSebastian Reichel default: 19438c0984e5SSebastian Reichel break; 19448c0984e5SSebastian Reichel } 19458c0984e5SSebastian Reichel break; 19468c0984e5SSebastian Reichel default: 19478c0984e5SSebastian Reichel break; 19488c0984e5SSebastian Reichel } 19498c0984e5SSebastian Reichel } 19508c0984e5SSebastian Reichel return 0; 19518c0984e5SSebastian Reichel } 19528c0984e5SSebastian Reichel 19538c0984e5SSebastian Reichel /** 19548c0984e5SSebastian Reichel * ab8500_charger_check_vbat_work() - keep vbus current within spec 19558c0984e5SSebastian Reichel * @work pointer to the work_struct structure 19568c0984e5SSebastian Reichel * 19578c0984e5SSebastian Reichel * Due to a asic bug it is necessary to lower the input current to the vbus 19588c0984e5SSebastian Reichel * charger when charging with at some specific levels. This issue is only valid 19598c0984e5SSebastian Reichel * for below a certain battery voltage. This function makes sure that the 19608c0984e5SSebastian Reichel * the allowed current limit isn't exceeded. 19618c0984e5SSebastian Reichel */ 19628c0984e5SSebastian Reichel static void ab8500_charger_check_vbat_work(struct work_struct *work) 19638c0984e5SSebastian Reichel { 19648c0984e5SSebastian Reichel int t = 10; 19658c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 19668c0984e5SSebastian Reichel struct ab8500_charger, check_vbat_work.work); 19678c0984e5SSebastian Reichel 19688c0984e5SSebastian Reichel class_for_each_device(power_supply_class, NULL, 19698c0984e5SSebastian Reichel di->usb_chg.psy, ab8500_charger_get_ext_psy_data); 19708c0984e5SSebastian Reichel 19718c0984e5SSebastian Reichel /* First run old_vbat is 0. */ 19728c0984e5SSebastian Reichel if (di->old_vbat == 0) 19738c0984e5SSebastian Reichel di->old_vbat = di->vbat; 19748c0984e5SSebastian Reichel 19758c0984e5SSebastian Reichel if (!((di->old_vbat <= VBAT_TRESH_IP_CUR_RED && 19768c0984e5SSebastian Reichel di->vbat <= VBAT_TRESH_IP_CUR_RED) || 19778c0984e5SSebastian Reichel (di->old_vbat > VBAT_TRESH_IP_CUR_RED && 19788c0984e5SSebastian Reichel di->vbat > VBAT_TRESH_IP_CUR_RED))) { 19798c0984e5SSebastian Reichel 19808c0984e5SSebastian Reichel dev_dbg(di->dev, "Vbat did cross threshold, curr: %d, new: %d," 198183e5aa77SLinus Walleij " old: %d\n", di->max_usb_in_curr.usb_type_max_ua, 19828c0984e5SSebastian Reichel di->vbat, di->old_vbat); 19838c0984e5SSebastian Reichel ab8500_charger_set_vbus_in_curr(di, 198483e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua); 19858c0984e5SSebastian Reichel power_supply_changed(di->usb_chg.psy); 19868c0984e5SSebastian Reichel } 19878c0984e5SSebastian Reichel 19888c0984e5SSebastian Reichel di->old_vbat = di->vbat; 19898c0984e5SSebastian Reichel 19908c0984e5SSebastian Reichel /* 19918c0984e5SSebastian Reichel * No need to check the battery voltage every second when not close to 19928c0984e5SSebastian Reichel * the threshold. 19938c0984e5SSebastian Reichel */ 19948c0984e5SSebastian Reichel if (di->vbat < (VBAT_TRESH_IP_CUR_RED + 100) && 19958c0984e5SSebastian Reichel (di->vbat > (VBAT_TRESH_IP_CUR_RED - 100))) 19968c0984e5SSebastian Reichel t = 1; 19978c0984e5SSebastian Reichel 19988c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->check_vbat_work, t * HZ); 19998c0984e5SSebastian Reichel } 20008c0984e5SSebastian Reichel 20018c0984e5SSebastian Reichel /** 20028c0984e5SSebastian Reichel * ab8500_charger_check_hw_failure_work() - check main charger failure 20038c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 20048c0984e5SSebastian Reichel * 20058c0984e5SSebastian Reichel * Work queue function for checking the main charger status 20068c0984e5SSebastian Reichel */ 20078c0984e5SSebastian Reichel static void ab8500_charger_check_hw_failure_work(struct work_struct *work) 20088c0984e5SSebastian Reichel { 20098c0984e5SSebastian Reichel int ret; 20108c0984e5SSebastian Reichel u8 reg_value; 20118c0984e5SSebastian Reichel 20128c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 20138c0984e5SSebastian Reichel struct ab8500_charger, check_hw_failure_work.work); 20148c0984e5SSebastian Reichel 20158c0984e5SSebastian Reichel /* Check if the status bits for HW failure is still active */ 20168c0984e5SSebastian Reichel if (di->flags.mainextchnotok) { 20178c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 20188c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_STATUS2_REG, ®_value); 20198c0984e5SSebastian Reichel if (ret < 0) { 20208c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 20218c0984e5SSebastian Reichel return; 20228c0984e5SSebastian Reichel } 20238c0984e5SSebastian Reichel if (!(reg_value & MAIN_CH_NOK)) { 20248c0984e5SSebastian Reichel di->flags.mainextchnotok = false; 20258c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 20268c0984e5SSebastian Reichel } 20278c0984e5SSebastian Reichel } 20288c0984e5SSebastian Reichel if (di->flags.vbus_ovv) { 20298c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 20308c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG, 20318c0984e5SSebastian Reichel ®_value); 20328c0984e5SSebastian Reichel if (ret < 0) { 20338c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 20348c0984e5SSebastian Reichel return; 20358c0984e5SSebastian Reichel } 20368c0984e5SSebastian Reichel if (!(reg_value & VBUS_OVV_TH)) { 20378c0984e5SSebastian Reichel di->flags.vbus_ovv = false; 20388c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 20398c0984e5SSebastian Reichel } 20408c0984e5SSebastian Reichel } 20418c0984e5SSebastian Reichel /* If we still have a failure, schedule a new check */ 20428c0984e5SSebastian Reichel if (di->flags.mainextchnotok || di->flags.vbus_ovv) { 20438c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 20448c0984e5SSebastian Reichel &di->check_hw_failure_work, round_jiffies(HZ)); 20458c0984e5SSebastian Reichel } 20468c0984e5SSebastian Reichel } 20478c0984e5SSebastian Reichel 20488c0984e5SSebastian Reichel /** 20498c0984e5SSebastian Reichel * ab8500_charger_kick_watchdog_work() - kick the watchdog 20508c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 20518c0984e5SSebastian Reichel * 20528c0984e5SSebastian Reichel * Work queue function for kicking the charger watchdog. 20538c0984e5SSebastian Reichel * 20548c0984e5SSebastian Reichel * For ABB revision 1.0 and 1.1 there is a bug in the watchdog 2055ddb74e98SAshish Chavan * logic. That means we have to continuously kick the charger 20568c0984e5SSebastian Reichel * watchdog even when no charger is connected. This is only 20578c0984e5SSebastian Reichel * valid once the AC charger has been enabled. This is 20588c0984e5SSebastian Reichel * a bug that is not handled by the algorithm and the 20598c0984e5SSebastian Reichel * watchdog have to be kicked by the charger driver 20608c0984e5SSebastian Reichel * when the AC charger is disabled 20618c0984e5SSebastian Reichel */ 20628c0984e5SSebastian Reichel static void ab8500_charger_kick_watchdog_work(struct work_struct *work) 20638c0984e5SSebastian Reichel { 20648c0984e5SSebastian Reichel int ret; 20658c0984e5SSebastian Reichel 20668c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 20678c0984e5SSebastian Reichel struct ab8500_charger, kick_wd_work.work); 20688c0984e5SSebastian Reichel 20698c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 20708c0984e5SSebastian Reichel AB8500_CHARG_WD_CTRL, CHARG_WD_KICK); 20718c0984e5SSebastian Reichel if (ret) 20728c0984e5SSebastian Reichel dev_err(di->dev, "Failed to kick WD!\n"); 20738c0984e5SSebastian Reichel 20748c0984e5SSebastian Reichel /* Schedule a new watchdog kick */ 20758c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 20768c0984e5SSebastian Reichel &di->kick_wd_work, round_jiffies(WD_KICK_INTERVAL)); 20778c0984e5SSebastian Reichel } 20788c0984e5SSebastian Reichel 20798c0984e5SSebastian Reichel /** 20808c0984e5SSebastian Reichel * ab8500_charger_ac_work() - work to get and set main charger status 20818c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 20828c0984e5SSebastian Reichel * 20838c0984e5SSebastian Reichel * Work queue function for checking the main charger status 20848c0984e5SSebastian Reichel */ 20858c0984e5SSebastian Reichel static void ab8500_charger_ac_work(struct work_struct *work) 20868c0984e5SSebastian Reichel { 20878c0984e5SSebastian Reichel int ret; 20888c0984e5SSebastian Reichel 20898c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 20908c0984e5SSebastian Reichel struct ab8500_charger, ac_work); 20918c0984e5SSebastian Reichel 20928c0984e5SSebastian Reichel /* 20938c0984e5SSebastian Reichel * Since we can't be sure that the events are received 20948c0984e5SSebastian Reichel * synchronously, we have the check if the main charger is 20958c0984e5SSebastian Reichel * connected by reading the status register 20968c0984e5SSebastian Reichel */ 20978c0984e5SSebastian Reichel ret = ab8500_charger_detect_chargers(di, false); 20988c0984e5SSebastian Reichel if (ret < 0) 20998c0984e5SSebastian Reichel return; 21008c0984e5SSebastian Reichel 21018c0984e5SSebastian Reichel if (ret & AC_PW_CONN) { 21028c0984e5SSebastian Reichel di->ac.charger_connected = 1; 21038c0984e5SSebastian Reichel di->ac_conn = true; 21048c0984e5SSebastian Reichel } else { 21058c0984e5SSebastian Reichel di->ac.charger_connected = 0; 21068c0984e5SSebastian Reichel } 21078c0984e5SSebastian Reichel 21088c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 21098c0984e5SSebastian Reichel sysfs_notify(&di->ac_chg.psy->dev.kobj, NULL, "present"); 21108c0984e5SSebastian Reichel } 21118c0984e5SSebastian Reichel 21128c0984e5SSebastian Reichel static void ab8500_charger_usb_attached_work(struct work_struct *work) 21138c0984e5SSebastian Reichel { 21148c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 21158c0984e5SSebastian Reichel struct ab8500_charger, 21168c0984e5SSebastian Reichel usb_charger_attached_work.work); 21178c0984e5SSebastian Reichel int usbch = (USB_CH_VBUSDROP | USB_CH_VBUSDETDBNC); 21188c0984e5SSebastian Reichel int ret, i; 21198c0984e5SSebastian Reichel u8 statval; 21208c0984e5SSebastian Reichel 21218c0984e5SSebastian Reichel for (i = 0; i < 10; i++) { 21228c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 21238c0984e5SSebastian Reichel AB8500_CHARGER, 21248c0984e5SSebastian Reichel AB8500_CH_USBCH_STAT1_REG, 21258c0984e5SSebastian Reichel &statval); 21268c0984e5SSebastian Reichel if (ret < 0) { 21278c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 read failed %d\n", __LINE__); 21288c0984e5SSebastian Reichel goto reschedule; 21298c0984e5SSebastian Reichel } 21308c0984e5SSebastian Reichel if ((statval & usbch) != usbch) 21318c0984e5SSebastian Reichel goto reschedule; 21328c0984e5SSebastian Reichel 21338c0984e5SSebastian Reichel msleep(CHARGER_STATUS_POLL); 21348c0984e5SSebastian Reichel } 21358c0984e5SSebastian Reichel 21368c0984e5SSebastian Reichel ab8500_charger_usb_en(&di->usb_chg, 0, 0, 0); 21378c0984e5SSebastian Reichel 21388c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 21398c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 21408c0984e5SSebastian Reichel 21418c0984e5SSebastian Reichel return; 21428c0984e5SSebastian Reichel 21438c0984e5SSebastian Reichel reschedule: 21448c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 21458c0984e5SSebastian Reichel &di->usb_charger_attached_work, 21468c0984e5SSebastian Reichel HZ); 21478c0984e5SSebastian Reichel } 21488c0984e5SSebastian Reichel 21498c0984e5SSebastian Reichel static void ab8500_charger_ac_attached_work(struct work_struct *work) 21508c0984e5SSebastian Reichel { 21518c0984e5SSebastian Reichel 21528c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 21538c0984e5SSebastian Reichel struct ab8500_charger, 21548c0984e5SSebastian Reichel ac_charger_attached_work.work); 21558c0984e5SSebastian Reichel int mainch = (MAIN_CH_STATUS2_MAINCHGDROP | 21568c0984e5SSebastian Reichel MAIN_CH_STATUS2_MAINCHARGERDETDBNC); 21578c0984e5SSebastian Reichel int ret, i; 21588c0984e5SSebastian Reichel u8 statval; 21598c0984e5SSebastian Reichel 21608c0984e5SSebastian Reichel for (i = 0; i < 10; i++) { 21618c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 21628c0984e5SSebastian Reichel AB8500_CHARGER, 21638c0984e5SSebastian Reichel AB8500_CH_STATUS2_REG, 21648c0984e5SSebastian Reichel &statval); 21658c0984e5SSebastian Reichel if (ret < 0) { 21668c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 read failed %d\n", __LINE__); 21678c0984e5SSebastian Reichel goto reschedule; 21688c0984e5SSebastian Reichel } 21698c0984e5SSebastian Reichel 21708c0984e5SSebastian Reichel if ((statval & mainch) != mainch) 21718c0984e5SSebastian Reichel goto reschedule; 21728c0984e5SSebastian Reichel 21738c0984e5SSebastian Reichel msleep(CHARGER_STATUS_POLL); 21748c0984e5SSebastian Reichel } 21758c0984e5SSebastian Reichel 21768c0984e5SSebastian Reichel ab8500_charger_ac_en(&di->ac_chg, 0, 0, 0); 21778c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->ac_work); 21788c0984e5SSebastian Reichel 21798c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 21808c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 21818c0984e5SSebastian Reichel 21828c0984e5SSebastian Reichel return; 21838c0984e5SSebastian Reichel 21848c0984e5SSebastian Reichel reschedule: 21858c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 21868c0984e5SSebastian Reichel &di->ac_charger_attached_work, 21878c0984e5SSebastian Reichel HZ); 21888c0984e5SSebastian Reichel } 21898c0984e5SSebastian Reichel 21908c0984e5SSebastian Reichel /** 21918c0984e5SSebastian Reichel * ab8500_charger_detect_usb_type_work() - work to detect USB type 21928c0984e5SSebastian Reichel * @work: Pointer to the work_struct structure 21938c0984e5SSebastian Reichel * 21948c0984e5SSebastian Reichel * Detect the type of USB plugged 21958c0984e5SSebastian Reichel */ 21968c0984e5SSebastian Reichel static void ab8500_charger_detect_usb_type_work(struct work_struct *work) 21978c0984e5SSebastian Reichel { 21988c0984e5SSebastian Reichel int ret; 21998c0984e5SSebastian Reichel 22008c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 22018c0984e5SSebastian Reichel struct ab8500_charger, detect_usb_type_work); 22028c0984e5SSebastian Reichel 22038c0984e5SSebastian Reichel /* 22048c0984e5SSebastian Reichel * Since we can't be sure that the events are received 22058c0984e5SSebastian Reichel * synchronously, we have the check if is 22068c0984e5SSebastian Reichel * connected by reading the status register 22078c0984e5SSebastian Reichel */ 22088c0984e5SSebastian Reichel ret = ab8500_charger_detect_chargers(di, false); 22098c0984e5SSebastian Reichel if (ret < 0) 22108c0984e5SSebastian Reichel return; 22118c0984e5SSebastian Reichel 22128c0984e5SSebastian Reichel if (!(ret & USB_PW_CONN)) { 22138c0984e5SSebastian Reichel dev_dbg(di->dev, "%s di->vbus_detected = false\n", __func__); 22148c0984e5SSebastian Reichel di->vbus_detected = false; 22158c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, false); 22168c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 22178c0984e5SSebastian Reichel } else { 22188c0984e5SSebastian Reichel dev_dbg(di->dev, "%s di->vbus_detected = true\n", __func__); 22198c0984e5SSebastian Reichel di->vbus_detected = true; 22208c0984e5SSebastian Reichel 22218c0984e5SSebastian Reichel if (is_ab8500_1p1_or_earlier(di->parent)) { 22228c0984e5SSebastian Reichel ret = ab8500_charger_detect_usb_type(di); 22238c0984e5SSebastian Reichel if (!ret) { 22248c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, true); 22258c0984e5SSebastian Reichel ab8500_power_supply_changed(di, 22268c0984e5SSebastian Reichel di->usb_chg.psy); 22278c0984e5SSebastian Reichel } 22288c0984e5SSebastian Reichel } else { 22298c0984e5SSebastian Reichel /* 22308c0984e5SSebastian Reichel * For ABB cut2.0 and onwards we have an IRQ, 22318c0984e5SSebastian Reichel * USB_LINK_STATUS that will be triggered when the USB 22328c0984e5SSebastian Reichel * link status changes. The exception is USB connected 22338c0984e5SSebastian Reichel * during startup. Then we don't get a 22348c0984e5SSebastian Reichel * USB_LINK_STATUS IRQ 22358c0984e5SSebastian Reichel */ 22368c0984e5SSebastian Reichel if (di->vbus_detected_start) { 22378c0984e5SSebastian Reichel di->vbus_detected_start = false; 22388c0984e5SSebastian Reichel ret = ab8500_charger_detect_usb_type(di); 22398c0984e5SSebastian Reichel if (!ret) { 22408c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, 22418c0984e5SSebastian Reichel true); 22428c0984e5SSebastian Reichel ab8500_power_supply_changed(di, 22438c0984e5SSebastian Reichel di->usb_chg.psy); 22448c0984e5SSebastian Reichel } 22458c0984e5SSebastian Reichel } 22468c0984e5SSebastian Reichel } 22478c0984e5SSebastian Reichel } 22488c0984e5SSebastian Reichel } 22498c0984e5SSebastian Reichel 22508c0984e5SSebastian Reichel /** 22518c0984e5SSebastian Reichel * ab8500_charger_usb_link_attach_work() - work to detect USB type 22528c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 22538c0984e5SSebastian Reichel * 22548c0984e5SSebastian Reichel * Detect the type of USB plugged 22558c0984e5SSebastian Reichel */ 22568c0984e5SSebastian Reichel static void ab8500_charger_usb_link_attach_work(struct work_struct *work) 22578c0984e5SSebastian Reichel { 22588c0984e5SSebastian Reichel struct ab8500_charger *di = 22598c0984e5SSebastian Reichel container_of(work, struct ab8500_charger, attach_work.work); 22608c0984e5SSebastian Reichel int ret; 22618c0984e5SSebastian Reichel 22628c0984e5SSebastian Reichel /* Update maximum input current if USB enumeration is not detected */ 22638c0984e5SSebastian Reichel if (!di->usb.charger_online) { 22648c0984e5SSebastian Reichel ret = ab8500_charger_set_vbus_in_curr(di, 226583e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua); 22668c0984e5SSebastian Reichel if (ret) 22678c0984e5SSebastian Reichel return; 22688c0984e5SSebastian Reichel } 22698c0984e5SSebastian Reichel 22708c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, true); 22718c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 22728c0984e5SSebastian Reichel } 22738c0984e5SSebastian Reichel 22748c0984e5SSebastian Reichel /** 22758c0984e5SSebastian Reichel * ab8500_charger_usb_link_status_work() - work to detect USB type 22768c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 22778c0984e5SSebastian Reichel * 22788c0984e5SSebastian Reichel * Detect the type of USB plugged 22798c0984e5SSebastian Reichel */ 22808c0984e5SSebastian Reichel static void ab8500_charger_usb_link_status_work(struct work_struct *work) 22818c0984e5SSebastian Reichel { 22828c0984e5SSebastian Reichel int detected_chargers; 22838c0984e5SSebastian Reichel int ret; 22848c0984e5SSebastian Reichel u8 val; 22858c0984e5SSebastian Reichel u8 link_status; 22868c0984e5SSebastian Reichel 22878c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 22888c0984e5SSebastian Reichel struct ab8500_charger, usb_link_status_work); 22898c0984e5SSebastian Reichel 22908c0984e5SSebastian Reichel /* 22918c0984e5SSebastian Reichel * Since we can't be sure that the events are received 22928c0984e5SSebastian Reichel * synchronously, we have the check if is 22938c0984e5SSebastian Reichel * connected by reading the status register 22948c0984e5SSebastian Reichel */ 22958c0984e5SSebastian Reichel detected_chargers = ab8500_charger_detect_chargers(di, false); 22968c0984e5SSebastian Reichel if (detected_chargers < 0) 22978c0984e5SSebastian Reichel return; 22988c0984e5SSebastian Reichel 22998c0984e5SSebastian Reichel /* 23008c0984e5SSebastian Reichel * Some chargers that breaks the USB spec is 23018c0984e5SSebastian Reichel * identified as invalid by AB8500 and it refuse 23028c0984e5SSebastian Reichel * to start the charging process. but by jumping 2303ddb74e98SAshish Chavan * through a few hoops it can be forced to start. 23048c0984e5SSebastian Reichel */ 23058c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 23068c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_USB, 23078c0984e5SSebastian Reichel AB8500_USB_LINE_STAT_REG, &val); 23088c0984e5SSebastian Reichel else 23098c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_USB, 23108c0984e5SSebastian Reichel AB8500_USB_LINK1_STAT_REG, &val); 23118c0984e5SSebastian Reichel 23128c0984e5SSebastian Reichel if (ret >= 0) 23138c0984e5SSebastian Reichel dev_dbg(di->dev, "UsbLineStatus register = 0x%02x\n", val); 23148c0984e5SSebastian Reichel else 23158c0984e5SSebastian Reichel dev_dbg(di->dev, "Error reading USB link status\n"); 23168c0984e5SSebastian Reichel 23178c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 23188c0984e5SSebastian Reichel link_status = AB8500_USB_LINK_STATUS; 23198c0984e5SSebastian Reichel else 23208c0984e5SSebastian Reichel link_status = AB8505_USB_LINK_STATUS; 23218c0984e5SSebastian Reichel 23228c0984e5SSebastian Reichel if (detected_chargers & USB_PW_CONN) { 23238c0984e5SSebastian Reichel if (((val & link_status) >> USB_LINK_STATUS_SHIFT) == 23248c0984e5SSebastian Reichel USB_STAT_NOT_VALID_LINK && 23258c0984e5SSebastian Reichel di->invalid_charger_detect_state == 0) { 23268c0984e5SSebastian Reichel dev_dbg(di->dev, 23278c0984e5SSebastian Reichel "Invalid charger detected, state= 0\n"); 23288c0984e5SSebastian Reichel /*Enable charger*/ 23298c0984e5SSebastian Reichel abx500_mask_and_set_register_interruptible(di->dev, 23308c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_USBCH_CTRL1_REG, 23318c0984e5SSebastian Reichel USB_CH_ENA, USB_CH_ENA); 23328c0984e5SSebastian Reichel /*Enable charger detection*/ 23338c0984e5SSebastian Reichel abx500_mask_and_set_register_interruptible(di->dev, 23348c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINE_CTRL2_REG, 23358c0984e5SSebastian Reichel USB_CH_DET, USB_CH_DET); 23368c0984e5SSebastian Reichel di->invalid_charger_detect_state = 1; 23378c0984e5SSebastian Reichel /*exit and wait for new link status interrupt.*/ 23388c0984e5SSebastian Reichel return; 23398c0984e5SSebastian Reichel 23408c0984e5SSebastian Reichel } 23418c0984e5SSebastian Reichel if (di->invalid_charger_detect_state == 1) { 23428c0984e5SSebastian Reichel dev_dbg(di->dev, 23438c0984e5SSebastian Reichel "Invalid charger detected, state= 1\n"); 23448c0984e5SSebastian Reichel /*Stop charger detection*/ 23458c0984e5SSebastian Reichel abx500_mask_and_set_register_interruptible(di->dev, 23468c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINE_CTRL2_REG, 23478c0984e5SSebastian Reichel USB_CH_DET, 0x00); 23488c0984e5SSebastian Reichel /*Check link status*/ 23498c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 23508c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 23518c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINE_STAT_REG, 23528c0984e5SSebastian Reichel &val); 23538c0984e5SSebastian Reichel else 23548c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 23558c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINK1_STAT_REG, 23568c0984e5SSebastian Reichel &val); 23578c0984e5SSebastian Reichel 23588c0984e5SSebastian Reichel dev_dbg(di->dev, "USB link status= 0x%02x\n", 23598c0984e5SSebastian Reichel (val & link_status) >> USB_LINK_STATUS_SHIFT); 23608c0984e5SSebastian Reichel di->invalid_charger_detect_state = 2; 23618c0984e5SSebastian Reichel } 23628c0984e5SSebastian Reichel } else { 23638c0984e5SSebastian Reichel di->invalid_charger_detect_state = 0; 23648c0984e5SSebastian Reichel } 23658c0984e5SSebastian Reichel 23668c0984e5SSebastian Reichel if (!(detected_chargers & USB_PW_CONN)) { 23678c0984e5SSebastian Reichel di->vbus_detected = false; 23688c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, false); 23698c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 23708c0984e5SSebastian Reichel return; 23718c0984e5SSebastian Reichel } 23728c0984e5SSebastian Reichel 23738c0984e5SSebastian Reichel dev_dbg(di->dev,"%s di->vbus_detected = true\n",__func__); 23748c0984e5SSebastian Reichel di->vbus_detected = true; 23758c0984e5SSebastian Reichel ret = ab8500_charger_read_usb_type(di); 23768c0984e5SSebastian Reichel if (ret) { 23778c0984e5SSebastian Reichel if (ret == -ENXIO) { 23788c0984e5SSebastian Reichel /* No valid charger type detected */ 23798c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, false); 23808c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 23818c0984e5SSebastian Reichel } 23828c0984e5SSebastian Reichel return; 23838c0984e5SSebastian Reichel } 23848c0984e5SSebastian Reichel 23858c0984e5SSebastian Reichel if (di->usb_device_is_unrecognised) { 23868c0984e5SSebastian Reichel dev_dbg(di->dev, 23878c0984e5SSebastian Reichel "Potential Legacy Charger device. " 23888c0984e5SSebastian Reichel "Delay work for %d msec for USB enum " 23898c0984e5SSebastian Reichel "to finish", 23908c0984e5SSebastian Reichel WAIT_ACA_RID_ENUMERATION); 23918c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 23928c0984e5SSebastian Reichel &di->attach_work, 23938c0984e5SSebastian Reichel msecs_to_jiffies(WAIT_ACA_RID_ENUMERATION)); 23948c0984e5SSebastian Reichel } else if (di->is_aca_rid == 1) { 23958c0984e5SSebastian Reichel /* Only wait once */ 23968c0984e5SSebastian Reichel di->is_aca_rid++; 23978c0984e5SSebastian Reichel dev_dbg(di->dev, 23988c0984e5SSebastian Reichel "%s Wait %d msec for USB enum to finish", 23998c0984e5SSebastian Reichel __func__, WAIT_ACA_RID_ENUMERATION); 24008c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 24018c0984e5SSebastian Reichel &di->attach_work, 24028c0984e5SSebastian Reichel msecs_to_jiffies(WAIT_ACA_RID_ENUMERATION)); 24038c0984e5SSebastian Reichel } else { 24048c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 24058c0984e5SSebastian Reichel &di->attach_work, 24068c0984e5SSebastian Reichel 0); 24078c0984e5SSebastian Reichel } 24088c0984e5SSebastian Reichel } 24098c0984e5SSebastian Reichel 24108c0984e5SSebastian Reichel static void ab8500_charger_usb_state_changed_work(struct work_struct *work) 24118c0984e5SSebastian Reichel { 24128c0984e5SSebastian Reichel int ret; 24138c0984e5SSebastian Reichel unsigned long flags; 24148c0984e5SSebastian Reichel 24158c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 24168c0984e5SSebastian Reichel struct ab8500_charger, usb_state_changed_work.work); 24178c0984e5SSebastian Reichel 24188c0984e5SSebastian Reichel if (!di->vbus_detected) { 24198c0984e5SSebastian Reichel dev_dbg(di->dev, 24208c0984e5SSebastian Reichel "%s !di->vbus_detected\n", 24218c0984e5SSebastian Reichel __func__); 24228c0984e5SSebastian Reichel return; 24238c0984e5SSebastian Reichel } 24248c0984e5SSebastian Reichel 24258c0984e5SSebastian Reichel spin_lock_irqsave(&di->usb_state.usb_lock, flags); 24268c0984e5SSebastian Reichel di->usb_state.state = di->usb_state.state_tmp; 242783e5aa77SLinus Walleij di->usb_state.usb_current_ua = di->usb_state.usb_current_tmp_ua; 24288c0984e5SSebastian Reichel spin_unlock_irqrestore(&di->usb_state.usb_lock, flags); 24298c0984e5SSebastian Reichel 243083e5aa77SLinus Walleij dev_dbg(di->dev, "%s USB state: 0x%02x uA: %d\n", 243183e5aa77SLinus Walleij __func__, di->usb_state.state, di->usb_state.usb_current_ua); 24328c0984e5SSebastian Reichel 24338c0984e5SSebastian Reichel switch (di->usb_state.state) { 24348c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_RESET_HS: 24358c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_RESET_FS: 24368c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_SUSPEND: 24378c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_MAX: 24388c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, false); 24398c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 24408c0984e5SSebastian Reichel break; 24418c0984e5SSebastian Reichel 24428c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_RESUME: 24438c0984e5SSebastian Reichel /* 24448c0984e5SSebastian Reichel * when suspend->resume there should be delay 24458c0984e5SSebastian Reichel * of 1sec for enabling charging 24468c0984e5SSebastian Reichel */ 24478c0984e5SSebastian Reichel msleep(1000); 2448df561f66SGustavo A. R. Silva fallthrough; 24498c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_CONFIGURED: 24508c0984e5SSebastian Reichel /* 24518c0984e5SSebastian Reichel * USB is configured, enable charging with the charging 24528c0984e5SSebastian Reichel * input current obtained from USB driver 24538c0984e5SSebastian Reichel */ 24548c0984e5SSebastian Reichel if (!ab8500_charger_get_usb_cur(di)) { 24558c0984e5SSebastian Reichel /* Update maximum input current */ 24568c0984e5SSebastian Reichel ret = ab8500_charger_set_vbus_in_curr(di, 245783e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua); 24588c0984e5SSebastian Reichel if (ret) 24598c0984e5SSebastian Reichel return; 24608c0984e5SSebastian Reichel 24618c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, true); 24628c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 24638c0984e5SSebastian Reichel } 24648c0984e5SSebastian Reichel break; 24658c0984e5SSebastian Reichel 24668c0984e5SSebastian Reichel default: 24678c0984e5SSebastian Reichel break; 2468e15c54d2SMa Feng } 24698c0984e5SSebastian Reichel } 24708c0984e5SSebastian Reichel 24718c0984e5SSebastian Reichel /** 24728c0984e5SSebastian Reichel * ab8500_charger_check_usbchargernotok_work() - check USB chg not ok status 24738c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 24748c0984e5SSebastian Reichel * 24758c0984e5SSebastian Reichel * Work queue function for checking the USB charger Not OK status 24768c0984e5SSebastian Reichel */ 24778c0984e5SSebastian Reichel static void ab8500_charger_check_usbchargernotok_work(struct work_struct *work) 24788c0984e5SSebastian Reichel { 24798c0984e5SSebastian Reichel int ret; 24808c0984e5SSebastian Reichel u8 reg_value; 24818c0984e5SSebastian Reichel bool prev_status; 24828c0984e5SSebastian Reichel 24838c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 24848c0984e5SSebastian Reichel struct ab8500_charger, check_usbchgnotok_work.work); 24858c0984e5SSebastian Reichel 24868c0984e5SSebastian Reichel /* Check if the status bit for usbchargernotok is still active */ 24878c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 24888c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG, ®_value); 24898c0984e5SSebastian Reichel if (ret < 0) { 24908c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 24918c0984e5SSebastian Reichel return; 24928c0984e5SSebastian Reichel } 24938c0984e5SSebastian Reichel prev_status = di->flags.usbchargernotok; 24948c0984e5SSebastian Reichel 24958c0984e5SSebastian Reichel if (reg_value & VBUS_CH_NOK) { 24968c0984e5SSebastian Reichel di->flags.usbchargernotok = true; 24978c0984e5SSebastian Reichel /* Check again in 1sec */ 24988c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 24998c0984e5SSebastian Reichel &di->check_usbchgnotok_work, HZ); 25008c0984e5SSebastian Reichel } else { 25018c0984e5SSebastian Reichel di->flags.usbchargernotok = false; 25028c0984e5SSebastian Reichel di->flags.vbus_collapse = false; 25038c0984e5SSebastian Reichel } 25048c0984e5SSebastian Reichel 25058c0984e5SSebastian Reichel if (prev_status != di->flags.usbchargernotok) 25068c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 25078c0984e5SSebastian Reichel } 25088c0984e5SSebastian Reichel 25098c0984e5SSebastian Reichel /** 25108c0984e5SSebastian Reichel * ab8500_charger_check_main_thermal_prot_work() - check main thermal status 25118c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 25128c0984e5SSebastian Reichel * 25138c0984e5SSebastian Reichel * Work queue function for checking the Main thermal prot status 25148c0984e5SSebastian Reichel */ 25158c0984e5SSebastian Reichel static void ab8500_charger_check_main_thermal_prot_work( 25168c0984e5SSebastian Reichel struct work_struct *work) 25178c0984e5SSebastian Reichel { 25188c0984e5SSebastian Reichel int ret; 25198c0984e5SSebastian Reichel u8 reg_value; 25208c0984e5SSebastian Reichel 25218c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 25228c0984e5SSebastian Reichel struct ab8500_charger, check_main_thermal_prot_work); 25238c0984e5SSebastian Reichel 25248c0984e5SSebastian Reichel /* Check if the status bit for main_thermal_prot is still active */ 25258c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 25268c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_STATUS2_REG, ®_value); 25278c0984e5SSebastian Reichel if (ret < 0) { 25288c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 25298c0984e5SSebastian Reichel return; 25308c0984e5SSebastian Reichel } 25318c0984e5SSebastian Reichel if (reg_value & MAIN_CH_TH_PROT) 25328c0984e5SSebastian Reichel di->flags.main_thermal_prot = true; 25338c0984e5SSebastian Reichel else 25348c0984e5SSebastian Reichel di->flags.main_thermal_prot = false; 25358c0984e5SSebastian Reichel 25368c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 25378c0984e5SSebastian Reichel } 25388c0984e5SSebastian Reichel 25398c0984e5SSebastian Reichel /** 25408c0984e5SSebastian Reichel * ab8500_charger_check_usb_thermal_prot_work() - check usb thermal status 25418c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 25428c0984e5SSebastian Reichel * 25438c0984e5SSebastian Reichel * Work queue function for checking the USB thermal prot status 25448c0984e5SSebastian Reichel */ 25458c0984e5SSebastian Reichel static void ab8500_charger_check_usb_thermal_prot_work( 25468c0984e5SSebastian Reichel struct work_struct *work) 25478c0984e5SSebastian Reichel { 25488c0984e5SSebastian Reichel int ret; 25498c0984e5SSebastian Reichel u8 reg_value; 25508c0984e5SSebastian Reichel 25518c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 25528c0984e5SSebastian Reichel struct ab8500_charger, check_usb_thermal_prot_work); 25538c0984e5SSebastian Reichel 25548c0984e5SSebastian Reichel /* Check if the status bit for usb_thermal_prot is still active */ 25558c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 25568c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG, ®_value); 25578c0984e5SSebastian Reichel if (ret < 0) { 25588c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 25598c0984e5SSebastian Reichel return; 25608c0984e5SSebastian Reichel } 25618c0984e5SSebastian Reichel if (reg_value & USB_CH_TH_PROT) 25628c0984e5SSebastian Reichel di->flags.usb_thermal_prot = true; 25638c0984e5SSebastian Reichel else 25648c0984e5SSebastian Reichel di->flags.usb_thermal_prot = false; 25658c0984e5SSebastian Reichel 25668c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 25678c0984e5SSebastian Reichel } 25688c0984e5SSebastian Reichel 25698c0984e5SSebastian Reichel /** 25708c0984e5SSebastian Reichel * ab8500_charger_mainchunplugdet_handler() - main charger unplugged 25718c0984e5SSebastian Reichel * @irq: interrupt number 25728c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 25738c0984e5SSebastian Reichel * 25748c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 25758c0984e5SSebastian Reichel */ 25768c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_mainchunplugdet_handler(int irq, void *_di) 25778c0984e5SSebastian Reichel { 25788c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 25798c0984e5SSebastian Reichel 25808c0984e5SSebastian Reichel dev_dbg(di->dev, "Main charger unplugged\n"); 25818c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->ac_work); 25828c0984e5SSebastian Reichel 25838c0984e5SSebastian Reichel cancel_delayed_work_sync(&di->ac_charger_attached_work); 25848c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 25858c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 25868c0984e5SSebastian Reichel 25878c0984e5SSebastian Reichel return IRQ_HANDLED; 25888c0984e5SSebastian Reichel } 25898c0984e5SSebastian Reichel 25908c0984e5SSebastian Reichel /** 25918c0984e5SSebastian Reichel * ab8500_charger_mainchplugdet_handler() - main charger plugged 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_mainchplugdet_handler(int irq, void *_di) 25988c0984e5SSebastian Reichel { 25998c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 26008c0984e5SSebastian Reichel 26018c0984e5SSebastian Reichel dev_dbg(di->dev, "Main charger plugged\n"); 26028c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->ac_work); 26038c0984e5SSebastian Reichel 26048c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 26058c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 26068c0984e5SSebastian Reichel 26078c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 26088c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 26098c0984e5SSebastian Reichel &di->ac_charger_attached_work, 26108c0984e5SSebastian Reichel HZ); 26118c0984e5SSebastian Reichel return IRQ_HANDLED; 26128c0984e5SSebastian Reichel } 26138c0984e5SSebastian Reichel 26148c0984e5SSebastian Reichel /** 26158c0984e5SSebastian Reichel * ab8500_charger_mainextchnotok_handler() - main charger not ok 26168c0984e5SSebastian Reichel * @irq: interrupt number 26178c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 26188c0984e5SSebastian Reichel * 26198c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 26208c0984e5SSebastian Reichel */ 26218c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_mainextchnotok_handler(int irq, void *_di) 26228c0984e5SSebastian Reichel { 26238c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 26248c0984e5SSebastian Reichel 26258c0984e5SSebastian Reichel dev_dbg(di->dev, "Main charger not ok\n"); 26268c0984e5SSebastian Reichel di->flags.mainextchnotok = true; 26278c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 26288c0984e5SSebastian Reichel 26298c0984e5SSebastian Reichel /* Schedule a new HW failure check */ 26308c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->check_hw_failure_work, 0); 26318c0984e5SSebastian Reichel 26328c0984e5SSebastian Reichel return IRQ_HANDLED; 26338c0984e5SSebastian Reichel } 26348c0984e5SSebastian Reichel 26358c0984e5SSebastian Reichel /** 26368c0984e5SSebastian Reichel * ab8500_charger_mainchthprotr_handler() - Die temp is above main charger 26378c0984e5SSebastian Reichel * thermal protection threshold 26388c0984e5SSebastian Reichel * @irq: interrupt number 26398c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 26408c0984e5SSebastian Reichel * 26418c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 26428c0984e5SSebastian Reichel */ 26438c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_mainchthprotr_handler(int irq, void *_di) 26448c0984e5SSebastian Reichel { 26458c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 26468c0984e5SSebastian Reichel 26478c0984e5SSebastian Reichel dev_dbg(di->dev, 26488c0984e5SSebastian Reichel "Die temp above Main charger thermal protection threshold\n"); 26498c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->check_main_thermal_prot_work); 26508c0984e5SSebastian Reichel 26518c0984e5SSebastian Reichel return IRQ_HANDLED; 26528c0984e5SSebastian Reichel } 26538c0984e5SSebastian Reichel 26548c0984e5SSebastian Reichel /** 26558c0984e5SSebastian Reichel * ab8500_charger_mainchthprotf_handler() - Die temp is below main charger 26568c0984e5SSebastian Reichel * thermal protection threshold 26578c0984e5SSebastian Reichel * @irq: interrupt number 26588c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 26598c0984e5SSebastian Reichel * 26608c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 26618c0984e5SSebastian Reichel */ 26628c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_mainchthprotf_handler(int irq, void *_di) 26638c0984e5SSebastian Reichel { 26648c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 26658c0984e5SSebastian Reichel 26668c0984e5SSebastian Reichel dev_dbg(di->dev, 26678c0984e5SSebastian Reichel "Die temp ok for Main charger thermal protection threshold\n"); 26688c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->check_main_thermal_prot_work); 26698c0984e5SSebastian Reichel 26708c0984e5SSebastian Reichel return IRQ_HANDLED; 26718c0984e5SSebastian Reichel } 26728c0984e5SSebastian Reichel 26738c0984e5SSebastian Reichel static void ab8500_charger_vbus_drop_end_work(struct work_struct *work) 26748c0984e5SSebastian Reichel { 26758c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 26768c0984e5SSebastian Reichel struct ab8500_charger, vbus_drop_end_work.work); 267783e5aa77SLinus Walleij int ret, curr_ua; 26788c0984e5SSebastian Reichel u8 reg_value; 26798c0984e5SSebastian Reichel 26808c0984e5SSebastian Reichel di->flags.vbus_drop_end = false; 26818c0984e5SSebastian Reichel 26828c0984e5SSebastian Reichel /* Reset the drop counter */ 26838c0984e5SSebastian Reichel abx500_set_register_interruptible(di->dev, 26848c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CHARGER_CTRL, 0x01); 26858c0984e5SSebastian Reichel 26868c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 26878c0984e5SSebastian Reichel AB8500_CH_USBCH_STAT2_REG, ®_value); 26888c0984e5SSebastian Reichel if (ret < 0) { 26898c0984e5SSebastian Reichel dev_err(di->dev, "%s read failed\n", __func__); 26908c0984e5SSebastian Reichel return; 26918c0984e5SSebastian Reichel } 26928c0984e5SSebastian Reichel 269383e5aa77SLinus Walleij curr_ua = ab8500_charge_input_curr_map[ 26948c0984e5SSebastian Reichel reg_value >> AUTO_VBUS_IN_CURR_LIM_SHIFT]; 26958c0984e5SSebastian Reichel 269683e5aa77SLinus Walleij if (di->max_usb_in_curr.calculated_max_ua != curr_ua) { 26978c0984e5SSebastian Reichel /* USB source is collapsing */ 269883e5aa77SLinus Walleij di->max_usb_in_curr.calculated_max_ua = curr_ua; 26998c0984e5SSebastian Reichel dev_dbg(di->dev, 270083e5aa77SLinus Walleij "VBUS input current limiting to %d uA\n", 270183e5aa77SLinus Walleij di->max_usb_in_curr.calculated_max_ua); 27028c0984e5SSebastian Reichel } else { 27038c0984e5SSebastian Reichel /* 27048c0984e5SSebastian Reichel * USB source can not give more than this amount. 27058c0984e5SSebastian Reichel * Taking more will collapse the source. 27068c0984e5SSebastian Reichel */ 270783e5aa77SLinus Walleij di->max_usb_in_curr.set_max_ua = 270883e5aa77SLinus Walleij di->max_usb_in_curr.calculated_max_ua; 27098c0984e5SSebastian Reichel dev_dbg(di->dev, 271083e5aa77SLinus Walleij "VBUS input current limited to %d uA\n", 271183e5aa77SLinus Walleij di->max_usb_in_curr.set_max_ua); 27128c0984e5SSebastian Reichel } 27138c0984e5SSebastian Reichel 27148c0984e5SSebastian Reichel if (di->usb.charger_connected) 27158c0984e5SSebastian Reichel ab8500_charger_set_vbus_in_curr(di, 271683e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua); 27178c0984e5SSebastian Reichel } 27188c0984e5SSebastian Reichel 27198c0984e5SSebastian Reichel /** 27208c0984e5SSebastian Reichel * ab8500_charger_vbusdetf_handler() - VBUS falling detected 27218c0984e5SSebastian Reichel * @irq: interrupt number 27228c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 27238c0984e5SSebastian Reichel * 27248c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 27258c0984e5SSebastian Reichel */ 27268c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_vbusdetf_handler(int irq, void *_di) 27278c0984e5SSebastian Reichel { 27288c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 27298c0984e5SSebastian Reichel 27308c0984e5SSebastian Reichel di->vbus_detected = false; 27318c0984e5SSebastian Reichel dev_dbg(di->dev, "VBUS falling detected\n"); 27328c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->detect_usb_type_work); 27338c0984e5SSebastian Reichel 27348c0984e5SSebastian Reichel return IRQ_HANDLED; 27358c0984e5SSebastian Reichel } 27368c0984e5SSebastian Reichel 27378c0984e5SSebastian Reichel /** 27388c0984e5SSebastian Reichel * ab8500_charger_vbusdetr_handler() - VBUS rising detected 27398c0984e5SSebastian Reichel * @irq: interrupt number 27408c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 27418c0984e5SSebastian Reichel * 27428c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 27438c0984e5SSebastian Reichel */ 27448c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_vbusdetr_handler(int irq, void *_di) 27458c0984e5SSebastian Reichel { 27468c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 27478c0984e5SSebastian Reichel 27488c0984e5SSebastian Reichel di->vbus_detected = true; 27498c0984e5SSebastian Reichel dev_dbg(di->dev, "VBUS rising detected\n"); 27508c0984e5SSebastian Reichel 27518c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->detect_usb_type_work); 27528c0984e5SSebastian Reichel 27538c0984e5SSebastian Reichel return IRQ_HANDLED; 27548c0984e5SSebastian Reichel } 27558c0984e5SSebastian Reichel 27568c0984e5SSebastian Reichel /** 27578c0984e5SSebastian Reichel * ab8500_charger_usblinkstatus_handler() - USB link status has changed 27588c0984e5SSebastian Reichel * @irq: interrupt number 27598c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 27608c0984e5SSebastian Reichel * 27618c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 27628c0984e5SSebastian Reichel */ 27638c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_usblinkstatus_handler(int irq, void *_di) 27648c0984e5SSebastian Reichel { 27658c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 27668c0984e5SSebastian Reichel 27678c0984e5SSebastian Reichel dev_dbg(di->dev, "USB link status changed\n"); 27688c0984e5SSebastian Reichel 27698c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->usb_link_status_work); 27708c0984e5SSebastian Reichel 27718c0984e5SSebastian Reichel return IRQ_HANDLED; 27728c0984e5SSebastian Reichel } 27738c0984e5SSebastian Reichel 27748c0984e5SSebastian Reichel /** 27758c0984e5SSebastian Reichel * ab8500_charger_usbchthprotr_handler() - Die temp is above usb charger 27768c0984e5SSebastian Reichel * thermal protection threshold 27778c0984e5SSebastian Reichel * @irq: interrupt number 27788c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 27798c0984e5SSebastian Reichel * 27808c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 27818c0984e5SSebastian Reichel */ 27828c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_usbchthprotr_handler(int irq, void *_di) 27838c0984e5SSebastian Reichel { 27848c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 27858c0984e5SSebastian Reichel 27868c0984e5SSebastian Reichel dev_dbg(di->dev, 27878c0984e5SSebastian Reichel "Die temp above USB charger thermal protection threshold\n"); 27888c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->check_usb_thermal_prot_work); 27898c0984e5SSebastian Reichel 27908c0984e5SSebastian Reichel return IRQ_HANDLED; 27918c0984e5SSebastian Reichel } 27928c0984e5SSebastian Reichel 27938c0984e5SSebastian Reichel /** 27948c0984e5SSebastian Reichel * ab8500_charger_usbchthprotf_handler() - Die temp is below usb charger 27958c0984e5SSebastian Reichel * thermal protection threshold 27968c0984e5SSebastian Reichel * @irq: interrupt number 27978c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 27988c0984e5SSebastian Reichel * 27998c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 28008c0984e5SSebastian Reichel */ 28018c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_usbchthprotf_handler(int irq, void *_di) 28028c0984e5SSebastian Reichel { 28038c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 28048c0984e5SSebastian Reichel 28058c0984e5SSebastian Reichel dev_dbg(di->dev, 28068c0984e5SSebastian Reichel "Die temp ok for USB charger thermal protection threshold\n"); 28078c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->check_usb_thermal_prot_work); 28088c0984e5SSebastian Reichel 28098c0984e5SSebastian Reichel return IRQ_HANDLED; 28108c0984e5SSebastian Reichel } 28118c0984e5SSebastian Reichel 28128c0984e5SSebastian Reichel /** 28138c0984e5SSebastian Reichel * ab8500_charger_usbchargernotokr_handler() - USB charger not ok detected 28148c0984e5SSebastian Reichel * @irq: interrupt number 28158c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 28168c0984e5SSebastian Reichel * 28178c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 28188c0984e5SSebastian Reichel */ 28198c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_usbchargernotokr_handler(int irq, void *_di) 28208c0984e5SSebastian Reichel { 28218c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 28228c0984e5SSebastian Reichel 28238c0984e5SSebastian Reichel dev_dbg(di->dev, "Not allowed USB charger detected\n"); 28248c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->check_usbchgnotok_work, 0); 28258c0984e5SSebastian Reichel 28268c0984e5SSebastian Reichel return IRQ_HANDLED; 28278c0984e5SSebastian Reichel } 28288c0984e5SSebastian Reichel 28298c0984e5SSebastian Reichel /** 28308c0984e5SSebastian Reichel * ab8500_charger_chwdexp_handler() - Charger watchdog expired 28318c0984e5SSebastian Reichel * @irq: interrupt number 28328c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 28338c0984e5SSebastian Reichel * 28348c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 28358c0984e5SSebastian Reichel */ 28368c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_chwdexp_handler(int irq, void *_di) 28378c0984e5SSebastian Reichel { 28388c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 28398c0984e5SSebastian Reichel 28408c0984e5SSebastian Reichel dev_dbg(di->dev, "Charger watchdog expired\n"); 28418c0984e5SSebastian Reichel 28428c0984e5SSebastian Reichel /* 28438c0984e5SSebastian Reichel * The charger that was online when the watchdog expired 28448c0984e5SSebastian Reichel * needs to be restarted for charging to start again 28458c0984e5SSebastian Reichel */ 28468c0984e5SSebastian Reichel if (di->ac.charger_online) { 28478c0984e5SSebastian Reichel di->ac.wd_expired = true; 28488c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 28498c0984e5SSebastian Reichel } 28508c0984e5SSebastian Reichel if (di->usb.charger_online) { 28518c0984e5SSebastian Reichel di->usb.wd_expired = true; 28528c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 28538c0984e5SSebastian Reichel } 28548c0984e5SSebastian Reichel 28558c0984e5SSebastian Reichel return IRQ_HANDLED; 28568c0984e5SSebastian Reichel } 28578c0984e5SSebastian Reichel 28588c0984e5SSebastian Reichel /** 28598c0984e5SSebastian Reichel * ab8500_charger_vbuschdropend_handler() - VBUS drop removed 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_vbuschdropend_handler(int irq, void *_di) 28668c0984e5SSebastian Reichel { 28678c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 28688c0984e5SSebastian Reichel 28698c0984e5SSebastian Reichel dev_dbg(di->dev, "VBUS charger drop ended\n"); 28708c0984e5SSebastian Reichel di->flags.vbus_drop_end = true; 28718c0984e5SSebastian Reichel 28728c0984e5SSebastian Reichel /* 28738c0984e5SSebastian Reichel * VBUS might have dropped due to bad connection. 28748c0984e5SSebastian Reichel * Schedule a new input limit set to the value SW requests. 28758c0984e5SSebastian Reichel */ 28768c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->vbus_drop_end_work, 28778c0984e5SSebastian Reichel round_jiffies(VBUS_IN_CURR_LIM_RETRY_SET_TIME * HZ)); 28788c0984e5SSebastian Reichel 28798c0984e5SSebastian Reichel return IRQ_HANDLED; 28808c0984e5SSebastian Reichel } 28818c0984e5SSebastian Reichel 28828c0984e5SSebastian Reichel /** 28838c0984e5SSebastian Reichel * ab8500_charger_vbusovv_handler() - VBUS overvoltage detected 28848c0984e5SSebastian Reichel * @irq: interrupt number 28858c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 28868c0984e5SSebastian Reichel * 28878c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 28888c0984e5SSebastian Reichel */ 28898c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_vbusovv_handler(int irq, void *_di) 28908c0984e5SSebastian Reichel { 28918c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 28928c0984e5SSebastian Reichel 28938c0984e5SSebastian Reichel dev_dbg(di->dev, "VBUS overvoltage detected\n"); 28948c0984e5SSebastian Reichel di->flags.vbus_ovv = true; 28958c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 28968c0984e5SSebastian Reichel 28978c0984e5SSebastian Reichel /* Schedule a new HW failure check */ 28988c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->check_hw_failure_work, 0); 28998c0984e5SSebastian Reichel 29008c0984e5SSebastian Reichel return IRQ_HANDLED; 29018c0984e5SSebastian Reichel } 29028c0984e5SSebastian Reichel 29038c0984e5SSebastian Reichel /** 29048c0984e5SSebastian Reichel * ab8500_charger_ac_get_property() - get the ac/mains properties 29058c0984e5SSebastian Reichel * @psy: pointer to the power_supply structure 29068c0984e5SSebastian Reichel * @psp: pointer to the power_supply_property structure 29078c0984e5SSebastian Reichel * @val: pointer to the power_supply_propval union 29088c0984e5SSebastian Reichel * 29098c0984e5SSebastian Reichel * This function gets called when an application tries to get the ac/mains 29108c0984e5SSebastian Reichel * properties by reading the sysfs files. 29118c0984e5SSebastian Reichel * AC/Mains properties are online, present and voltage. 29128c0984e5SSebastian Reichel * online: ac/mains charging is in progress or not 29138c0984e5SSebastian Reichel * present: presence of the ac/mains 29148c0984e5SSebastian Reichel * voltage: AC/Mains voltage 29158c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 29168c0984e5SSebastian Reichel */ 29178c0984e5SSebastian Reichel static int ab8500_charger_ac_get_property(struct power_supply *psy, 29188c0984e5SSebastian Reichel enum power_supply_property psp, 29198c0984e5SSebastian Reichel union power_supply_propval *val) 29208c0984e5SSebastian Reichel { 29218c0984e5SSebastian Reichel struct ab8500_charger *di; 29228c0984e5SSebastian Reichel int ret; 29238c0984e5SSebastian Reichel 29248c0984e5SSebastian Reichel di = to_ab8500_charger_ac_device_info(psy_to_ux500_charger(psy)); 29258c0984e5SSebastian Reichel 29268c0984e5SSebastian Reichel switch (psp) { 29278c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_HEALTH: 29288c0984e5SSebastian Reichel if (di->flags.mainextchnotok) 29298c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 29308c0984e5SSebastian Reichel else if (di->ac.wd_expired || di->usb.wd_expired) 29318c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_DEAD; 29328c0984e5SSebastian Reichel else if (di->flags.main_thermal_prot) 29338c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 29348c0984e5SSebastian Reichel else 29358c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_GOOD; 29368c0984e5SSebastian Reichel break; 29378c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_ONLINE: 29388c0984e5SSebastian Reichel val->intval = di->ac.charger_online; 29398c0984e5SSebastian Reichel break; 29408c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_PRESENT: 29418c0984e5SSebastian Reichel val->intval = di->ac.charger_connected; 29428c0984e5SSebastian Reichel break; 29438c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_NOW: 29448c0984e5SSebastian Reichel ret = ab8500_charger_get_ac_voltage(di); 29458c0984e5SSebastian Reichel if (ret >= 0) 2946bc6e0287SLinus Walleij di->ac.charger_voltage_uv = ret; 29478c0984e5SSebastian Reichel /* On error, use previous value */ 2948bc6e0287SLinus Walleij val->intval = di->ac.charger_voltage_uv; 29498c0984e5SSebastian Reichel break; 29508c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_AVG: 29518c0984e5SSebastian Reichel /* 29528c0984e5SSebastian Reichel * This property is used to indicate when CV mode is entered 29538c0984e5SSebastian Reichel * for the AC charger 29548c0984e5SSebastian Reichel */ 29558c0984e5SSebastian Reichel di->ac.cv_active = ab8500_charger_ac_cv(di); 29568c0984e5SSebastian Reichel val->intval = di->ac.cv_active; 29578c0984e5SSebastian Reichel break; 29588c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CURRENT_NOW: 29598c0984e5SSebastian Reichel ret = ab8500_charger_get_ac_current(di); 29608c0984e5SSebastian Reichel if (ret >= 0) 296183e5aa77SLinus Walleij di->ac.charger_current_ua = ret; 296283e5aa77SLinus Walleij val->intval = di->ac.charger_current_ua; 29638c0984e5SSebastian Reichel break; 29648c0984e5SSebastian Reichel default: 29658c0984e5SSebastian Reichel return -EINVAL; 29668c0984e5SSebastian Reichel } 29678c0984e5SSebastian Reichel return 0; 29688c0984e5SSebastian Reichel } 29698c0984e5SSebastian Reichel 29708c0984e5SSebastian Reichel /** 29718c0984e5SSebastian Reichel * ab8500_charger_usb_get_property() - get the usb properties 29728c0984e5SSebastian Reichel * @psy: pointer to the power_supply structure 29738c0984e5SSebastian Reichel * @psp: pointer to the power_supply_property structure 29748c0984e5SSebastian Reichel * @val: pointer to the power_supply_propval union 29758c0984e5SSebastian Reichel * 29768c0984e5SSebastian Reichel * This function gets called when an application tries to get the usb 29778c0984e5SSebastian Reichel * properties by reading the sysfs files. 29788c0984e5SSebastian Reichel * USB properties are online, present and voltage. 29798c0984e5SSebastian Reichel * online: usb charging is in progress or not 29808c0984e5SSebastian Reichel * present: presence of the usb 29818c0984e5SSebastian Reichel * voltage: vbus voltage 29828c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 29838c0984e5SSebastian Reichel */ 29848c0984e5SSebastian Reichel static int ab8500_charger_usb_get_property(struct power_supply *psy, 29858c0984e5SSebastian Reichel enum power_supply_property psp, 29868c0984e5SSebastian Reichel union power_supply_propval *val) 29878c0984e5SSebastian Reichel { 29888c0984e5SSebastian Reichel struct ab8500_charger *di; 29898c0984e5SSebastian Reichel int ret; 29908c0984e5SSebastian Reichel 29918c0984e5SSebastian Reichel di = to_ab8500_charger_usb_device_info(psy_to_ux500_charger(psy)); 29928c0984e5SSebastian Reichel 29938c0984e5SSebastian Reichel switch (psp) { 29948c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_HEALTH: 29958c0984e5SSebastian Reichel if (di->flags.usbchargernotok) 29968c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 29978c0984e5SSebastian Reichel else if (di->ac.wd_expired || di->usb.wd_expired) 29988c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_DEAD; 29998c0984e5SSebastian Reichel else if (di->flags.usb_thermal_prot) 30008c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 30018c0984e5SSebastian Reichel else if (di->flags.vbus_ovv) 30028c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 30038c0984e5SSebastian Reichel else 30048c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_GOOD; 30058c0984e5SSebastian Reichel break; 30068c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_ONLINE: 30078c0984e5SSebastian Reichel val->intval = di->usb.charger_online; 30088c0984e5SSebastian Reichel break; 30098c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_PRESENT: 30108c0984e5SSebastian Reichel val->intval = di->usb.charger_connected; 30118c0984e5SSebastian Reichel break; 30128c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_NOW: 30138c0984e5SSebastian Reichel ret = ab8500_charger_get_vbus_voltage(di); 30148c0984e5SSebastian Reichel if (ret >= 0) 3015bc6e0287SLinus Walleij di->usb.charger_voltage_uv = ret; 3016bc6e0287SLinus Walleij val->intval = di->usb.charger_voltage_uv; 30178c0984e5SSebastian Reichel break; 30188c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_AVG: 30198c0984e5SSebastian Reichel /* 30208c0984e5SSebastian Reichel * This property is used to indicate when CV mode is entered 30218c0984e5SSebastian Reichel * for the USB charger 30228c0984e5SSebastian Reichel */ 30238c0984e5SSebastian Reichel di->usb.cv_active = ab8500_charger_usb_cv(di); 30248c0984e5SSebastian Reichel val->intval = di->usb.cv_active; 30258c0984e5SSebastian Reichel break; 30268c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CURRENT_NOW: 30278c0984e5SSebastian Reichel ret = ab8500_charger_get_usb_current(di); 30288c0984e5SSebastian Reichel if (ret >= 0) 302983e5aa77SLinus Walleij di->usb.charger_current_ua = ret; 303083e5aa77SLinus Walleij val->intval = di->usb.charger_current_ua; 30318c0984e5SSebastian Reichel break; 30328c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CURRENT_AVG: 30338c0984e5SSebastian Reichel /* 30348c0984e5SSebastian Reichel * This property is used to indicate when VBUS has collapsed 30358c0984e5SSebastian Reichel * due to too high output current from the USB charger 30368c0984e5SSebastian Reichel */ 30378c0984e5SSebastian Reichel if (di->flags.vbus_collapse) 30388c0984e5SSebastian Reichel val->intval = 1; 30398c0984e5SSebastian Reichel else 30408c0984e5SSebastian Reichel val->intval = 0; 30418c0984e5SSebastian Reichel break; 30428c0984e5SSebastian Reichel default: 30438c0984e5SSebastian Reichel return -EINVAL; 30448c0984e5SSebastian Reichel } 30458c0984e5SSebastian Reichel return 0; 30468c0984e5SSebastian Reichel } 30478c0984e5SSebastian Reichel 30488c0984e5SSebastian Reichel /** 30498c0984e5SSebastian Reichel * ab8500_charger_init_hw_registers() - Set up charger related registers 30508c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 30518c0984e5SSebastian Reichel * 30528c0984e5SSebastian Reichel * Set up charger OVV, watchdog and maximum voltage registers as well as 30538c0984e5SSebastian Reichel * charging of the backup battery 30548c0984e5SSebastian Reichel */ 30558c0984e5SSebastian Reichel static int ab8500_charger_init_hw_registers(struct ab8500_charger *di) 30568c0984e5SSebastian Reichel { 30578c0984e5SSebastian Reichel int ret = 0; 30588c0984e5SSebastian Reichel 30598c0984e5SSebastian Reichel /* Setup maximum charger current and voltage for ABB cut2.0 */ 30608c0984e5SSebastian Reichel if (!is_ab8500_1p1_or_earlier(di->parent)) { 30618c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 30628c0984e5SSebastian Reichel AB8500_CHARGER, 30638c0984e5SSebastian Reichel AB8500_CH_VOLT_LVL_MAX_REG, CH_VOL_LVL_4P6); 30648c0984e5SSebastian Reichel if (ret) { 30658c0984e5SSebastian Reichel dev_err(di->dev, 30668c0984e5SSebastian Reichel "failed to set CH_VOLT_LVL_MAX_REG\n"); 30678c0984e5SSebastian Reichel goto out; 30688c0984e5SSebastian Reichel } 30698c0984e5SSebastian Reichel 30708c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 30718c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_OPT_CRNTLVL_MAX_REG, 30728c0984e5SSebastian Reichel CH_OP_CUR_LVL_1P6); 30738c0984e5SSebastian Reichel if (ret) { 30748c0984e5SSebastian Reichel dev_err(di->dev, 30758c0984e5SSebastian Reichel "failed to set CH_OPT_CRNTLVL_MAX_REG\n"); 30768c0984e5SSebastian Reichel goto out; 30778c0984e5SSebastian Reichel } 30788c0984e5SSebastian Reichel } 30798c0984e5SSebastian Reichel 30804c4268dcSLinus Walleij if (is_ab8505_2p0(di->parent)) 30818c0984e5SSebastian Reichel ret = abx500_mask_and_set_register_interruptible(di->dev, 30828c0984e5SSebastian Reichel AB8500_CHARGER, 30838c0984e5SSebastian Reichel AB8500_USBCH_CTRL2_REG, 30848c0984e5SSebastian Reichel VBUS_AUTO_IN_CURR_LIM_ENA, 30858c0984e5SSebastian Reichel VBUS_AUTO_IN_CURR_LIM_ENA); 30868c0984e5SSebastian Reichel else 30878c0984e5SSebastian Reichel /* 30888c0984e5SSebastian Reichel * VBUS OVV set to 6.3V and enable automatic current limitation 30898c0984e5SSebastian Reichel */ 30908c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 30918c0984e5SSebastian Reichel AB8500_CHARGER, 30928c0984e5SSebastian Reichel AB8500_USBCH_CTRL2_REG, 30938c0984e5SSebastian Reichel VBUS_OVV_SELECT_6P3V | VBUS_AUTO_IN_CURR_LIM_ENA); 30948c0984e5SSebastian Reichel if (ret) { 30958c0984e5SSebastian Reichel dev_err(di->dev, 30968c0984e5SSebastian Reichel "failed to set automatic current limitation\n"); 30978c0984e5SSebastian Reichel goto out; 30988c0984e5SSebastian Reichel } 30998c0984e5SSebastian Reichel 31008c0984e5SSebastian Reichel /* Enable main watchdog in OTP */ 31018c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 31028c0984e5SSebastian Reichel AB8500_OTP_EMUL, AB8500_OTP_CONF_15, OTP_ENABLE_WD); 31038c0984e5SSebastian Reichel if (ret) { 31048c0984e5SSebastian Reichel dev_err(di->dev, "failed to enable main WD in OTP\n"); 31058c0984e5SSebastian Reichel goto out; 31068c0984e5SSebastian Reichel } 31078c0984e5SSebastian Reichel 31088c0984e5SSebastian Reichel /* Enable main watchdog */ 31098c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 31108c0984e5SSebastian Reichel AB8500_SYS_CTRL2_BLOCK, 31118c0984e5SSebastian Reichel AB8500_MAIN_WDOG_CTRL_REG, MAIN_WDOG_ENA); 31128c0984e5SSebastian Reichel if (ret) { 3113b5e11cc1SColin Ian King dev_err(di->dev, "failed to enable main watchdog\n"); 31148c0984e5SSebastian Reichel goto out; 31158c0984e5SSebastian Reichel } 31168c0984e5SSebastian Reichel 31178c0984e5SSebastian Reichel /* 31188c0984e5SSebastian Reichel * Due to internal synchronisation, Enable and Kick watchdog bits 31198c0984e5SSebastian Reichel * cannot be enabled in a single write. 31208c0984e5SSebastian Reichel * A minimum delay of 2*32 kHz period (62.5µs) must be inserted 31218c0984e5SSebastian Reichel * between writing Enable then Kick bits. 31228c0984e5SSebastian Reichel */ 31238c0984e5SSebastian Reichel udelay(63); 31248c0984e5SSebastian Reichel 31258c0984e5SSebastian Reichel /* Kick main watchdog */ 31268c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 31278c0984e5SSebastian Reichel AB8500_SYS_CTRL2_BLOCK, 31288c0984e5SSebastian Reichel AB8500_MAIN_WDOG_CTRL_REG, 31298c0984e5SSebastian Reichel (MAIN_WDOG_ENA | MAIN_WDOG_KICK)); 31308c0984e5SSebastian Reichel if (ret) { 31318c0984e5SSebastian Reichel dev_err(di->dev, "failed to kick main watchdog\n"); 31328c0984e5SSebastian Reichel goto out; 31338c0984e5SSebastian Reichel } 31348c0984e5SSebastian Reichel 31358c0984e5SSebastian Reichel /* Disable main watchdog */ 31368c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 31378c0984e5SSebastian Reichel AB8500_SYS_CTRL2_BLOCK, 31388c0984e5SSebastian Reichel AB8500_MAIN_WDOG_CTRL_REG, MAIN_WDOG_DIS); 31398c0984e5SSebastian Reichel if (ret) { 31408c0984e5SSebastian Reichel dev_err(di->dev, "failed to disable main watchdog\n"); 31418c0984e5SSebastian Reichel goto out; 31428c0984e5SSebastian Reichel } 31438c0984e5SSebastian Reichel 31448c0984e5SSebastian Reichel /* Set watchdog timeout */ 31458c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 31468c0984e5SSebastian Reichel AB8500_CH_WD_TIMER_REG, WD_TIMER); 31478c0984e5SSebastian Reichel if (ret) { 31488c0984e5SSebastian Reichel dev_err(di->dev, "failed to set charger watchdog timeout\n"); 31498c0984e5SSebastian Reichel goto out; 31508c0984e5SSebastian Reichel } 31518c0984e5SSebastian Reichel 31528c0984e5SSebastian Reichel ret = ab8500_charger_led_en(di, false); 31538c0984e5SSebastian Reichel if (ret < 0) { 31548c0984e5SSebastian Reichel dev_err(di->dev, "failed to disable LED\n"); 31558c0984e5SSebastian Reichel goto out; 31568c0984e5SSebastian Reichel } 31578c0984e5SSebastian Reichel 31588c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 31598c0984e5SSebastian Reichel AB8500_RTC, 31608c0984e5SSebastian Reichel AB8500_RTC_BACKUP_CHG_REG, 31618c0984e5SSebastian Reichel (di->bm->bkup_bat_v & 0x3) | di->bm->bkup_bat_i); 31628c0984e5SSebastian Reichel if (ret) { 31638c0984e5SSebastian Reichel dev_err(di->dev, "failed to setup backup battery charging\n"); 31648c0984e5SSebastian Reichel goto out; 31658c0984e5SSebastian Reichel } 31668c0984e5SSebastian Reichel 31678c0984e5SSebastian Reichel /* Enable backup battery charging */ 3168bf59fdddSChristophe JAILLET ret = abx500_mask_and_set_register_interruptible(di->dev, 31698c0984e5SSebastian Reichel AB8500_RTC, AB8500_RTC_CTRL_REG, 31708c0984e5SSebastian Reichel RTC_BUP_CH_ENA, RTC_BUP_CH_ENA); 317109edcb64SChristophe JAILLET if (ret < 0) { 31728c0984e5SSebastian Reichel dev_err(di->dev, "%s mask and set failed\n", __func__); 317309edcb64SChristophe JAILLET goto out; 317409edcb64SChristophe JAILLET } 31758c0984e5SSebastian Reichel 31768c0984e5SSebastian Reichel out: 31778c0984e5SSebastian Reichel return ret; 31788c0984e5SSebastian Reichel } 31798c0984e5SSebastian Reichel 31808c0984e5SSebastian Reichel /* 31818c0984e5SSebastian Reichel * ab8500 charger driver interrupts and their respective isr 31828c0984e5SSebastian Reichel */ 31838c0984e5SSebastian Reichel static struct ab8500_charger_interrupts ab8500_charger_irq[] = { 31848c0984e5SSebastian Reichel {"MAIN_CH_UNPLUG_DET", ab8500_charger_mainchunplugdet_handler}, 31858c0984e5SSebastian Reichel {"MAIN_CHARGE_PLUG_DET", ab8500_charger_mainchplugdet_handler}, 31868c0984e5SSebastian Reichel {"MAIN_EXT_CH_NOT_OK", ab8500_charger_mainextchnotok_handler}, 31878c0984e5SSebastian Reichel {"MAIN_CH_TH_PROT_R", ab8500_charger_mainchthprotr_handler}, 31888c0984e5SSebastian Reichel {"MAIN_CH_TH_PROT_F", ab8500_charger_mainchthprotf_handler}, 31898c0984e5SSebastian Reichel {"VBUS_DET_F", ab8500_charger_vbusdetf_handler}, 31908c0984e5SSebastian Reichel {"VBUS_DET_R", ab8500_charger_vbusdetr_handler}, 31918c0984e5SSebastian Reichel {"USB_LINK_STATUS", ab8500_charger_usblinkstatus_handler}, 31928c0984e5SSebastian Reichel {"USB_CH_TH_PROT_R", ab8500_charger_usbchthprotr_handler}, 31938c0984e5SSebastian Reichel {"USB_CH_TH_PROT_F", ab8500_charger_usbchthprotf_handler}, 31948c0984e5SSebastian Reichel {"USB_CHARGER_NOT_OKR", ab8500_charger_usbchargernotokr_handler}, 31958c0984e5SSebastian Reichel {"VBUS_OVV", ab8500_charger_vbusovv_handler}, 31968c0984e5SSebastian Reichel {"CH_WD_EXP", ab8500_charger_chwdexp_handler}, 31978c0984e5SSebastian Reichel {"VBUS_CH_DROP_END", ab8500_charger_vbuschdropend_handler}, 31988c0984e5SSebastian Reichel }; 31998c0984e5SSebastian Reichel 32008c0984e5SSebastian Reichel static int ab8500_charger_usb_notifier_call(struct notifier_block *nb, 32018c0984e5SSebastian Reichel unsigned long event, void *power) 32028c0984e5SSebastian Reichel { 32038c0984e5SSebastian Reichel struct ab8500_charger *di = 32048c0984e5SSebastian Reichel container_of(nb, struct ab8500_charger, nb); 32058c0984e5SSebastian Reichel enum ab8500_usb_state bm_usb_state; 320683e5aa77SLinus Walleij /* 320783e5aa77SLinus Walleij * FIXME: it appears the AB8500 PHY never sends what it should here. 320883e5aa77SLinus Walleij * Fix the PHY driver to properly notify the desired current. 320983e5aa77SLinus Walleij * Also broadcast microampere and not milliampere. 321083e5aa77SLinus Walleij */ 32118c0984e5SSebastian Reichel unsigned mA = *((unsigned *)power); 32128c0984e5SSebastian Reichel 32138c0984e5SSebastian Reichel if (event != USB_EVENT_VBUS) { 32148c0984e5SSebastian Reichel dev_dbg(di->dev, "not a standard host, returning\n"); 32158c0984e5SSebastian Reichel return NOTIFY_DONE; 32168c0984e5SSebastian Reichel } 32178c0984e5SSebastian Reichel 32188c0984e5SSebastian Reichel /* TODO: State is fabricate here. See if charger really needs USB 32198c0984e5SSebastian Reichel * state or if mA is enough 32208c0984e5SSebastian Reichel */ 322183e5aa77SLinus Walleij if ((di->usb_state.usb_current_ua == 2000) && (mA > 2)) 32228c0984e5SSebastian Reichel bm_usb_state = AB8500_BM_USB_STATE_RESUME; 32238c0984e5SSebastian Reichel else if (mA == 0) 32248c0984e5SSebastian Reichel bm_usb_state = AB8500_BM_USB_STATE_RESET_HS; 32258c0984e5SSebastian Reichel else if (mA == 2) 32268c0984e5SSebastian Reichel bm_usb_state = AB8500_BM_USB_STATE_SUSPEND; 32278c0984e5SSebastian Reichel else if (mA >= 8) /* 8, 100, 500 */ 32288c0984e5SSebastian Reichel bm_usb_state = AB8500_BM_USB_STATE_CONFIGURED; 32298c0984e5SSebastian Reichel else /* Should never occur */ 32308c0984e5SSebastian Reichel bm_usb_state = AB8500_BM_USB_STATE_RESET_FS; 32318c0984e5SSebastian Reichel 32328c0984e5SSebastian Reichel dev_dbg(di->dev, "%s usb_state: 0x%02x mA: %d\n", 32338c0984e5SSebastian Reichel __func__, bm_usb_state, mA); 32348c0984e5SSebastian Reichel 32358c0984e5SSebastian Reichel spin_lock(&di->usb_state.usb_lock); 32368c0984e5SSebastian Reichel di->usb_state.state_tmp = bm_usb_state; 323783e5aa77SLinus Walleij /* FIXME: broadcast ua instead, see above */ 323883e5aa77SLinus Walleij di->usb_state.usb_current_tmp_ua = mA * 1000; 32398c0984e5SSebastian Reichel spin_unlock(&di->usb_state.usb_lock); 32408c0984e5SSebastian Reichel 32418c0984e5SSebastian Reichel /* 32428c0984e5SSebastian Reichel * wait for some time until you get updates from the usb stack 32438c0984e5SSebastian Reichel * and negotiations are completed 32448c0984e5SSebastian Reichel */ 32458c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->usb_state_changed_work, HZ/2); 32468c0984e5SSebastian Reichel 32478c0984e5SSebastian Reichel return NOTIFY_OK; 32488c0984e5SSebastian Reichel } 32498c0984e5SSebastian Reichel 3250f8efa0a8SLinus Walleij static int __maybe_unused ab8500_charger_resume(struct device *dev) 32518c0984e5SSebastian Reichel { 32528c0984e5SSebastian Reichel int ret; 3253f8efa0a8SLinus Walleij struct ab8500_charger *di = dev_get_drvdata(dev); 32548c0984e5SSebastian Reichel 32558c0984e5SSebastian Reichel /* 32568c0984e5SSebastian Reichel * For ABB revision 1.0 and 1.1 there is a bug in the watchdog 3257ddb74e98SAshish Chavan * logic. That means we have to continuously kick the charger 32588c0984e5SSebastian Reichel * watchdog even when no charger is connected. This is only 32598c0984e5SSebastian Reichel * valid once the AC charger has been enabled. This is 32608c0984e5SSebastian Reichel * a bug that is not handled by the algorithm and the 32618c0984e5SSebastian Reichel * watchdog have to be kicked by the charger driver 32628c0984e5SSebastian Reichel * when the AC charger is disabled 32638c0984e5SSebastian Reichel */ 32648c0984e5SSebastian Reichel if (di->ac_conn && is_ab8500_1p1_or_earlier(di->parent)) { 32658c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 32668c0984e5SSebastian Reichel AB8500_CHARG_WD_CTRL, CHARG_WD_KICK); 32678c0984e5SSebastian Reichel if (ret) 32688c0984e5SSebastian Reichel dev_err(di->dev, "Failed to kick WD!\n"); 32698c0984e5SSebastian Reichel 32708c0984e5SSebastian Reichel /* If not already pending start a new timer */ 32718c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->kick_wd_work, 32728c0984e5SSebastian Reichel round_jiffies(WD_KICK_INTERVAL)); 32738c0984e5SSebastian Reichel } 32748c0984e5SSebastian Reichel 32758c0984e5SSebastian Reichel /* If we still have a HW failure, schedule a new check */ 32768c0984e5SSebastian Reichel if (di->flags.mainextchnotok || di->flags.vbus_ovv) { 32778c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 32788c0984e5SSebastian Reichel &di->check_hw_failure_work, 0); 32798c0984e5SSebastian Reichel } 32808c0984e5SSebastian Reichel 32818c0984e5SSebastian Reichel if (di->flags.vbus_drop_end) 32828c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->vbus_drop_end_work, 0); 32838c0984e5SSebastian Reichel 32848c0984e5SSebastian Reichel return 0; 32858c0984e5SSebastian Reichel } 32868c0984e5SSebastian Reichel 3287f8efa0a8SLinus Walleij static int __maybe_unused ab8500_charger_suspend(struct device *dev) 32888c0984e5SSebastian Reichel { 3289f8efa0a8SLinus Walleij struct ab8500_charger *di = dev_get_drvdata(dev); 32908c0984e5SSebastian Reichel 32918c0984e5SSebastian Reichel /* Cancel any pending jobs */ 32928c0984e5SSebastian Reichel cancel_delayed_work(&di->check_hw_failure_work); 32938c0984e5SSebastian Reichel cancel_delayed_work(&di->vbus_drop_end_work); 32948c0984e5SSebastian Reichel 32958c0984e5SSebastian Reichel flush_delayed_work(&di->attach_work); 32968c0984e5SSebastian Reichel flush_delayed_work(&di->usb_charger_attached_work); 32978c0984e5SSebastian Reichel flush_delayed_work(&di->ac_charger_attached_work); 32988c0984e5SSebastian Reichel flush_delayed_work(&di->check_usbchgnotok_work); 32998c0984e5SSebastian Reichel flush_delayed_work(&di->check_vbat_work); 33008c0984e5SSebastian Reichel flush_delayed_work(&di->kick_wd_work); 33018c0984e5SSebastian Reichel 33028c0984e5SSebastian Reichel flush_work(&di->usb_link_status_work); 33038c0984e5SSebastian Reichel flush_work(&di->ac_work); 33048c0984e5SSebastian Reichel flush_work(&di->detect_usb_type_work); 33058c0984e5SSebastian Reichel 33068c0984e5SSebastian Reichel if (atomic_read(&di->current_stepping_sessions)) 33078c0984e5SSebastian Reichel return -EAGAIN; 33088c0984e5SSebastian Reichel 33098c0984e5SSebastian Reichel return 0; 33108c0984e5SSebastian Reichel } 33118c0984e5SSebastian Reichel 33128c0984e5SSebastian Reichel static struct notifier_block charger_nb = { 33138c0984e5SSebastian Reichel .notifier_call = ab8500_external_charger_prepare, 33148c0984e5SSebastian Reichel }; 33158c0984e5SSebastian Reichel 33168c0984e5SSebastian Reichel static char *supply_interface[] = { 33178c0984e5SSebastian Reichel "ab8500_chargalg", 33188c0984e5SSebastian Reichel "ab8500_fg", 33198c0984e5SSebastian Reichel "ab8500_btemp", 33208c0984e5SSebastian Reichel }; 33218c0984e5SSebastian Reichel 33228c0984e5SSebastian Reichel static const struct power_supply_desc ab8500_ac_chg_desc = { 33238c0984e5SSebastian Reichel .name = "ab8500_ac", 33248c0984e5SSebastian Reichel .type = POWER_SUPPLY_TYPE_MAINS, 33258c0984e5SSebastian Reichel .properties = ab8500_charger_ac_props, 33268c0984e5SSebastian Reichel .num_properties = ARRAY_SIZE(ab8500_charger_ac_props), 33278c0984e5SSebastian Reichel .get_property = ab8500_charger_ac_get_property, 33288c0984e5SSebastian Reichel }; 33298c0984e5SSebastian Reichel 33308c0984e5SSebastian Reichel static const struct power_supply_desc ab8500_usb_chg_desc = { 33318c0984e5SSebastian Reichel .name = "ab8500_usb", 33328c0984e5SSebastian Reichel .type = POWER_SUPPLY_TYPE_USB, 33338c0984e5SSebastian Reichel .properties = ab8500_charger_usb_props, 33348c0984e5SSebastian Reichel .num_properties = ARRAY_SIZE(ab8500_charger_usb_props), 33358c0984e5SSebastian Reichel .get_property = ab8500_charger_usb_get_property, 33368c0984e5SSebastian Reichel }; 33378c0984e5SSebastian Reichel 33381c1f13a0SLinus Walleij static int ab8500_charger_bind(struct device *dev) 33391c1f13a0SLinus Walleij { 33401c1f13a0SLinus Walleij struct ab8500_charger *di = dev_get_drvdata(dev); 33411c1f13a0SLinus Walleij int ch_stat; 33421c1f13a0SLinus Walleij int ret; 33431c1f13a0SLinus Walleij 33441c1f13a0SLinus Walleij /* Create a work queue for the charger */ 33451c1f13a0SLinus Walleij di->charger_wq = alloc_ordered_workqueue("ab8500_charger_wq", 33461c1f13a0SLinus Walleij WQ_MEM_RECLAIM); 33471c1f13a0SLinus Walleij if (di->charger_wq == NULL) { 33481c1f13a0SLinus Walleij dev_err(dev, "failed to create work queue\n"); 33491c1f13a0SLinus Walleij return -ENOMEM; 33501c1f13a0SLinus Walleij } 33511c1f13a0SLinus Walleij 33521c1f13a0SLinus Walleij ch_stat = ab8500_charger_detect_chargers(di, false); 33531c1f13a0SLinus Walleij 33541c1f13a0SLinus Walleij if (ch_stat & AC_PW_CONN) { 33551c1f13a0SLinus Walleij if (is_ab8500(di->parent)) 33561c1f13a0SLinus Walleij queue_delayed_work(di->charger_wq, 33571c1f13a0SLinus Walleij &di->ac_charger_attached_work, 33581c1f13a0SLinus Walleij HZ); 33591c1f13a0SLinus Walleij } 33601c1f13a0SLinus Walleij if (ch_stat & USB_PW_CONN) { 33611c1f13a0SLinus Walleij if (is_ab8500(di->parent)) 33621c1f13a0SLinus Walleij queue_delayed_work(di->charger_wq, 33631c1f13a0SLinus Walleij &di->usb_charger_attached_work, 33641c1f13a0SLinus Walleij HZ); 33651c1f13a0SLinus Walleij di->vbus_detected = true; 33661c1f13a0SLinus Walleij di->vbus_detected_start = true; 33671c1f13a0SLinus Walleij queue_work(di->charger_wq, 33681c1f13a0SLinus Walleij &di->detect_usb_type_work); 33691c1f13a0SLinus Walleij } 33701c1f13a0SLinus Walleij 33711c1f13a0SLinus Walleij ret = component_bind_all(dev, di); 33721c1f13a0SLinus Walleij if (ret) { 33731c1f13a0SLinus Walleij dev_err(dev, "can't bind component devices\n"); 33741c1f13a0SLinus Walleij return ret; 33751c1f13a0SLinus Walleij } 33761c1f13a0SLinus Walleij 33771c1f13a0SLinus Walleij return 0; 33781c1f13a0SLinus Walleij } 33791c1f13a0SLinus Walleij 33801c1f13a0SLinus Walleij static void ab8500_charger_unbind(struct device *dev) 33811c1f13a0SLinus Walleij { 33821c1f13a0SLinus Walleij struct ab8500_charger *di = dev_get_drvdata(dev); 33831c1f13a0SLinus Walleij int ret; 33841c1f13a0SLinus Walleij 33851c1f13a0SLinus Walleij /* Disable AC charging */ 33861c1f13a0SLinus Walleij ab8500_charger_ac_en(&di->ac_chg, false, 0, 0); 33871c1f13a0SLinus Walleij 33881c1f13a0SLinus Walleij /* Disable USB charging */ 33891c1f13a0SLinus Walleij ab8500_charger_usb_en(&di->usb_chg, false, 0, 0); 33901c1f13a0SLinus Walleij 33911c1f13a0SLinus Walleij /* Backup battery voltage and current disable */ 33921c1f13a0SLinus Walleij ret = abx500_mask_and_set_register_interruptible(di->dev, 33931c1f13a0SLinus Walleij AB8500_RTC, AB8500_RTC_CTRL_REG, RTC_BUP_CH_ENA, 0); 33941c1f13a0SLinus Walleij if (ret < 0) 33951c1f13a0SLinus Walleij dev_err(di->dev, "%s mask and set failed\n", __func__); 33961c1f13a0SLinus Walleij 33971c1f13a0SLinus Walleij /* Delete the work queue */ 33981c1f13a0SLinus Walleij destroy_workqueue(di->charger_wq); 33991c1f13a0SLinus Walleij 34001c1f13a0SLinus Walleij flush_scheduled_work(); 34011c1f13a0SLinus Walleij 34021c1f13a0SLinus Walleij /* Unbind fg, btemp, algorithm */ 34031c1f13a0SLinus Walleij component_unbind_all(dev, di); 34041c1f13a0SLinus Walleij } 34051c1f13a0SLinus Walleij 34061c1f13a0SLinus Walleij static const struct component_master_ops ab8500_charger_comp_ops = { 34071c1f13a0SLinus Walleij .bind = ab8500_charger_bind, 34081c1f13a0SLinus Walleij .unbind = ab8500_charger_unbind, 34091c1f13a0SLinus Walleij }; 34101c1f13a0SLinus Walleij 34111c1f13a0SLinus Walleij static struct platform_driver *const ab8500_charger_component_drivers[] = { 34121c1f13a0SLinus Walleij &ab8500_fg_driver, 34131c1f13a0SLinus Walleij &ab8500_btemp_driver, 3414c5b64a99SLinus Walleij &ab8500_chargalg_driver, 34151c1f13a0SLinus Walleij }; 34161c1f13a0SLinus Walleij 34171c1f13a0SLinus Walleij static int ab8500_charger_compare_dev(struct device *dev, void *data) 34181c1f13a0SLinus Walleij { 34191c1f13a0SLinus Walleij return dev == data; 34201c1f13a0SLinus Walleij } 34211c1f13a0SLinus Walleij 34228c0984e5SSebastian Reichel static int ab8500_charger_probe(struct platform_device *pdev) 34238c0984e5SSebastian Reichel { 34241c1f13a0SLinus Walleij struct device *dev = &pdev->dev; 34251c1f13a0SLinus Walleij struct device_node *np = dev->of_node; 34261c1f13a0SLinus Walleij struct component_match *match = NULL; 34278c0984e5SSebastian Reichel struct power_supply_config ac_psy_cfg = {}, usb_psy_cfg = {}; 34288c0984e5SSebastian Reichel struct ab8500_charger *di; 34291c1f13a0SLinus Walleij int charger_status; 34301c1f13a0SLinus Walleij int i, irq; 34311c1f13a0SLinus Walleij int ret; 34328c0984e5SSebastian Reichel 3433ad89cb5fSLinus Walleij di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL); 3434ad89cb5fSLinus Walleij if (!di) 34358c0984e5SSebastian Reichel return -ENOMEM; 34368c0984e5SSebastian Reichel 3437417c0fc2SLinus Walleij di->bm = &ab8500_bm_data; 34388c0984e5SSebastian Reichel 34398c0984e5SSebastian Reichel di->autopower_cfg = of_property_read_bool(np, "autopower_cfg"); 34408c0984e5SSebastian Reichel 34418c0984e5SSebastian Reichel /* get parent data */ 3442ad89cb5fSLinus Walleij di->dev = dev; 34438c0984e5SSebastian Reichel di->parent = dev_get_drvdata(pdev->dev.parent); 344497ab78baSLinus Walleij 344597ab78baSLinus Walleij /* Get ADC channels */ 344636f1de0dSLinus Walleij di->adc_main_charger_v = devm_iio_channel_get(dev, "main_charger_v"); 344797ab78baSLinus Walleij if (IS_ERR(di->adc_main_charger_v)) { 344836f1de0dSLinus Walleij ret = dev_err_probe(dev, PTR_ERR(di->adc_main_charger_v), 344936f1de0dSLinus Walleij "failed to get ADC main charger voltage\n"); 345036f1de0dSLinus Walleij return ret; 345197ab78baSLinus Walleij } 345236f1de0dSLinus Walleij di->adc_main_charger_c = devm_iio_channel_get(dev, "main_charger_c"); 345397ab78baSLinus Walleij if (IS_ERR(di->adc_main_charger_c)) { 345436f1de0dSLinus Walleij ret = dev_err_probe(dev, PTR_ERR(di->adc_main_charger_c), 345536f1de0dSLinus Walleij "failed to get ADC main charger current\n"); 345636f1de0dSLinus Walleij return ret; 345797ab78baSLinus Walleij } 3458ad89cb5fSLinus Walleij di->adc_vbus_v = devm_iio_channel_get(dev, "vbus_v"); 345997ab78baSLinus Walleij if (IS_ERR(di->adc_vbus_v)) { 346036f1de0dSLinus Walleij ret = dev_err_probe(dev, PTR_ERR(di->adc_vbus_v), 346136f1de0dSLinus Walleij "failed to get ADC USB charger voltage\n"); 346236f1de0dSLinus Walleij return ret; 346397ab78baSLinus Walleij } 346436f1de0dSLinus Walleij di->adc_usb_charger_c = devm_iio_channel_get(dev, "usb_charger_c"); 346597ab78baSLinus Walleij if (IS_ERR(di->adc_usb_charger_c)) { 346636f1de0dSLinus Walleij ret = dev_err_probe(dev, PTR_ERR(di->adc_usb_charger_c), 346736f1de0dSLinus Walleij "failed to get ADC USB charger current\n"); 346836f1de0dSLinus Walleij return ret; 346997ab78baSLinus Walleij } 34708c0984e5SSebastian Reichel 34711c1f13a0SLinus Walleij /* 34721c1f13a0SLinus Walleij * VDD ADC supply needs to be enabled from this driver when there 34731c1f13a0SLinus Walleij * is a charger connected to avoid erroneous BTEMP_HIGH/LOW 34741c1f13a0SLinus Walleij * interrupts during charging 34751c1f13a0SLinus Walleij */ 34761c1f13a0SLinus Walleij di->regu = devm_regulator_get(dev, "vddadc"); 34771c1f13a0SLinus Walleij if (IS_ERR(di->regu)) { 34781c1f13a0SLinus Walleij ret = PTR_ERR(di->regu); 34791c1f13a0SLinus Walleij dev_err(dev, "failed to get vddadc regulator\n"); 34801c1f13a0SLinus Walleij return ret; 34811c1f13a0SLinus Walleij } 34821c1f13a0SLinus Walleij 34831c1f13a0SLinus Walleij /* Request interrupts */ 34841c1f13a0SLinus Walleij for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { 34851c1f13a0SLinus Walleij irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); 34861c1f13a0SLinus Walleij if (irq < 0) 34871c1f13a0SLinus Walleij return irq; 34881c1f13a0SLinus Walleij 34891c1f13a0SLinus Walleij ret = devm_request_threaded_irq(dev, 34901c1f13a0SLinus Walleij irq, NULL, ab8500_charger_irq[i].isr, 34911c1f13a0SLinus Walleij IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, 34921c1f13a0SLinus Walleij ab8500_charger_irq[i].name, di); 34931c1f13a0SLinus Walleij 34941c1f13a0SLinus Walleij if (ret != 0) { 34951c1f13a0SLinus Walleij dev_err(dev, "failed to request %s IRQ %d: %d\n" 34961c1f13a0SLinus Walleij , ab8500_charger_irq[i].name, irq, ret); 34971c1f13a0SLinus Walleij return ret; 34981c1f13a0SLinus Walleij } 34991c1f13a0SLinus Walleij dev_dbg(dev, "Requested %s IRQ %d: %d\n", 35001c1f13a0SLinus Walleij ab8500_charger_irq[i].name, irq, ret); 35011c1f13a0SLinus Walleij } 35021c1f13a0SLinus Walleij 35038c0984e5SSebastian Reichel /* initialize lock */ 35048c0984e5SSebastian Reichel spin_lock_init(&di->usb_state.usb_lock); 35058c0984e5SSebastian Reichel mutex_init(&di->usb_ipt_crnt_lock); 35068c0984e5SSebastian Reichel 35078c0984e5SSebastian Reichel di->autopower = false; 35088c0984e5SSebastian Reichel di->invalid_charger_detect_state = 0; 35098c0984e5SSebastian Reichel 35108c0984e5SSebastian Reichel /* AC and USB supply config */ 351159f1b854SLinus Walleij ac_psy_cfg.of_node = np; 35128c0984e5SSebastian Reichel ac_psy_cfg.supplied_to = supply_interface; 35138c0984e5SSebastian Reichel ac_psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); 35148c0984e5SSebastian Reichel ac_psy_cfg.drv_data = &di->ac_chg; 351559f1b854SLinus Walleij usb_psy_cfg.of_node = np; 35168c0984e5SSebastian Reichel usb_psy_cfg.supplied_to = supply_interface; 35178c0984e5SSebastian Reichel usb_psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); 35188c0984e5SSebastian Reichel usb_psy_cfg.drv_data = &di->usb_chg; 35198c0984e5SSebastian Reichel 35208c0984e5SSebastian Reichel /* AC supply */ 35218c0984e5SSebastian Reichel /* ux500_charger sub-class */ 35228c0984e5SSebastian Reichel di->ac_chg.ops.enable = &ab8500_charger_ac_en; 35238c0984e5SSebastian Reichel di->ac_chg.ops.check_enable = &ab8500_charger_ac_check_enable; 35248c0984e5SSebastian Reichel di->ac_chg.ops.kick_wd = &ab8500_charger_watchdog_kick; 35258c0984e5SSebastian Reichel di->ac_chg.ops.update_curr = &ab8500_charger_update_charger_current; 3526bc6e0287SLinus Walleij di->ac_chg.max_out_volt_uv = ab8500_charger_voltage_map[ 35278c0984e5SSebastian Reichel ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; 352883e5aa77SLinus Walleij di->ac_chg.max_out_curr_ua = 35293aca6ecdSLinus Walleij ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1]; 35308c0984e5SSebastian Reichel di->ac_chg.wdt_refresh = CHG_WD_INTERVAL; 3531f9184a22SLinus Walleij /* 3532f9184a22SLinus Walleij * The AB8505 only supports USB charging. If we are not the 3533f9184a22SLinus Walleij * AB8505, register an AC charger. 3534f9184a22SLinus Walleij * 3535f9184a22SLinus Walleij * TODO: if this should be opt-in, add DT properties for this. 3536f9184a22SLinus Walleij */ 3537f9184a22SLinus Walleij if (!is_ab8505(di->parent)) 3538f9184a22SLinus Walleij di->ac_chg.enabled = true; 35398c0984e5SSebastian Reichel di->ac_chg.external = false; 35408c0984e5SSebastian Reichel 35418c0984e5SSebastian Reichel /* USB supply */ 35428c0984e5SSebastian Reichel /* ux500_charger sub-class */ 35438c0984e5SSebastian Reichel di->usb_chg.ops.enable = &ab8500_charger_usb_en; 35448c0984e5SSebastian Reichel di->usb_chg.ops.check_enable = &ab8500_charger_usb_check_enable; 35458c0984e5SSebastian Reichel di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick; 35468c0984e5SSebastian Reichel di->usb_chg.ops.update_curr = &ab8500_charger_update_charger_current; 3547bc6e0287SLinus Walleij di->usb_chg.max_out_volt_uv = ab8500_charger_voltage_map[ 35488c0984e5SSebastian Reichel ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; 354983e5aa77SLinus Walleij di->usb_chg.max_out_curr_ua = 35503aca6ecdSLinus Walleij ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1]; 35518c0984e5SSebastian Reichel di->usb_chg.wdt_refresh = CHG_WD_INTERVAL; 35528c0984e5SSebastian Reichel di->usb_chg.external = false; 355383e5aa77SLinus Walleij di->usb_state.usb_current_ua = -1; 35548c0984e5SSebastian Reichel 35558c0984e5SSebastian Reichel mutex_init(&di->charger_attached_mutex); 35568c0984e5SSebastian Reichel 35578c0984e5SSebastian Reichel /* Init work for HW failure check */ 35588c0984e5SSebastian Reichel INIT_DEFERRABLE_WORK(&di->check_hw_failure_work, 35598c0984e5SSebastian Reichel ab8500_charger_check_hw_failure_work); 35608c0984e5SSebastian Reichel INIT_DEFERRABLE_WORK(&di->check_usbchgnotok_work, 35618c0984e5SSebastian Reichel ab8500_charger_check_usbchargernotok_work); 35628c0984e5SSebastian Reichel 35638c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->ac_charger_attached_work, 35648c0984e5SSebastian Reichel ab8500_charger_ac_attached_work); 35658c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->usb_charger_attached_work, 35668c0984e5SSebastian Reichel ab8500_charger_usb_attached_work); 35678c0984e5SSebastian Reichel 35688c0984e5SSebastian Reichel /* 35698c0984e5SSebastian Reichel * For ABB revision 1.0 and 1.1 there is a bug in the watchdog 3570ddb74e98SAshish Chavan * logic. That means we have to continuously kick the charger 35718c0984e5SSebastian Reichel * watchdog even when no charger is connected. This is only 35728c0984e5SSebastian Reichel * valid once the AC charger has been enabled. This is 35738c0984e5SSebastian Reichel * a bug that is not handled by the algorithm and the 35748c0984e5SSebastian Reichel * watchdog have to be kicked by the charger driver 35758c0984e5SSebastian Reichel * when the AC charger is disabled 35768c0984e5SSebastian Reichel */ 35778c0984e5SSebastian Reichel INIT_DEFERRABLE_WORK(&di->kick_wd_work, 35788c0984e5SSebastian Reichel ab8500_charger_kick_watchdog_work); 35798c0984e5SSebastian Reichel 35808c0984e5SSebastian Reichel INIT_DEFERRABLE_WORK(&di->check_vbat_work, 35818c0984e5SSebastian Reichel ab8500_charger_check_vbat_work); 35828c0984e5SSebastian Reichel 35838c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->attach_work, 35848c0984e5SSebastian Reichel ab8500_charger_usb_link_attach_work); 35858c0984e5SSebastian Reichel 35868c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->usb_state_changed_work, 35878c0984e5SSebastian Reichel ab8500_charger_usb_state_changed_work); 35888c0984e5SSebastian Reichel 35898c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->vbus_drop_end_work, 35908c0984e5SSebastian Reichel ab8500_charger_vbus_drop_end_work); 35918c0984e5SSebastian Reichel 35928c0984e5SSebastian Reichel /* Init work for charger detection */ 35938c0984e5SSebastian Reichel INIT_WORK(&di->usb_link_status_work, 35948c0984e5SSebastian Reichel ab8500_charger_usb_link_status_work); 35958c0984e5SSebastian Reichel INIT_WORK(&di->ac_work, ab8500_charger_ac_work); 35968c0984e5SSebastian Reichel INIT_WORK(&di->detect_usb_type_work, 35978c0984e5SSebastian Reichel ab8500_charger_detect_usb_type_work); 35988c0984e5SSebastian Reichel 35998c0984e5SSebastian Reichel /* Init work for checking HW status */ 36008c0984e5SSebastian Reichel INIT_WORK(&di->check_main_thermal_prot_work, 36018c0984e5SSebastian Reichel ab8500_charger_check_main_thermal_prot_work); 36028c0984e5SSebastian Reichel INIT_WORK(&di->check_usb_thermal_prot_work, 36038c0984e5SSebastian Reichel ab8500_charger_check_usb_thermal_prot_work); 36048c0984e5SSebastian Reichel 36058c0984e5SSebastian Reichel 36068c0984e5SSebastian Reichel /* Initialize OVV, and other registers */ 36078c0984e5SSebastian Reichel ret = ab8500_charger_init_hw_registers(di); 36088c0984e5SSebastian Reichel if (ret) { 3609ad89cb5fSLinus Walleij dev_err(dev, "failed to initialize ABB registers\n"); 36101c1f13a0SLinus Walleij return ret; 36118c0984e5SSebastian Reichel } 36128c0984e5SSebastian Reichel 36138c0984e5SSebastian Reichel /* Register AC charger class */ 36148c0984e5SSebastian Reichel if (di->ac_chg.enabled) { 36151c1f13a0SLinus Walleij di->ac_chg.psy = devm_power_supply_register(dev, 36168c0984e5SSebastian Reichel &ab8500_ac_chg_desc, 36178c0984e5SSebastian Reichel &ac_psy_cfg); 36188c0984e5SSebastian Reichel if (IS_ERR(di->ac_chg.psy)) { 3619ad89cb5fSLinus Walleij dev_err(dev, "failed to register AC charger\n"); 36201c1f13a0SLinus Walleij return PTR_ERR(di->ac_chg.psy); 36218c0984e5SSebastian Reichel } 36228c0984e5SSebastian Reichel } 36238c0984e5SSebastian Reichel 36248c0984e5SSebastian Reichel /* Register USB charger class */ 36251c1f13a0SLinus Walleij di->usb_chg.psy = devm_power_supply_register(dev, 36268c0984e5SSebastian Reichel &ab8500_usb_chg_desc, 36278c0984e5SSebastian Reichel &usb_psy_cfg); 36288c0984e5SSebastian Reichel if (IS_ERR(di->usb_chg.psy)) { 3629ad89cb5fSLinus Walleij dev_err(dev, "failed to register USB charger\n"); 36301c1f13a0SLinus Walleij return PTR_ERR(di->usb_chg.psy); 36318c0984e5SSebastian Reichel } 36328c0984e5SSebastian Reichel 363359f1b854SLinus Walleij /* 363459f1b854SLinus Walleij * Check what battery we have, since we always have the USB 363559f1b854SLinus Walleij * psy, use that as a handle. 363659f1b854SLinus Walleij */ 363759f1b854SLinus Walleij ret = ab8500_bm_of_probe(di->usb_chg.psy, di->bm); 363859f1b854SLinus Walleij if (ret) 363959f1b854SLinus Walleij return dev_err_probe(dev, ret, 364059f1b854SLinus Walleij "failed to get battery information\n"); 364159f1b854SLinus Walleij 36428c0984e5SSebastian Reichel /* Identify the connected charger types during startup */ 36438c0984e5SSebastian Reichel charger_status = ab8500_charger_detect_chargers(di, true); 36448c0984e5SSebastian Reichel if (charger_status & AC_PW_CONN) { 36458c0984e5SSebastian Reichel di->ac.charger_connected = 1; 36468c0984e5SSebastian Reichel di->ac_conn = true; 36478c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 36488c0984e5SSebastian Reichel sysfs_notify(&di->ac_chg.psy->dev.kobj, NULL, "present"); 36498c0984e5SSebastian Reichel } 36508c0984e5SSebastian Reichel 36518c0984e5SSebastian Reichel platform_set_drvdata(pdev, di); 36528c0984e5SSebastian Reichel 36531c1f13a0SLinus Walleij /* Create something that will match the subdrivers when we bind */ 36541c1f13a0SLinus Walleij for (i = 0; i < ARRAY_SIZE(ab8500_charger_component_drivers); i++) { 36551c1f13a0SLinus Walleij struct device_driver *drv = &ab8500_charger_component_drivers[i]->driver; 36561c1f13a0SLinus Walleij struct device *p = NULL, *d; 36578c0984e5SSebastian Reichel 36581c1f13a0SLinus Walleij while ((d = platform_find_device_by_driver(p, drv))) { 36591c1f13a0SLinus Walleij put_device(p); 36601c1f13a0SLinus Walleij component_match_add(dev, &match, 36611c1f13a0SLinus Walleij ab8500_charger_compare_dev, d); 36621c1f13a0SLinus Walleij p = d; 36638c0984e5SSebastian Reichel } 36641c1f13a0SLinus Walleij put_device(p); 36651c1f13a0SLinus Walleij } 36661c1f13a0SLinus Walleij if (!match) { 36671c1f13a0SLinus Walleij dev_err(dev, "no matching components\n"); 3668*be2c0d54SChristophe JAILLET ret = -ENODEV; 3669*be2c0d54SChristophe JAILLET goto remove_ab8500_bm; 36701c1f13a0SLinus Walleij } 36711c1f13a0SLinus Walleij if (IS_ERR(match)) { 36721c1f13a0SLinus Walleij dev_err(dev, "could not create component match\n"); 3673*be2c0d54SChristophe JAILLET ret = PTR_ERR(match); 3674*be2c0d54SChristophe JAILLET goto remove_ab8500_bm; 36758c0984e5SSebastian Reichel } 36768c0984e5SSebastian Reichel 36771c1f13a0SLinus Walleij /* Notifier for external charger enabling */ 36781c1f13a0SLinus Walleij if (!di->ac_chg.enabled) 36791c1f13a0SLinus Walleij blocking_notifier_chain_register( 36801c1f13a0SLinus Walleij &charger_notifier_list, &charger_nb); 36818c0984e5SSebastian Reichel 36828c0984e5SSebastian Reichel 36831c1f13a0SLinus Walleij di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2); 36841c1f13a0SLinus Walleij if (IS_ERR_OR_NULL(di->usb_phy)) { 36851c1f13a0SLinus Walleij dev_err(dev, "failed to get usb transceiver\n"); 36861c1f13a0SLinus Walleij ret = -EINVAL; 36871c1f13a0SLinus Walleij goto out_charger_notifier; 36881c1f13a0SLinus Walleij } 36891c1f13a0SLinus Walleij di->nb.notifier_call = ab8500_charger_usb_notifier_call; 36901c1f13a0SLinus Walleij ret = usb_register_notifier(di->usb_phy, &di->nb); 36911c1f13a0SLinus Walleij if (ret) { 36921c1f13a0SLinus Walleij dev_err(dev, "failed to register usb notifier\n"); 36931c1f13a0SLinus Walleij goto put_usb_phy; 36941c1f13a0SLinus Walleij } 36951c1f13a0SLinus Walleij 36961c1f13a0SLinus Walleij 36971c1f13a0SLinus Walleij ret = component_master_add_with_match(&pdev->dev, 36981c1f13a0SLinus Walleij &ab8500_charger_comp_ops, 36991c1f13a0SLinus Walleij match); 37001c1f13a0SLinus Walleij if (ret) { 37011c1f13a0SLinus Walleij dev_err(dev, "failed to add component master\n"); 37021c1f13a0SLinus Walleij goto free_notifier; 37031c1f13a0SLinus Walleij } 37041c1f13a0SLinus Walleij 37051c1f13a0SLinus Walleij return 0; 37061c1f13a0SLinus Walleij 37071c1f13a0SLinus Walleij free_notifier: 37088c0984e5SSebastian Reichel usb_unregister_notifier(di->usb_phy, &di->nb); 37098c0984e5SSebastian Reichel put_usb_phy: 37108c0984e5SSebastian Reichel usb_put_phy(di->usb_phy); 37111c1f13a0SLinus Walleij out_charger_notifier: 37121c1f13a0SLinus Walleij if (!di->ac_chg.enabled) 37131c1f13a0SLinus Walleij blocking_notifier_chain_unregister( 37141c1f13a0SLinus Walleij &charger_notifier_list, &charger_nb); 3715*be2c0d54SChristophe JAILLET remove_ab8500_bm: 3716*be2c0d54SChristophe JAILLET ab8500_bm_of_remove(di->usb_chg.psy, di->bm); 37178c0984e5SSebastian Reichel return ret; 37188c0984e5SSebastian Reichel } 37198c0984e5SSebastian Reichel 37201c1f13a0SLinus Walleij static int ab8500_charger_remove(struct platform_device *pdev) 37211c1f13a0SLinus Walleij { 37221c1f13a0SLinus Walleij struct ab8500_charger *di = platform_get_drvdata(pdev); 37231c1f13a0SLinus Walleij 37241c1f13a0SLinus Walleij component_master_del(&pdev->dev, &ab8500_charger_comp_ops); 37251c1f13a0SLinus Walleij 37261c1f13a0SLinus Walleij usb_unregister_notifier(di->usb_phy, &di->nb); 37276252c706SLinus Walleij ab8500_bm_of_remove(di->usb_chg.psy, di->bm); 37281c1f13a0SLinus Walleij usb_put_phy(di->usb_phy); 37291c1f13a0SLinus Walleij if (!di->ac_chg.enabled) 37301c1f13a0SLinus Walleij blocking_notifier_chain_unregister( 37311c1f13a0SLinus Walleij &charger_notifier_list, &charger_nb); 37321c1f13a0SLinus Walleij 37331c1f13a0SLinus Walleij return 0; 37341c1f13a0SLinus Walleij } 37351c1f13a0SLinus Walleij 3736f8efa0a8SLinus Walleij static SIMPLE_DEV_PM_OPS(ab8500_charger_pm_ops, ab8500_charger_suspend, ab8500_charger_resume); 3737f8efa0a8SLinus Walleij 37388c0984e5SSebastian Reichel static const struct of_device_id ab8500_charger_match[] = { 37398c0984e5SSebastian Reichel { .compatible = "stericsson,ab8500-charger", }, 37408c0984e5SSebastian Reichel { }, 37418c0984e5SSebastian Reichel }; 3742dfe52db1SZou Wei MODULE_DEVICE_TABLE(of, ab8500_charger_match); 37438c0984e5SSebastian Reichel 37448c0984e5SSebastian Reichel static struct platform_driver ab8500_charger_driver = { 37458c0984e5SSebastian Reichel .probe = ab8500_charger_probe, 37468c0984e5SSebastian Reichel .remove = ab8500_charger_remove, 37478c0984e5SSebastian Reichel .driver = { 37488c0984e5SSebastian Reichel .name = "ab8500-charger", 37498c0984e5SSebastian Reichel .of_match_table = ab8500_charger_match, 3750f8efa0a8SLinus Walleij .pm = &ab8500_charger_pm_ops, 37518c0984e5SSebastian Reichel }, 37528c0984e5SSebastian Reichel }; 37538c0984e5SSebastian Reichel 37548c0984e5SSebastian Reichel static int __init ab8500_charger_init(void) 37558c0984e5SSebastian Reichel { 37561c1f13a0SLinus Walleij int ret; 37571c1f13a0SLinus Walleij 37581c1f13a0SLinus Walleij ret = platform_register_drivers(ab8500_charger_component_drivers, 37591c1f13a0SLinus Walleij ARRAY_SIZE(ab8500_charger_component_drivers)); 37601c1f13a0SLinus Walleij if (ret) 37611c1f13a0SLinus Walleij return ret; 37621c1f13a0SLinus Walleij 37638c0984e5SSebastian Reichel return platform_driver_register(&ab8500_charger_driver); 37648c0984e5SSebastian Reichel } 37658c0984e5SSebastian Reichel 37668c0984e5SSebastian Reichel static void __exit ab8500_charger_exit(void) 37678c0984e5SSebastian Reichel { 37681c1f13a0SLinus Walleij platform_unregister_drivers(ab8500_charger_component_drivers, 37691c1f13a0SLinus Walleij ARRAY_SIZE(ab8500_charger_component_drivers)); 37708c0984e5SSebastian Reichel platform_driver_unregister(&ab8500_charger_driver); 37718c0984e5SSebastian Reichel } 37728c0984e5SSebastian Reichel 37731c1f13a0SLinus Walleij module_init(ab8500_charger_init); 37748c0984e5SSebastian Reichel module_exit(ab8500_charger_exit); 37758c0984e5SSebastian Reichel 37768c0984e5SSebastian Reichel MODULE_LICENSE("GPL v2"); 37778c0984e5SSebastian Reichel MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy"); 37788c0984e5SSebastian Reichel MODULE_ALIAS("platform:ab8500-charger"); 37798c0984e5SSebastian Reichel MODULE_DESCRIPTION("AB8500 charger management driver"); 3780