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 16621ad180dSLinus Walleij #define VBAT_TRESH_IP_CUR_RED 3800000 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 /** 1748f5b3739SHong Peng * struct ab8500_charger_interrupts - ab8500 interrupts 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 10868f5b3739SHong Peng * @di: pointer to the ab8500_charger structure 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 /** 17208c0984e5SSebastian Reichel * ab8500_charger_usb_check_enable() - enable usb charging 17218c0984e5SSebastian Reichel * @charger: pointer to the ux500_charger structure 1722bc6e0287SLinus Walleij * @vset_uv: charging voltage in microvolt 172383e5aa77SLinus Walleij * @iset_ua: charger output current in microampere 17248c0984e5SSebastian Reichel * 17258c0984e5SSebastian Reichel * Check if the VBUS charger has been disconnected and reconnected without 17268c0984e5SSebastian Reichel * AB8500 rising an interrupt. Returns 0 on success. 17278c0984e5SSebastian Reichel */ 17288c0984e5SSebastian Reichel static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, 1729bc6e0287SLinus Walleij int vset_uv, int iset_ua) 17308c0984e5SSebastian Reichel { 17318c0984e5SSebastian Reichel u8 usbch_ctrl1 = 0; 17328c0984e5SSebastian Reichel int ret = 0; 17338c0984e5SSebastian Reichel 17348c0984e5SSebastian Reichel struct ab8500_charger *di = to_ab8500_charger_usb_device_info(charger); 17358c0984e5SSebastian Reichel 17368c0984e5SSebastian Reichel if (!di->usb.charger_connected) 17378c0984e5SSebastian Reichel return ret; 17388c0984e5SSebastian Reichel 17398c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 17408c0984e5SSebastian Reichel AB8500_USBCH_CTRL1_REG, &usbch_ctrl1); 17418c0984e5SSebastian Reichel if (ret < 0) { 17428c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 read failed %d\n", __LINE__); 17438c0984e5SSebastian Reichel return ret; 17448c0984e5SSebastian Reichel } 17458c0984e5SSebastian Reichel dev_dbg(di->dev, "USB charger ctrl: 0x%02x\n", usbch_ctrl1); 17468c0984e5SSebastian Reichel 17478c0984e5SSebastian Reichel if (!(usbch_ctrl1 & USB_CH_ENA)) { 17488c0984e5SSebastian Reichel dev_info(di->dev, "Charging has been disabled abnormally and will be re-enabled\n"); 17498c0984e5SSebastian Reichel 17508c0984e5SSebastian Reichel ret = abx500_mask_and_set_register_interruptible(di->dev, 17518c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CHARGER_CTRL, 17528c0984e5SSebastian Reichel DROP_COUNT_RESET, DROP_COUNT_RESET); 17538c0984e5SSebastian Reichel if (ret < 0) { 17548c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 write failed %d\n", __LINE__); 17558c0984e5SSebastian Reichel return ret; 17568c0984e5SSebastian Reichel } 17578c0984e5SSebastian Reichel 1758bc6e0287SLinus Walleij ret = ab8500_charger_usb_en(&di->usb_chg, true, vset_uv, iset_ua); 17598c0984e5SSebastian Reichel if (ret < 0) { 17608c0984e5SSebastian Reichel dev_err(di->dev, "Failed to enable VBUS charger %d\n", 17618c0984e5SSebastian Reichel __LINE__); 17628c0984e5SSebastian Reichel return ret; 17638c0984e5SSebastian Reichel } 17648c0984e5SSebastian Reichel } 17658c0984e5SSebastian Reichel return ret; 17668c0984e5SSebastian Reichel } 17678c0984e5SSebastian Reichel 17688c0984e5SSebastian Reichel /** 17698c0984e5SSebastian Reichel * ab8500_charger_ac_check_enable() - enable usb charging 17708c0984e5SSebastian Reichel * @charger: pointer to the ux500_charger structure 1771bc6e0287SLinus Walleij * @vset_uv: charging voltage in microvolt 177283e5aa77SLinus Walleij * @iset_ua: charger output current in micrompere 17738c0984e5SSebastian Reichel * 17748c0984e5SSebastian Reichel * Check if the AC charger has been disconnected and reconnected without 17758c0984e5SSebastian Reichel * AB8500 rising an interrupt. Returns 0 on success. 17768c0984e5SSebastian Reichel */ 17778c0984e5SSebastian Reichel static int ab8500_charger_ac_check_enable(struct ux500_charger *charger, 1778bc6e0287SLinus Walleij int vset_uv, int iset_ua) 17798c0984e5SSebastian Reichel { 17808c0984e5SSebastian Reichel u8 mainch_ctrl1 = 0; 17818c0984e5SSebastian Reichel int ret = 0; 17828c0984e5SSebastian Reichel 17838c0984e5SSebastian Reichel struct ab8500_charger *di = to_ab8500_charger_ac_device_info(charger); 17848c0984e5SSebastian Reichel 17858c0984e5SSebastian Reichel if (!di->ac.charger_connected) 17868c0984e5SSebastian Reichel return ret; 17878c0984e5SSebastian Reichel 17888c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 17898c0984e5SSebastian Reichel AB8500_MCH_CTRL1, &mainch_ctrl1); 17908c0984e5SSebastian Reichel if (ret < 0) { 17918c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 read failed %d\n", __LINE__); 17928c0984e5SSebastian Reichel return ret; 17938c0984e5SSebastian Reichel } 17948c0984e5SSebastian Reichel dev_dbg(di->dev, "AC charger ctrl: 0x%02x\n", mainch_ctrl1); 17958c0984e5SSebastian Reichel 17968c0984e5SSebastian Reichel if (!(mainch_ctrl1 & MAIN_CH_ENA)) { 17978c0984e5SSebastian Reichel dev_info(di->dev, "Charging has been disabled abnormally and will be re-enabled\n"); 17988c0984e5SSebastian Reichel 17998c0984e5SSebastian Reichel ret = abx500_mask_and_set_register_interruptible(di->dev, 18008c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CHARGER_CTRL, 18018c0984e5SSebastian Reichel DROP_COUNT_RESET, DROP_COUNT_RESET); 18028c0984e5SSebastian Reichel 18038c0984e5SSebastian Reichel if (ret < 0) { 18048c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 write failed %d\n", __LINE__); 18058c0984e5SSebastian Reichel return ret; 18068c0984e5SSebastian Reichel } 18078c0984e5SSebastian Reichel 1808bc6e0287SLinus Walleij ret = ab8500_charger_ac_en(&di->usb_chg, true, vset_uv, iset_ua); 18098c0984e5SSebastian Reichel if (ret < 0) { 18108c0984e5SSebastian Reichel dev_err(di->dev, "failed to enable AC charger %d\n", 18118c0984e5SSebastian Reichel __LINE__); 18128c0984e5SSebastian Reichel return ret; 18138c0984e5SSebastian Reichel } 18148c0984e5SSebastian Reichel } 18158c0984e5SSebastian Reichel return ret; 18168c0984e5SSebastian Reichel } 18178c0984e5SSebastian Reichel 18188c0984e5SSebastian Reichel /** 18198c0984e5SSebastian Reichel * ab8500_charger_watchdog_kick() - kick charger watchdog 18208c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 18218c0984e5SSebastian Reichel * 18228c0984e5SSebastian Reichel * Kick charger watchdog 18238c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 18248c0984e5SSebastian Reichel */ 18258c0984e5SSebastian Reichel static int ab8500_charger_watchdog_kick(struct ux500_charger *charger) 18268c0984e5SSebastian Reichel { 18278c0984e5SSebastian Reichel int ret; 18288c0984e5SSebastian Reichel struct ab8500_charger *di; 18298c0984e5SSebastian Reichel 18308c0984e5SSebastian Reichel if (charger->psy->desc->type == POWER_SUPPLY_TYPE_MAINS) 18318c0984e5SSebastian Reichel di = to_ab8500_charger_ac_device_info(charger); 18328c0984e5SSebastian Reichel else if (charger->psy->desc->type == POWER_SUPPLY_TYPE_USB) 18338c0984e5SSebastian Reichel di = to_ab8500_charger_usb_device_info(charger); 18348c0984e5SSebastian Reichel else 18358c0984e5SSebastian Reichel return -ENXIO; 18368c0984e5SSebastian Reichel 18378c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 18388c0984e5SSebastian Reichel AB8500_CHARG_WD_CTRL, CHARG_WD_KICK); 18398c0984e5SSebastian Reichel if (ret) 18408c0984e5SSebastian Reichel dev_err(di->dev, "Failed to kick WD!\n"); 18418c0984e5SSebastian Reichel 18428c0984e5SSebastian Reichel return ret; 18438c0984e5SSebastian Reichel } 18448c0984e5SSebastian Reichel 18458c0984e5SSebastian Reichel /** 18468c0984e5SSebastian Reichel * ab8500_charger_update_charger_current() - update charger current 184783e5aa77SLinus Walleij * @charger: pointer to the ab8500_charger structure 184883e5aa77SLinus Walleij * @ich_out_ua: desired output current in microampere 18498c0984e5SSebastian Reichel * 18508c0984e5SSebastian Reichel * Update the charger output current for the specified charger 18518c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 18528c0984e5SSebastian Reichel */ 18538c0984e5SSebastian Reichel static int ab8500_charger_update_charger_current(struct ux500_charger *charger, 185483e5aa77SLinus Walleij int ich_out_ua) 18558c0984e5SSebastian Reichel { 18568c0984e5SSebastian Reichel int ret; 18578c0984e5SSebastian Reichel struct ab8500_charger *di; 18588c0984e5SSebastian Reichel 18598c0984e5SSebastian Reichel if (charger->psy->desc->type == POWER_SUPPLY_TYPE_MAINS) 18608c0984e5SSebastian Reichel di = to_ab8500_charger_ac_device_info(charger); 18618c0984e5SSebastian Reichel else if (charger->psy->desc->type == POWER_SUPPLY_TYPE_USB) 18628c0984e5SSebastian Reichel di = to_ab8500_charger_usb_device_info(charger); 18638c0984e5SSebastian Reichel else 18648c0984e5SSebastian Reichel return -ENXIO; 18658c0984e5SSebastian Reichel 186683e5aa77SLinus Walleij ret = ab8500_charger_set_output_curr(di, ich_out_ua); 18678c0984e5SSebastian Reichel if (ret) { 18688c0984e5SSebastian Reichel dev_err(di->dev, "%s " 18698c0984e5SSebastian Reichel "Failed to set ChOutputCurentLevel\n", 18708c0984e5SSebastian Reichel __func__); 18718c0984e5SSebastian Reichel return ret; 18728c0984e5SSebastian Reichel } 18738c0984e5SSebastian Reichel 18748c0984e5SSebastian Reichel /* Reset the main and usb drop input current measurement counter */ 18758c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 18768c0984e5SSebastian Reichel AB8500_CHARGER_CTRL, DROP_COUNT_RESET); 18778c0984e5SSebastian Reichel if (ret) { 18788c0984e5SSebastian Reichel dev_err(di->dev, "%s write failed\n", __func__); 18798c0984e5SSebastian Reichel return ret; 18808c0984e5SSebastian Reichel } 18818c0984e5SSebastian Reichel 18828c0984e5SSebastian Reichel return ret; 18838c0984e5SSebastian Reichel } 18848c0984e5SSebastian Reichel 18858c0984e5SSebastian Reichel static int ab8500_charger_get_ext_psy_data(struct device *dev, void *data) 18868c0984e5SSebastian Reichel { 18878c0984e5SSebastian Reichel struct power_supply *psy; 18888c0984e5SSebastian Reichel struct power_supply *ext = dev_get_drvdata(dev); 18898c0984e5SSebastian Reichel const char **supplicants = (const char **)ext->supplied_to; 18908c0984e5SSebastian Reichel struct ab8500_charger *di; 18918c0984e5SSebastian Reichel union power_supply_propval ret; 18928c0984e5SSebastian Reichel int j; 18938c0984e5SSebastian Reichel struct ux500_charger *usb_chg; 18948c0984e5SSebastian Reichel 18958c0984e5SSebastian Reichel usb_chg = (struct ux500_charger *)data; 18968c0984e5SSebastian Reichel psy = usb_chg->psy; 18978c0984e5SSebastian Reichel 18988c0984e5SSebastian Reichel di = to_ab8500_charger_usb_device_info(usb_chg); 18998c0984e5SSebastian Reichel 190021ad180dSLinus Walleij /* 190121ad180dSLinus Walleij * For all psy where the driver name appears in any supplied_to 190221ad180dSLinus Walleij * in practice what we will find will always be "ab8500_fg" as 190321ad180dSLinus Walleij * the fuel gauge is responsible of keeping track of VBAT. 190421ad180dSLinus Walleij */ 19058c0984e5SSebastian Reichel j = match_string(supplicants, ext->num_supplicants, psy->desc->name); 19068c0984e5SSebastian Reichel if (j < 0) 19078c0984e5SSebastian Reichel return 0; 19088c0984e5SSebastian Reichel 19098c0984e5SSebastian Reichel /* Go through all properties for the psy */ 19108c0984e5SSebastian Reichel for (j = 0; j < ext->desc->num_properties; j++) { 19118c0984e5SSebastian Reichel enum power_supply_property prop; 19128c0984e5SSebastian Reichel prop = ext->desc->properties[j]; 19138c0984e5SSebastian Reichel 19148c0984e5SSebastian Reichel if (power_supply_get_property(ext, prop, &ret)) 19158c0984e5SSebastian Reichel continue; 19168c0984e5SSebastian Reichel 19178c0984e5SSebastian Reichel switch (prop) { 19188c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_NOW: 19198c0984e5SSebastian Reichel switch (ext->desc->type) { 19208c0984e5SSebastian Reichel case POWER_SUPPLY_TYPE_BATTERY: 192121ad180dSLinus Walleij /* This will always be "ab8500_fg" */ 192221ad180dSLinus Walleij dev_dbg(di->dev, "get VBAT from %s\n", 192321ad180dSLinus Walleij dev_name(&ext->dev)); 192421ad180dSLinus Walleij di->vbat = ret.intval; 19258c0984e5SSebastian Reichel break; 19268c0984e5SSebastian Reichel default: 19278c0984e5SSebastian Reichel break; 19288c0984e5SSebastian Reichel } 19298c0984e5SSebastian Reichel break; 19308c0984e5SSebastian Reichel default: 19318c0984e5SSebastian Reichel break; 19328c0984e5SSebastian Reichel } 19338c0984e5SSebastian Reichel } 19348c0984e5SSebastian Reichel return 0; 19358c0984e5SSebastian Reichel } 19368c0984e5SSebastian Reichel 19378c0984e5SSebastian Reichel /** 19388c0984e5SSebastian Reichel * ab8500_charger_check_vbat_work() - keep vbus current within spec 19398c0984e5SSebastian Reichel * @work pointer to the work_struct structure 19408c0984e5SSebastian Reichel * 19418c0984e5SSebastian Reichel * Due to a asic bug it is necessary to lower the input current to the vbus 19428c0984e5SSebastian Reichel * charger when charging with at some specific levels. This issue is only valid 194303b33d4aSwangjianli * for below a certain battery voltage. This function makes sure that 19448c0984e5SSebastian Reichel * the allowed current limit isn't exceeded. 19458c0984e5SSebastian Reichel */ 19468c0984e5SSebastian Reichel static void ab8500_charger_check_vbat_work(struct work_struct *work) 19478c0984e5SSebastian Reichel { 19488c0984e5SSebastian Reichel int t = 10; 19498c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 19508c0984e5SSebastian Reichel struct ab8500_charger, check_vbat_work.work); 19518c0984e5SSebastian Reichel 19528c0984e5SSebastian Reichel class_for_each_device(power_supply_class, NULL, 195321ad180dSLinus Walleij &di->usb_chg, ab8500_charger_get_ext_psy_data); 19548c0984e5SSebastian Reichel 19558c0984e5SSebastian Reichel /* First run old_vbat is 0. */ 19568c0984e5SSebastian Reichel if (di->old_vbat == 0) 19578c0984e5SSebastian Reichel di->old_vbat = di->vbat; 19588c0984e5SSebastian Reichel 19598c0984e5SSebastian Reichel if (!((di->old_vbat <= VBAT_TRESH_IP_CUR_RED && 19608c0984e5SSebastian Reichel di->vbat <= VBAT_TRESH_IP_CUR_RED) || 19618c0984e5SSebastian Reichel (di->old_vbat > VBAT_TRESH_IP_CUR_RED && 19628c0984e5SSebastian Reichel di->vbat > VBAT_TRESH_IP_CUR_RED))) { 19638c0984e5SSebastian Reichel 19648c0984e5SSebastian Reichel dev_dbg(di->dev, "Vbat did cross threshold, curr: %d, new: %d," 196583e5aa77SLinus Walleij " old: %d\n", di->max_usb_in_curr.usb_type_max_ua, 19668c0984e5SSebastian Reichel di->vbat, di->old_vbat); 19678c0984e5SSebastian Reichel ab8500_charger_set_vbus_in_curr(di, 196883e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua); 19698c0984e5SSebastian Reichel power_supply_changed(di->usb_chg.psy); 19708c0984e5SSebastian Reichel } 19718c0984e5SSebastian Reichel 19728c0984e5SSebastian Reichel di->old_vbat = di->vbat; 19738c0984e5SSebastian Reichel 19748c0984e5SSebastian Reichel /* 19758c0984e5SSebastian Reichel * No need to check the battery voltage every second when not close to 19768c0984e5SSebastian Reichel * the threshold. 19778c0984e5SSebastian Reichel */ 197821ad180dSLinus Walleij if (di->vbat < (VBAT_TRESH_IP_CUR_RED + 100000) && 197921ad180dSLinus Walleij (di->vbat > (VBAT_TRESH_IP_CUR_RED - 100000))) 19808c0984e5SSebastian Reichel t = 1; 19818c0984e5SSebastian Reichel 19828c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->check_vbat_work, t * HZ); 19838c0984e5SSebastian Reichel } 19848c0984e5SSebastian Reichel 19858c0984e5SSebastian Reichel /** 19868c0984e5SSebastian Reichel * ab8500_charger_check_hw_failure_work() - check main charger failure 19878c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 19888c0984e5SSebastian Reichel * 19898c0984e5SSebastian Reichel * Work queue function for checking the main charger status 19908c0984e5SSebastian Reichel */ 19918c0984e5SSebastian Reichel static void ab8500_charger_check_hw_failure_work(struct work_struct *work) 19928c0984e5SSebastian Reichel { 19938c0984e5SSebastian Reichel int ret; 19948c0984e5SSebastian Reichel u8 reg_value; 19958c0984e5SSebastian Reichel 19968c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 19978c0984e5SSebastian Reichel struct ab8500_charger, check_hw_failure_work.work); 19988c0984e5SSebastian Reichel 19998c0984e5SSebastian Reichel /* Check if the status bits for HW failure is still active */ 20008c0984e5SSebastian Reichel if (di->flags.mainextchnotok) { 20018c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 20028c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_STATUS2_REG, ®_value); 20038c0984e5SSebastian Reichel if (ret < 0) { 20048c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 20058c0984e5SSebastian Reichel return; 20068c0984e5SSebastian Reichel } 20078c0984e5SSebastian Reichel if (!(reg_value & MAIN_CH_NOK)) { 20088c0984e5SSebastian Reichel di->flags.mainextchnotok = false; 20098c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 20108c0984e5SSebastian Reichel } 20118c0984e5SSebastian Reichel } 20128c0984e5SSebastian Reichel if (di->flags.vbus_ovv) { 20138c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 20148c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG, 20158c0984e5SSebastian Reichel ®_value); 20168c0984e5SSebastian Reichel if (ret < 0) { 20178c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 20188c0984e5SSebastian Reichel return; 20198c0984e5SSebastian Reichel } 20208c0984e5SSebastian Reichel if (!(reg_value & VBUS_OVV_TH)) { 20218c0984e5SSebastian Reichel di->flags.vbus_ovv = false; 20228c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 20238c0984e5SSebastian Reichel } 20248c0984e5SSebastian Reichel } 20258c0984e5SSebastian Reichel /* If we still have a failure, schedule a new check */ 20268c0984e5SSebastian Reichel if (di->flags.mainextchnotok || di->flags.vbus_ovv) { 20278c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 20288c0984e5SSebastian Reichel &di->check_hw_failure_work, round_jiffies(HZ)); 20298c0984e5SSebastian Reichel } 20308c0984e5SSebastian Reichel } 20318c0984e5SSebastian Reichel 20328c0984e5SSebastian Reichel /** 20338c0984e5SSebastian Reichel * ab8500_charger_kick_watchdog_work() - kick the watchdog 20348c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 20358c0984e5SSebastian Reichel * 20368c0984e5SSebastian Reichel * Work queue function for kicking the charger watchdog. 20378c0984e5SSebastian Reichel * 20388c0984e5SSebastian Reichel * For ABB revision 1.0 and 1.1 there is a bug in the watchdog 2039ddb74e98SAshish Chavan * logic. That means we have to continuously kick the charger 20408c0984e5SSebastian Reichel * watchdog even when no charger is connected. This is only 20418c0984e5SSebastian Reichel * valid once the AC charger has been enabled. This is 20428c0984e5SSebastian Reichel * a bug that is not handled by the algorithm and the 20438c0984e5SSebastian Reichel * watchdog have to be kicked by the charger driver 20448c0984e5SSebastian Reichel * when the AC charger is disabled 20458c0984e5SSebastian Reichel */ 20468c0984e5SSebastian Reichel static void ab8500_charger_kick_watchdog_work(struct work_struct *work) 20478c0984e5SSebastian Reichel { 20488c0984e5SSebastian Reichel int ret; 20498c0984e5SSebastian Reichel 20508c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 20518c0984e5SSebastian Reichel struct ab8500_charger, kick_wd_work.work); 20528c0984e5SSebastian Reichel 20538c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 20548c0984e5SSebastian Reichel AB8500_CHARG_WD_CTRL, CHARG_WD_KICK); 20558c0984e5SSebastian Reichel if (ret) 20568c0984e5SSebastian Reichel dev_err(di->dev, "Failed to kick WD!\n"); 20578c0984e5SSebastian Reichel 20588c0984e5SSebastian Reichel /* Schedule a new watchdog kick */ 20598c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 20608c0984e5SSebastian Reichel &di->kick_wd_work, round_jiffies(WD_KICK_INTERVAL)); 20618c0984e5SSebastian Reichel } 20628c0984e5SSebastian Reichel 20638c0984e5SSebastian Reichel /** 20648c0984e5SSebastian Reichel * ab8500_charger_ac_work() - work to get and set main charger status 20658c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 20668c0984e5SSebastian Reichel * 20678c0984e5SSebastian Reichel * Work queue function for checking the main charger status 20688c0984e5SSebastian Reichel */ 20698c0984e5SSebastian Reichel static void ab8500_charger_ac_work(struct work_struct *work) 20708c0984e5SSebastian Reichel { 20718c0984e5SSebastian Reichel int ret; 20728c0984e5SSebastian Reichel 20738c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 20748c0984e5SSebastian Reichel struct ab8500_charger, ac_work); 20758c0984e5SSebastian Reichel 20768c0984e5SSebastian Reichel /* 20778c0984e5SSebastian Reichel * Since we can't be sure that the events are received 20788c0984e5SSebastian Reichel * synchronously, we have the check if the main charger is 20798c0984e5SSebastian Reichel * connected by reading the status register 20808c0984e5SSebastian Reichel */ 20818c0984e5SSebastian Reichel ret = ab8500_charger_detect_chargers(di, false); 20828c0984e5SSebastian Reichel if (ret < 0) 20838c0984e5SSebastian Reichel return; 20848c0984e5SSebastian Reichel 20858c0984e5SSebastian Reichel if (ret & AC_PW_CONN) { 20868c0984e5SSebastian Reichel di->ac.charger_connected = 1; 20878c0984e5SSebastian Reichel di->ac_conn = true; 20888c0984e5SSebastian Reichel } else { 20898c0984e5SSebastian Reichel di->ac.charger_connected = 0; 20908c0984e5SSebastian Reichel } 20918c0984e5SSebastian Reichel 20928c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 20938c0984e5SSebastian Reichel sysfs_notify(&di->ac_chg.psy->dev.kobj, NULL, "present"); 20948c0984e5SSebastian Reichel } 20958c0984e5SSebastian Reichel 20968c0984e5SSebastian Reichel static void ab8500_charger_usb_attached_work(struct work_struct *work) 20978c0984e5SSebastian Reichel { 20988c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 20998c0984e5SSebastian Reichel struct ab8500_charger, 21008c0984e5SSebastian Reichel usb_charger_attached_work.work); 21018c0984e5SSebastian Reichel int usbch = (USB_CH_VBUSDROP | USB_CH_VBUSDETDBNC); 21028c0984e5SSebastian Reichel int ret, i; 21038c0984e5SSebastian Reichel u8 statval; 21048c0984e5SSebastian Reichel 21058c0984e5SSebastian Reichel for (i = 0; i < 10; i++) { 21068c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 21078c0984e5SSebastian Reichel AB8500_CHARGER, 21088c0984e5SSebastian Reichel AB8500_CH_USBCH_STAT1_REG, 21098c0984e5SSebastian Reichel &statval); 21108c0984e5SSebastian Reichel if (ret < 0) { 21118c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 read failed %d\n", __LINE__); 21128c0984e5SSebastian Reichel goto reschedule; 21138c0984e5SSebastian Reichel } 21148c0984e5SSebastian Reichel if ((statval & usbch) != usbch) 21158c0984e5SSebastian Reichel goto reschedule; 21168c0984e5SSebastian Reichel 21178c0984e5SSebastian Reichel msleep(CHARGER_STATUS_POLL); 21188c0984e5SSebastian Reichel } 21198c0984e5SSebastian Reichel 21208c0984e5SSebastian Reichel ab8500_charger_usb_en(&di->usb_chg, 0, 0, 0); 21218c0984e5SSebastian Reichel 21228c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 21238c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 21248c0984e5SSebastian Reichel 21258c0984e5SSebastian Reichel return; 21268c0984e5SSebastian Reichel 21278c0984e5SSebastian Reichel reschedule: 21288c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 21298c0984e5SSebastian Reichel &di->usb_charger_attached_work, 21308c0984e5SSebastian Reichel HZ); 21318c0984e5SSebastian Reichel } 21328c0984e5SSebastian Reichel 21338c0984e5SSebastian Reichel static void ab8500_charger_ac_attached_work(struct work_struct *work) 21348c0984e5SSebastian Reichel { 21358c0984e5SSebastian Reichel 21368c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 21378c0984e5SSebastian Reichel struct ab8500_charger, 21388c0984e5SSebastian Reichel ac_charger_attached_work.work); 21398c0984e5SSebastian Reichel int mainch = (MAIN_CH_STATUS2_MAINCHGDROP | 21408c0984e5SSebastian Reichel MAIN_CH_STATUS2_MAINCHARGERDETDBNC); 21418c0984e5SSebastian Reichel int ret, i; 21428c0984e5SSebastian Reichel u8 statval; 21438c0984e5SSebastian Reichel 21448c0984e5SSebastian Reichel for (i = 0; i < 10; i++) { 21458c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 21468c0984e5SSebastian Reichel AB8500_CHARGER, 21478c0984e5SSebastian Reichel AB8500_CH_STATUS2_REG, 21488c0984e5SSebastian Reichel &statval); 21498c0984e5SSebastian Reichel if (ret < 0) { 21508c0984e5SSebastian Reichel dev_err(di->dev, "ab8500 read failed %d\n", __LINE__); 21518c0984e5SSebastian Reichel goto reschedule; 21528c0984e5SSebastian Reichel } 21538c0984e5SSebastian Reichel 21548c0984e5SSebastian Reichel if ((statval & mainch) != mainch) 21558c0984e5SSebastian Reichel goto reschedule; 21568c0984e5SSebastian Reichel 21578c0984e5SSebastian Reichel msleep(CHARGER_STATUS_POLL); 21588c0984e5SSebastian Reichel } 21598c0984e5SSebastian Reichel 21608c0984e5SSebastian Reichel ab8500_charger_ac_en(&di->ac_chg, 0, 0, 0); 21618c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->ac_work); 21628c0984e5SSebastian Reichel 21638c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 21648c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 21658c0984e5SSebastian Reichel 21668c0984e5SSebastian Reichel return; 21678c0984e5SSebastian Reichel 21688c0984e5SSebastian Reichel reschedule: 21698c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 21708c0984e5SSebastian Reichel &di->ac_charger_attached_work, 21718c0984e5SSebastian Reichel HZ); 21728c0984e5SSebastian Reichel } 21738c0984e5SSebastian Reichel 21748c0984e5SSebastian Reichel /** 21758c0984e5SSebastian Reichel * ab8500_charger_detect_usb_type_work() - work to detect USB type 21768c0984e5SSebastian Reichel * @work: Pointer to the work_struct structure 21778c0984e5SSebastian Reichel * 21788c0984e5SSebastian Reichel * Detect the type of USB plugged 21798c0984e5SSebastian Reichel */ 21808c0984e5SSebastian Reichel static void ab8500_charger_detect_usb_type_work(struct work_struct *work) 21818c0984e5SSebastian Reichel { 21828c0984e5SSebastian Reichel int ret; 21838c0984e5SSebastian Reichel 21848c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 21858c0984e5SSebastian Reichel struct ab8500_charger, detect_usb_type_work); 21868c0984e5SSebastian Reichel 21878c0984e5SSebastian Reichel /* 21888c0984e5SSebastian Reichel * Since we can't be sure that the events are received 21898c0984e5SSebastian Reichel * synchronously, we have the check if is 21908c0984e5SSebastian Reichel * connected by reading the status register 21918c0984e5SSebastian Reichel */ 21928c0984e5SSebastian Reichel ret = ab8500_charger_detect_chargers(di, false); 21938c0984e5SSebastian Reichel if (ret < 0) 21948c0984e5SSebastian Reichel return; 21958c0984e5SSebastian Reichel 21968c0984e5SSebastian Reichel if (!(ret & USB_PW_CONN)) { 21978c0984e5SSebastian Reichel dev_dbg(di->dev, "%s di->vbus_detected = false\n", __func__); 21988c0984e5SSebastian Reichel di->vbus_detected = false; 21998c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, false); 22008c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 22018c0984e5SSebastian Reichel } else { 22028c0984e5SSebastian Reichel dev_dbg(di->dev, "%s di->vbus_detected = true\n", __func__); 22038c0984e5SSebastian Reichel di->vbus_detected = true; 22048c0984e5SSebastian Reichel 22058c0984e5SSebastian Reichel if (is_ab8500_1p1_or_earlier(di->parent)) { 22068c0984e5SSebastian Reichel ret = ab8500_charger_detect_usb_type(di); 22078c0984e5SSebastian Reichel if (!ret) { 22088c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, true); 22098c0984e5SSebastian Reichel ab8500_power_supply_changed(di, 22108c0984e5SSebastian Reichel di->usb_chg.psy); 22118c0984e5SSebastian Reichel } 22128c0984e5SSebastian Reichel } else { 22138c0984e5SSebastian Reichel /* 22148c0984e5SSebastian Reichel * For ABB cut2.0 and onwards we have an IRQ, 22158c0984e5SSebastian Reichel * USB_LINK_STATUS that will be triggered when the USB 22168c0984e5SSebastian Reichel * link status changes. The exception is USB connected 22178c0984e5SSebastian Reichel * during startup. Then we don't get a 22188c0984e5SSebastian Reichel * USB_LINK_STATUS IRQ 22198c0984e5SSebastian Reichel */ 22208c0984e5SSebastian Reichel if (di->vbus_detected_start) { 22218c0984e5SSebastian Reichel di->vbus_detected_start = false; 22228c0984e5SSebastian Reichel ret = ab8500_charger_detect_usb_type(di); 22238c0984e5SSebastian Reichel if (!ret) { 22248c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, 22258c0984e5SSebastian Reichel true); 22268c0984e5SSebastian Reichel ab8500_power_supply_changed(di, 22278c0984e5SSebastian Reichel di->usb_chg.psy); 22288c0984e5SSebastian Reichel } 22298c0984e5SSebastian Reichel } 22308c0984e5SSebastian Reichel } 22318c0984e5SSebastian Reichel } 22328c0984e5SSebastian Reichel } 22338c0984e5SSebastian Reichel 22348c0984e5SSebastian Reichel /** 22358c0984e5SSebastian Reichel * ab8500_charger_usb_link_attach_work() - work to detect USB type 22368c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 22378c0984e5SSebastian Reichel * 22388c0984e5SSebastian Reichel * Detect the type of USB plugged 22398c0984e5SSebastian Reichel */ 22408c0984e5SSebastian Reichel static void ab8500_charger_usb_link_attach_work(struct work_struct *work) 22418c0984e5SSebastian Reichel { 22428c0984e5SSebastian Reichel struct ab8500_charger *di = 22438c0984e5SSebastian Reichel container_of(work, struct ab8500_charger, attach_work.work); 22448c0984e5SSebastian Reichel int ret; 22458c0984e5SSebastian Reichel 22468c0984e5SSebastian Reichel /* Update maximum input current if USB enumeration is not detected */ 22478c0984e5SSebastian Reichel if (!di->usb.charger_online) { 22488c0984e5SSebastian Reichel ret = ab8500_charger_set_vbus_in_curr(di, 224983e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua); 22508c0984e5SSebastian Reichel if (ret) 22518c0984e5SSebastian Reichel return; 22528c0984e5SSebastian Reichel } 22538c0984e5SSebastian Reichel 22548c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, true); 22558c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 22568c0984e5SSebastian Reichel } 22578c0984e5SSebastian Reichel 22588c0984e5SSebastian Reichel /** 22598c0984e5SSebastian Reichel * ab8500_charger_usb_link_status_work() - work to detect USB type 22608c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 22618c0984e5SSebastian Reichel * 22628c0984e5SSebastian Reichel * Detect the type of USB plugged 22638c0984e5SSebastian Reichel */ 22648c0984e5SSebastian Reichel static void ab8500_charger_usb_link_status_work(struct work_struct *work) 22658c0984e5SSebastian Reichel { 22668c0984e5SSebastian Reichel int detected_chargers; 22678c0984e5SSebastian Reichel int ret; 22688c0984e5SSebastian Reichel u8 val; 22698c0984e5SSebastian Reichel u8 link_status; 22708c0984e5SSebastian Reichel 22718c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 22728c0984e5SSebastian Reichel struct ab8500_charger, usb_link_status_work); 22738c0984e5SSebastian Reichel 22748c0984e5SSebastian Reichel /* 22758c0984e5SSebastian Reichel * Since we can't be sure that the events are received 22768c0984e5SSebastian Reichel * synchronously, we have the check if is 22778c0984e5SSebastian Reichel * connected by reading the status register 22788c0984e5SSebastian Reichel */ 22798c0984e5SSebastian Reichel detected_chargers = ab8500_charger_detect_chargers(di, false); 22808c0984e5SSebastian Reichel if (detected_chargers < 0) 22818c0984e5SSebastian Reichel return; 22828c0984e5SSebastian Reichel 22838c0984e5SSebastian Reichel /* 22848c0984e5SSebastian Reichel * Some chargers that breaks the USB spec is 22858c0984e5SSebastian Reichel * identified as invalid by AB8500 and it refuse 22868c0984e5SSebastian Reichel * to start the charging process. but by jumping 2287ddb74e98SAshish Chavan * through a few hoops it can be forced to start. 22888c0984e5SSebastian Reichel */ 22898c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 22908c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_USB, 22918c0984e5SSebastian Reichel AB8500_USB_LINE_STAT_REG, &val); 22928c0984e5SSebastian Reichel else 22938c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_USB, 22948c0984e5SSebastian Reichel AB8500_USB_LINK1_STAT_REG, &val); 22958c0984e5SSebastian Reichel 22968c0984e5SSebastian Reichel if (ret >= 0) 22978c0984e5SSebastian Reichel dev_dbg(di->dev, "UsbLineStatus register = 0x%02x\n", val); 22988c0984e5SSebastian Reichel else 22998c0984e5SSebastian Reichel dev_dbg(di->dev, "Error reading USB link status\n"); 23008c0984e5SSebastian Reichel 23018c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 23028c0984e5SSebastian Reichel link_status = AB8500_USB_LINK_STATUS; 23038c0984e5SSebastian Reichel else 23048c0984e5SSebastian Reichel link_status = AB8505_USB_LINK_STATUS; 23058c0984e5SSebastian Reichel 23068c0984e5SSebastian Reichel if (detected_chargers & USB_PW_CONN) { 23078c0984e5SSebastian Reichel if (((val & link_status) >> USB_LINK_STATUS_SHIFT) == 23088c0984e5SSebastian Reichel USB_STAT_NOT_VALID_LINK && 23098c0984e5SSebastian Reichel di->invalid_charger_detect_state == 0) { 23108c0984e5SSebastian Reichel dev_dbg(di->dev, 23118c0984e5SSebastian Reichel "Invalid charger detected, state= 0\n"); 23128c0984e5SSebastian Reichel /*Enable charger*/ 23138c0984e5SSebastian Reichel abx500_mask_and_set_register_interruptible(di->dev, 23148c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_USBCH_CTRL1_REG, 23158c0984e5SSebastian Reichel USB_CH_ENA, USB_CH_ENA); 23168c0984e5SSebastian Reichel /*Enable charger detection*/ 23178c0984e5SSebastian Reichel abx500_mask_and_set_register_interruptible(di->dev, 23188c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINE_CTRL2_REG, 23198c0984e5SSebastian Reichel USB_CH_DET, USB_CH_DET); 23208c0984e5SSebastian Reichel di->invalid_charger_detect_state = 1; 23218c0984e5SSebastian Reichel /*exit and wait for new link status interrupt.*/ 23228c0984e5SSebastian Reichel return; 23238c0984e5SSebastian Reichel 23248c0984e5SSebastian Reichel } 23258c0984e5SSebastian Reichel if (di->invalid_charger_detect_state == 1) { 23268c0984e5SSebastian Reichel dev_dbg(di->dev, 23278c0984e5SSebastian Reichel "Invalid charger detected, state= 1\n"); 23288c0984e5SSebastian Reichel /*Stop charger detection*/ 23298c0984e5SSebastian Reichel abx500_mask_and_set_register_interruptible(di->dev, 23308c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINE_CTRL2_REG, 23318c0984e5SSebastian Reichel USB_CH_DET, 0x00); 23328c0984e5SSebastian Reichel /*Check link status*/ 23338c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 23348c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 23358c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINE_STAT_REG, 23368c0984e5SSebastian Reichel &val); 23378c0984e5SSebastian Reichel else 23388c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 23398c0984e5SSebastian Reichel AB8500_USB, AB8500_USB_LINK1_STAT_REG, 23408c0984e5SSebastian Reichel &val); 23418c0984e5SSebastian Reichel 23428c0984e5SSebastian Reichel dev_dbg(di->dev, "USB link status= 0x%02x\n", 23438c0984e5SSebastian Reichel (val & link_status) >> USB_LINK_STATUS_SHIFT); 23448c0984e5SSebastian Reichel di->invalid_charger_detect_state = 2; 23458c0984e5SSebastian Reichel } 23468c0984e5SSebastian Reichel } else { 23478c0984e5SSebastian Reichel di->invalid_charger_detect_state = 0; 23488c0984e5SSebastian Reichel } 23498c0984e5SSebastian Reichel 23508c0984e5SSebastian Reichel if (!(detected_chargers & USB_PW_CONN)) { 23518c0984e5SSebastian Reichel di->vbus_detected = false; 23528c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, false); 23538c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 23548c0984e5SSebastian Reichel return; 23558c0984e5SSebastian Reichel } 23568c0984e5SSebastian Reichel 23578c0984e5SSebastian Reichel dev_dbg(di->dev,"%s di->vbus_detected = true\n",__func__); 23588c0984e5SSebastian Reichel di->vbus_detected = true; 23598c0984e5SSebastian Reichel ret = ab8500_charger_read_usb_type(di); 23608c0984e5SSebastian Reichel if (ret) { 23618c0984e5SSebastian Reichel if (ret == -ENXIO) { 23628c0984e5SSebastian Reichel /* No valid charger type detected */ 23638c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, false); 23648c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 23658c0984e5SSebastian Reichel } 23668c0984e5SSebastian Reichel return; 23678c0984e5SSebastian Reichel } 23688c0984e5SSebastian Reichel 23698c0984e5SSebastian Reichel if (di->usb_device_is_unrecognised) { 23708c0984e5SSebastian Reichel dev_dbg(di->dev, 23718c0984e5SSebastian Reichel "Potential Legacy Charger device. " 23728c0984e5SSebastian Reichel "Delay work for %d msec for USB enum " 23738c0984e5SSebastian Reichel "to finish", 23748c0984e5SSebastian Reichel WAIT_ACA_RID_ENUMERATION); 23758c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 23768c0984e5SSebastian Reichel &di->attach_work, 23778c0984e5SSebastian Reichel msecs_to_jiffies(WAIT_ACA_RID_ENUMERATION)); 23788c0984e5SSebastian Reichel } else if (di->is_aca_rid == 1) { 23798c0984e5SSebastian Reichel /* Only wait once */ 23808c0984e5SSebastian Reichel di->is_aca_rid++; 23818c0984e5SSebastian Reichel dev_dbg(di->dev, 23828c0984e5SSebastian Reichel "%s Wait %d msec for USB enum to finish", 23838c0984e5SSebastian Reichel __func__, WAIT_ACA_RID_ENUMERATION); 23848c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 23858c0984e5SSebastian Reichel &di->attach_work, 23868c0984e5SSebastian Reichel msecs_to_jiffies(WAIT_ACA_RID_ENUMERATION)); 23878c0984e5SSebastian Reichel } else { 23888c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 23898c0984e5SSebastian Reichel &di->attach_work, 23908c0984e5SSebastian Reichel 0); 23918c0984e5SSebastian Reichel } 23928c0984e5SSebastian Reichel } 23938c0984e5SSebastian Reichel 23948c0984e5SSebastian Reichel static void ab8500_charger_usb_state_changed_work(struct work_struct *work) 23958c0984e5SSebastian Reichel { 23968c0984e5SSebastian Reichel int ret; 23978c0984e5SSebastian Reichel unsigned long flags; 23988c0984e5SSebastian Reichel 23998c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 24008c0984e5SSebastian Reichel struct ab8500_charger, usb_state_changed_work.work); 24018c0984e5SSebastian Reichel 24028c0984e5SSebastian Reichel if (!di->vbus_detected) { 24038c0984e5SSebastian Reichel dev_dbg(di->dev, 24048c0984e5SSebastian Reichel "%s !di->vbus_detected\n", 24058c0984e5SSebastian Reichel __func__); 24068c0984e5SSebastian Reichel return; 24078c0984e5SSebastian Reichel } 24088c0984e5SSebastian Reichel 24098c0984e5SSebastian Reichel spin_lock_irqsave(&di->usb_state.usb_lock, flags); 24108c0984e5SSebastian Reichel di->usb_state.state = di->usb_state.state_tmp; 241183e5aa77SLinus Walleij di->usb_state.usb_current_ua = di->usb_state.usb_current_tmp_ua; 24128c0984e5SSebastian Reichel spin_unlock_irqrestore(&di->usb_state.usb_lock, flags); 24138c0984e5SSebastian Reichel 241483e5aa77SLinus Walleij dev_dbg(di->dev, "%s USB state: 0x%02x uA: %d\n", 241583e5aa77SLinus Walleij __func__, di->usb_state.state, di->usb_state.usb_current_ua); 24168c0984e5SSebastian Reichel 24178c0984e5SSebastian Reichel switch (di->usb_state.state) { 24188c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_RESET_HS: 24198c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_RESET_FS: 24208c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_SUSPEND: 24218c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_MAX: 24228c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, false); 24238c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 24248c0984e5SSebastian Reichel break; 24258c0984e5SSebastian Reichel 24268c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_RESUME: 24278c0984e5SSebastian Reichel /* 24288c0984e5SSebastian Reichel * when suspend->resume there should be delay 24298c0984e5SSebastian Reichel * of 1sec for enabling charging 24308c0984e5SSebastian Reichel */ 24318c0984e5SSebastian Reichel msleep(1000); 2432df561f66SGustavo A. R. Silva fallthrough; 24338c0984e5SSebastian Reichel case AB8500_BM_USB_STATE_CONFIGURED: 24348c0984e5SSebastian Reichel /* 24358c0984e5SSebastian Reichel * USB is configured, enable charging with the charging 24368c0984e5SSebastian Reichel * input current obtained from USB driver 24378c0984e5SSebastian Reichel */ 24388c0984e5SSebastian Reichel if (!ab8500_charger_get_usb_cur(di)) { 24398c0984e5SSebastian Reichel /* Update maximum input current */ 24408c0984e5SSebastian Reichel ret = ab8500_charger_set_vbus_in_curr(di, 244183e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua); 24428c0984e5SSebastian Reichel if (ret) 24438c0984e5SSebastian Reichel return; 24448c0984e5SSebastian Reichel 24458c0984e5SSebastian Reichel ab8500_charger_set_usb_connected(di, true); 24468c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 24478c0984e5SSebastian Reichel } 24488c0984e5SSebastian Reichel break; 24498c0984e5SSebastian Reichel 24508c0984e5SSebastian Reichel default: 24518c0984e5SSebastian Reichel break; 2452e15c54d2SMa Feng } 24538c0984e5SSebastian Reichel } 24548c0984e5SSebastian Reichel 24558c0984e5SSebastian Reichel /** 24568c0984e5SSebastian Reichel * ab8500_charger_check_usbchargernotok_work() - check USB chg not ok status 24578c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 24588c0984e5SSebastian Reichel * 24598c0984e5SSebastian Reichel * Work queue function for checking the USB charger Not OK status 24608c0984e5SSebastian Reichel */ 24618c0984e5SSebastian Reichel static void ab8500_charger_check_usbchargernotok_work(struct work_struct *work) 24628c0984e5SSebastian Reichel { 24638c0984e5SSebastian Reichel int ret; 24648c0984e5SSebastian Reichel u8 reg_value; 24658c0984e5SSebastian Reichel bool prev_status; 24668c0984e5SSebastian Reichel 24678c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 24688c0984e5SSebastian Reichel struct ab8500_charger, check_usbchgnotok_work.work); 24698c0984e5SSebastian Reichel 24708c0984e5SSebastian Reichel /* Check if the status bit for usbchargernotok is still active */ 24718c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 24728c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG, ®_value); 24738c0984e5SSebastian Reichel if (ret < 0) { 24748c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 24758c0984e5SSebastian Reichel return; 24768c0984e5SSebastian Reichel } 24778c0984e5SSebastian Reichel prev_status = di->flags.usbchargernotok; 24788c0984e5SSebastian Reichel 24798c0984e5SSebastian Reichel if (reg_value & VBUS_CH_NOK) { 24808c0984e5SSebastian Reichel di->flags.usbchargernotok = true; 24818c0984e5SSebastian Reichel /* Check again in 1sec */ 24828c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 24838c0984e5SSebastian Reichel &di->check_usbchgnotok_work, HZ); 24848c0984e5SSebastian Reichel } else { 24858c0984e5SSebastian Reichel di->flags.usbchargernotok = false; 24868c0984e5SSebastian Reichel di->flags.vbus_collapse = false; 24878c0984e5SSebastian Reichel } 24888c0984e5SSebastian Reichel 24898c0984e5SSebastian Reichel if (prev_status != di->flags.usbchargernotok) 24908c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 24918c0984e5SSebastian Reichel } 24928c0984e5SSebastian Reichel 24938c0984e5SSebastian Reichel /** 24948c0984e5SSebastian Reichel * ab8500_charger_check_main_thermal_prot_work() - check main thermal status 24958c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 24968c0984e5SSebastian Reichel * 24978c0984e5SSebastian Reichel * Work queue function for checking the Main thermal prot status 24988c0984e5SSebastian Reichel */ 24998c0984e5SSebastian Reichel static void ab8500_charger_check_main_thermal_prot_work( 25008c0984e5SSebastian Reichel struct work_struct *work) 25018c0984e5SSebastian Reichel { 25028c0984e5SSebastian Reichel int ret; 25038c0984e5SSebastian Reichel u8 reg_value; 25048c0984e5SSebastian Reichel 25058c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 25068c0984e5SSebastian Reichel struct ab8500_charger, check_main_thermal_prot_work); 25078c0984e5SSebastian Reichel 25088c0984e5SSebastian Reichel /* Check if the status bit for main_thermal_prot is still active */ 25098c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 25108c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_STATUS2_REG, ®_value); 25118c0984e5SSebastian Reichel if (ret < 0) { 25128c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 25138c0984e5SSebastian Reichel return; 25148c0984e5SSebastian Reichel } 25158c0984e5SSebastian Reichel if (reg_value & MAIN_CH_TH_PROT) 25168c0984e5SSebastian Reichel di->flags.main_thermal_prot = true; 25178c0984e5SSebastian Reichel else 25188c0984e5SSebastian Reichel di->flags.main_thermal_prot = false; 25198c0984e5SSebastian Reichel 25208c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 25218c0984e5SSebastian Reichel } 25228c0984e5SSebastian Reichel 25238c0984e5SSebastian Reichel /** 25248c0984e5SSebastian Reichel * ab8500_charger_check_usb_thermal_prot_work() - check usb thermal status 25258c0984e5SSebastian Reichel * @work: pointer to the work_struct structure 25268c0984e5SSebastian Reichel * 25278c0984e5SSebastian Reichel * Work queue function for checking the USB thermal prot status 25288c0984e5SSebastian Reichel */ 25298c0984e5SSebastian Reichel static void ab8500_charger_check_usb_thermal_prot_work( 25308c0984e5SSebastian Reichel struct work_struct *work) 25318c0984e5SSebastian Reichel { 25328c0984e5SSebastian Reichel int ret; 25338c0984e5SSebastian Reichel u8 reg_value; 25348c0984e5SSebastian Reichel 25358c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 25368c0984e5SSebastian Reichel struct ab8500_charger, check_usb_thermal_prot_work); 25378c0984e5SSebastian Reichel 25388c0984e5SSebastian Reichel /* Check if the status bit for usb_thermal_prot is still active */ 25398c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, 25408c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG, ®_value); 25418c0984e5SSebastian Reichel if (ret < 0) { 25428c0984e5SSebastian Reichel dev_err(di->dev, "%s ab8500 read failed\n", __func__); 25438c0984e5SSebastian Reichel return; 25448c0984e5SSebastian Reichel } 25458c0984e5SSebastian Reichel if (reg_value & USB_CH_TH_PROT) 25468c0984e5SSebastian Reichel di->flags.usb_thermal_prot = true; 25478c0984e5SSebastian Reichel else 25488c0984e5SSebastian Reichel di->flags.usb_thermal_prot = false; 25498c0984e5SSebastian Reichel 25508c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 25518c0984e5SSebastian Reichel } 25528c0984e5SSebastian Reichel 25538c0984e5SSebastian Reichel /** 25548c0984e5SSebastian Reichel * ab8500_charger_mainchunplugdet_handler() - main charger unplugged 25558c0984e5SSebastian Reichel * @irq: interrupt number 25568c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 25578c0984e5SSebastian Reichel * 25588c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 25598c0984e5SSebastian Reichel */ 25608c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_mainchunplugdet_handler(int irq, void *_di) 25618c0984e5SSebastian Reichel { 25628c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 25638c0984e5SSebastian Reichel 25648c0984e5SSebastian Reichel dev_dbg(di->dev, "Main charger unplugged\n"); 25658c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->ac_work); 25668c0984e5SSebastian Reichel 25678c0984e5SSebastian Reichel cancel_delayed_work_sync(&di->ac_charger_attached_work); 25688c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 25698c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 25708c0984e5SSebastian Reichel 25718c0984e5SSebastian Reichel return IRQ_HANDLED; 25728c0984e5SSebastian Reichel } 25738c0984e5SSebastian Reichel 25748c0984e5SSebastian Reichel /** 25758c0984e5SSebastian Reichel * ab8500_charger_mainchplugdet_handler() - main charger plugged 25768c0984e5SSebastian Reichel * @irq: interrupt number 25778c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 25788c0984e5SSebastian Reichel * 25798c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 25808c0984e5SSebastian Reichel */ 25818c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_mainchplugdet_handler(int irq, void *_di) 25828c0984e5SSebastian Reichel { 25838c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 25848c0984e5SSebastian Reichel 25858c0984e5SSebastian Reichel dev_dbg(di->dev, "Main charger plugged\n"); 25868c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->ac_work); 25878c0984e5SSebastian Reichel 25888c0984e5SSebastian Reichel mutex_lock(&di->charger_attached_mutex); 25898c0984e5SSebastian Reichel mutex_unlock(&di->charger_attached_mutex); 25908c0984e5SSebastian Reichel 25918c0984e5SSebastian Reichel if (is_ab8500(di->parent)) 25928c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 25938c0984e5SSebastian Reichel &di->ac_charger_attached_work, 25948c0984e5SSebastian Reichel HZ); 25958c0984e5SSebastian Reichel return IRQ_HANDLED; 25968c0984e5SSebastian Reichel } 25978c0984e5SSebastian Reichel 25988c0984e5SSebastian Reichel /** 25998c0984e5SSebastian Reichel * ab8500_charger_mainextchnotok_handler() - main charger not ok 26008c0984e5SSebastian Reichel * @irq: interrupt number 26018c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 26028c0984e5SSebastian Reichel * 26038c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 26048c0984e5SSebastian Reichel */ 26058c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_mainextchnotok_handler(int irq, void *_di) 26068c0984e5SSebastian Reichel { 26078c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 26088c0984e5SSebastian Reichel 26098c0984e5SSebastian Reichel dev_dbg(di->dev, "Main charger not ok\n"); 26108c0984e5SSebastian Reichel di->flags.mainextchnotok = true; 26118c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 26128c0984e5SSebastian Reichel 26138c0984e5SSebastian Reichel /* Schedule a new HW failure check */ 26148c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->check_hw_failure_work, 0); 26158c0984e5SSebastian Reichel 26168c0984e5SSebastian Reichel return IRQ_HANDLED; 26178c0984e5SSebastian Reichel } 26188c0984e5SSebastian Reichel 26198c0984e5SSebastian Reichel /** 26208c0984e5SSebastian Reichel * ab8500_charger_mainchthprotr_handler() - Die temp is above main charger 26218c0984e5SSebastian Reichel * thermal protection threshold 26228c0984e5SSebastian Reichel * @irq: interrupt number 26238c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 26248c0984e5SSebastian Reichel * 26258c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 26268c0984e5SSebastian Reichel */ 26278c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_mainchthprotr_handler(int irq, void *_di) 26288c0984e5SSebastian Reichel { 26298c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 26308c0984e5SSebastian Reichel 26318c0984e5SSebastian Reichel dev_dbg(di->dev, 26328c0984e5SSebastian Reichel "Die temp above Main charger thermal protection threshold\n"); 26338c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->check_main_thermal_prot_work); 26348c0984e5SSebastian Reichel 26358c0984e5SSebastian Reichel return IRQ_HANDLED; 26368c0984e5SSebastian Reichel } 26378c0984e5SSebastian Reichel 26388c0984e5SSebastian Reichel /** 26398c0984e5SSebastian Reichel * ab8500_charger_mainchthprotf_handler() - Die temp is below main charger 26408c0984e5SSebastian Reichel * thermal protection threshold 26418c0984e5SSebastian Reichel * @irq: interrupt number 26428c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 26438c0984e5SSebastian Reichel * 26448c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 26458c0984e5SSebastian Reichel */ 26468c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_mainchthprotf_handler(int irq, void *_di) 26478c0984e5SSebastian Reichel { 26488c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 26498c0984e5SSebastian Reichel 26508c0984e5SSebastian Reichel dev_dbg(di->dev, 26518c0984e5SSebastian Reichel "Die temp ok for Main charger thermal protection threshold\n"); 26528c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->check_main_thermal_prot_work); 26538c0984e5SSebastian Reichel 26548c0984e5SSebastian Reichel return IRQ_HANDLED; 26558c0984e5SSebastian Reichel } 26568c0984e5SSebastian Reichel 26578c0984e5SSebastian Reichel static void ab8500_charger_vbus_drop_end_work(struct work_struct *work) 26588c0984e5SSebastian Reichel { 26598c0984e5SSebastian Reichel struct ab8500_charger *di = container_of(work, 26608c0984e5SSebastian Reichel struct ab8500_charger, vbus_drop_end_work.work); 266183e5aa77SLinus Walleij int ret, curr_ua; 26628c0984e5SSebastian Reichel u8 reg_value; 26638c0984e5SSebastian Reichel 26648c0984e5SSebastian Reichel di->flags.vbus_drop_end = false; 26658c0984e5SSebastian Reichel 26668c0984e5SSebastian Reichel /* Reset the drop counter */ 26678c0984e5SSebastian Reichel abx500_set_register_interruptible(di->dev, 26688c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CHARGER_CTRL, 0x01); 26698c0984e5SSebastian Reichel 26708c0984e5SSebastian Reichel ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, 26718c0984e5SSebastian Reichel AB8500_CH_USBCH_STAT2_REG, ®_value); 26728c0984e5SSebastian Reichel if (ret < 0) { 26738c0984e5SSebastian Reichel dev_err(di->dev, "%s read failed\n", __func__); 26748c0984e5SSebastian Reichel return; 26758c0984e5SSebastian Reichel } 26768c0984e5SSebastian Reichel 267783e5aa77SLinus Walleij curr_ua = ab8500_charge_input_curr_map[ 26788c0984e5SSebastian Reichel reg_value >> AUTO_VBUS_IN_CURR_LIM_SHIFT]; 26798c0984e5SSebastian Reichel 268083e5aa77SLinus Walleij if (di->max_usb_in_curr.calculated_max_ua != curr_ua) { 26818c0984e5SSebastian Reichel /* USB source is collapsing */ 268283e5aa77SLinus Walleij di->max_usb_in_curr.calculated_max_ua = curr_ua; 26838c0984e5SSebastian Reichel dev_dbg(di->dev, 268483e5aa77SLinus Walleij "VBUS input current limiting to %d uA\n", 268583e5aa77SLinus Walleij di->max_usb_in_curr.calculated_max_ua); 26868c0984e5SSebastian Reichel } else { 26878c0984e5SSebastian Reichel /* 26888c0984e5SSebastian Reichel * USB source can not give more than this amount. 26898c0984e5SSebastian Reichel * Taking more will collapse the source. 26908c0984e5SSebastian Reichel */ 269183e5aa77SLinus Walleij di->max_usb_in_curr.set_max_ua = 269283e5aa77SLinus Walleij di->max_usb_in_curr.calculated_max_ua; 26938c0984e5SSebastian Reichel dev_dbg(di->dev, 269483e5aa77SLinus Walleij "VBUS input current limited to %d uA\n", 269583e5aa77SLinus Walleij di->max_usb_in_curr.set_max_ua); 26968c0984e5SSebastian Reichel } 26978c0984e5SSebastian Reichel 26988c0984e5SSebastian Reichel if (di->usb.charger_connected) 26998c0984e5SSebastian Reichel ab8500_charger_set_vbus_in_curr(di, 270083e5aa77SLinus Walleij di->max_usb_in_curr.usb_type_max_ua); 27018c0984e5SSebastian Reichel } 27028c0984e5SSebastian Reichel 27038c0984e5SSebastian Reichel /** 27048c0984e5SSebastian Reichel * ab8500_charger_vbusdetf_handler() - VBUS falling detected 27058c0984e5SSebastian Reichel * @irq: interrupt number 27068c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 27078c0984e5SSebastian Reichel * 27088c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 27098c0984e5SSebastian Reichel */ 27108c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_vbusdetf_handler(int irq, void *_di) 27118c0984e5SSebastian Reichel { 27128c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 27138c0984e5SSebastian Reichel 27148c0984e5SSebastian Reichel di->vbus_detected = false; 27158c0984e5SSebastian Reichel dev_dbg(di->dev, "VBUS falling detected\n"); 27168c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->detect_usb_type_work); 27178c0984e5SSebastian Reichel 27188c0984e5SSebastian Reichel return IRQ_HANDLED; 27198c0984e5SSebastian Reichel } 27208c0984e5SSebastian Reichel 27218c0984e5SSebastian Reichel /** 27228c0984e5SSebastian Reichel * ab8500_charger_vbusdetr_handler() - VBUS rising detected 27238c0984e5SSebastian Reichel * @irq: interrupt number 27248c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 27258c0984e5SSebastian Reichel * 27268c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 27278c0984e5SSebastian Reichel */ 27288c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_vbusdetr_handler(int irq, void *_di) 27298c0984e5SSebastian Reichel { 27308c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 27318c0984e5SSebastian Reichel 27328c0984e5SSebastian Reichel di->vbus_detected = true; 27338c0984e5SSebastian Reichel dev_dbg(di->dev, "VBUS rising detected\n"); 27348c0984e5SSebastian Reichel 27358c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->detect_usb_type_work); 27368c0984e5SSebastian Reichel 27378c0984e5SSebastian Reichel return IRQ_HANDLED; 27388c0984e5SSebastian Reichel } 27398c0984e5SSebastian Reichel 27408c0984e5SSebastian Reichel /** 27418c0984e5SSebastian Reichel * ab8500_charger_usblinkstatus_handler() - USB link status has changed 27428c0984e5SSebastian Reichel * @irq: interrupt number 27438c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 27448c0984e5SSebastian Reichel * 27458c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 27468c0984e5SSebastian Reichel */ 27478c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_usblinkstatus_handler(int irq, void *_di) 27488c0984e5SSebastian Reichel { 27498c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 27508c0984e5SSebastian Reichel 27518c0984e5SSebastian Reichel dev_dbg(di->dev, "USB link status changed\n"); 27528c0984e5SSebastian Reichel 27538c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->usb_link_status_work); 27548c0984e5SSebastian Reichel 27558c0984e5SSebastian Reichel return IRQ_HANDLED; 27568c0984e5SSebastian Reichel } 27578c0984e5SSebastian Reichel 27588c0984e5SSebastian Reichel /** 27598c0984e5SSebastian Reichel * ab8500_charger_usbchthprotr_handler() - Die temp is above usb charger 27608c0984e5SSebastian Reichel * thermal protection threshold 27618c0984e5SSebastian Reichel * @irq: interrupt number 27628c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 27638c0984e5SSebastian Reichel * 27648c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 27658c0984e5SSebastian Reichel */ 27668c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_usbchthprotr_handler(int irq, void *_di) 27678c0984e5SSebastian Reichel { 27688c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 27698c0984e5SSebastian Reichel 27708c0984e5SSebastian Reichel dev_dbg(di->dev, 27718c0984e5SSebastian Reichel "Die temp above USB charger thermal protection threshold\n"); 27728c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->check_usb_thermal_prot_work); 27738c0984e5SSebastian Reichel 27748c0984e5SSebastian Reichel return IRQ_HANDLED; 27758c0984e5SSebastian Reichel } 27768c0984e5SSebastian Reichel 27778c0984e5SSebastian Reichel /** 27788c0984e5SSebastian Reichel * ab8500_charger_usbchthprotf_handler() - Die temp is below usb charger 27798c0984e5SSebastian Reichel * thermal protection threshold 27808c0984e5SSebastian Reichel * @irq: interrupt number 27818c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 27828c0984e5SSebastian Reichel * 27838c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 27848c0984e5SSebastian Reichel */ 27858c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_usbchthprotf_handler(int irq, void *_di) 27868c0984e5SSebastian Reichel { 27878c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 27888c0984e5SSebastian Reichel 27898c0984e5SSebastian Reichel dev_dbg(di->dev, 27908c0984e5SSebastian Reichel "Die temp ok for USB charger thermal protection threshold\n"); 27918c0984e5SSebastian Reichel queue_work(di->charger_wq, &di->check_usb_thermal_prot_work); 27928c0984e5SSebastian Reichel 27938c0984e5SSebastian Reichel return IRQ_HANDLED; 27948c0984e5SSebastian Reichel } 27958c0984e5SSebastian Reichel 27968c0984e5SSebastian Reichel /** 27978c0984e5SSebastian Reichel * ab8500_charger_usbchargernotokr_handler() - USB charger not ok detected 27988c0984e5SSebastian Reichel * @irq: interrupt number 27998c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 28008c0984e5SSebastian Reichel * 28018c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 28028c0984e5SSebastian Reichel */ 28038c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_usbchargernotokr_handler(int irq, void *_di) 28048c0984e5SSebastian Reichel { 28058c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 28068c0984e5SSebastian Reichel 28078c0984e5SSebastian Reichel dev_dbg(di->dev, "Not allowed USB charger detected\n"); 28088c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->check_usbchgnotok_work, 0); 28098c0984e5SSebastian Reichel 28108c0984e5SSebastian Reichel return IRQ_HANDLED; 28118c0984e5SSebastian Reichel } 28128c0984e5SSebastian Reichel 28138c0984e5SSebastian Reichel /** 28148c0984e5SSebastian Reichel * ab8500_charger_chwdexp_handler() - Charger watchdog expired 28158c0984e5SSebastian Reichel * @irq: interrupt number 28168c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 28178c0984e5SSebastian Reichel * 28188c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 28198c0984e5SSebastian Reichel */ 28208c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_chwdexp_handler(int irq, void *_di) 28218c0984e5SSebastian Reichel { 28228c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 28238c0984e5SSebastian Reichel 28248c0984e5SSebastian Reichel dev_dbg(di->dev, "Charger watchdog expired\n"); 28258c0984e5SSebastian Reichel 28268c0984e5SSebastian Reichel /* 28278c0984e5SSebastian Reichel * The charger that was online when the watchdog expired 28288c0984e5SSebastian Reichel * needs to be restarted for charging to start again 28298c0984e5SSebastian Reichel */ 28308c0984e5SSebastian Reichel if (di->ac.charger_online) { 28318c0984e5SSebastian Reichel di->ac.wd_expired = true; 28328c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 28338c0984e5SSebastian Reichel } 28348c0984e5SSebastian Reichel if (di->usb.charger_online) { 28358c0984e5SSebastian Reichel di->usb.wd_expired = true; 28368c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 28378c0984e5SSebastian Reichel } 28388c0984e5SSebastian Reichel 28398c0984e5SSebastian Reichel return IRQ_HANDLED; 28408c0984e5SSebastian Reichel } 28418c0984e5SSebastian Reichel 28428c0984e5SSebastian Reichel /** 28438c0984e5SSebastian Reichel * ab8500_charger_vbuschdropend_handler() - VBUS drop removed 28448c0984e5SSebastian Reichel * @irq: interrupt number 28458c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 28468c0984e5SSebastian Reichel * 28478c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 28488c0984e5SSebastian Reichel */ 28498c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_vbuschdropend_handler(int irq, void *_di) 28508c0984e5SSebastian Reichel { 28518c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 28528c0984e5SSebastian Reichel 28538c0984e5SSebastian Reichel dev_dbg(di->dev, "VBUS charger drop ended\n"); 28548c0984e5SSebastian Reichel di->flags.vbus_drop_end = true; 28558c0984e5SSebastian Reichel 28568c0984e5SSebastian Reichel /* 28578c0984e5SSebastian Reichel * VBUS might have dropped due to bad connection. 28588c0984e5SSebastian Reichel * Schedule a new input limit set to the value SW requests. 28598c0984e5SSebastian Reichel */ 28608c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->vbus_drop_end_work, 28618c0984e5SSebastian Reichel round_jiffies(VBUS_IN_CURR_LIM_RETRY_SET_TIME * HZ)); 28628c0984e5SSebastian Reichel 28638c0984e5SSebastian Reichel return IRQ_HANDLED; 28648c0984e5SSebastian Reichel } 28658c0984e5SSebastian Reichel 28668c0984e5SSebastian Reichel /** 28678c0984e5SSebastian Reichel * ab8500_charger_vbusovv_handler() - VBUS overvoltage detected 28688c0984e5SSebastian Reichel * @irq: interrupt number 28698c0984e5SSebastian Reichel * @_di: pointer to the ab8500_charger structure 28708c0984e5SSebastian Reichel * 28718c0984e5SSebastian Reichel * Returns IRQ status(IRQ_HANDLED) 28728c0984e5SSebastian Reichel */ 28738c0984e5SSebastian Reichel static irqreturn_t ab8500_charger_vbusovv_handler(int irq, void *_di) 28748c0984e5SSebastian Reichel { 28758c0984e5SSebastian Reichel struct ab8500_charger *di = _di; 28768c0984e5SSebastian Reichel 28778c0984e5SSebastian Reichel dev_dbg(di->dev, "VBUS overvoltage detected\n"); 28788c0984e5SSebastian Reichel di->flags.vbus_ovv = true; 28798c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->usb_chg.psy); 28808c0984e5SSebastian Reichel 28818c0984e5SSebastian Reichel /* Schedule a new HW failure check */ 28828c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->check_hw_failure_work, 0); 28838c0984e5SSebastian Reichel 28848c0984e5SSebastian Reichel return IRQ_HANDLED; 28858c0984e5SSebastian Reichel } 28868c0984e5SSebastian Reichel 28878c0984e5SSebastian Reichel /** 28888c0984e5SSebastian Reichel * ab8500_charger_ac_get_property() - get the ac/mains properties 28898c0984e5SSebastian Reichel * @psy: pointer to the power_supply structure 28908c0984e5SSebastian Reichel * @psp: pointer to the power_supply_property structure 28918c0984e5SSebastian Reichel * @val: pointer to the power_supply_propval union 28928c0984e5SSebastian Reichel * 28938c0984e5SSebastian Reichel * This function gets called when an application tries to get the ac/mains 28948c0984e5SSebastian Reichel * properties by reading the sysfs files. 28958c0984e5SSebastian Reichel * AC/Mains properties are online, present and voltage. 28968c0984e5SSebastian Reichel * online: ac/mains charging is in progress or not 28978c0984e5SSebastian Reichel * present: presence of the ac/mains 28988c0984e5SSebastian Reichel * voltage: AC/Mains voltage 28998c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 29008c0984e5SSebastian Reichel */ 29018c0984e5SSebastian Reichel static int ab8500_charger_ac_get_property(struct power_supply *psy, 29028c0984e5SSebastian Reichel enum power_supply_property psp, 29038c0984e5SSebastian Reichel union power_supply_propval *val) 29048c0984e5SSebastian Reichel { 29058c0984e5SSebastian Reichel struct ab8500_charger *di; 29068c0984e5SSebastian Reichel int ret; 29078c0984e5SSebastian Reichel 29088c0984e5SSebastian Reichel di = to_ab8500_charger_ac_device_info(psy_to_ux500_charger(psy)); 29098c0984e5SSebastian Reichel 29108c0984e5SSebastian Reichel switch (psp) { 29118c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_HEALTH: 29128c0984e5SSebastian Reichel if (di->flags.mainextchnotok) 29138c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 29148c0984e5SSebastian Reichel else if (di->ac.wd_expired || di->usb.wd_expired) 29158c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_DEAD; 29168c0984e5SSebastian Reichel else if (di->flags.main_thermal_prot) 29178c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 29188c0984e5SSebastian Reichel else 29198c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_GOOD; 29208c0984e5SSebastian Reichel break; 29218c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_ONLINE: 29228c0984e5SSebastian Reichel val->intval = di->ac.charger_online; 29238c0984e5SSebastian Reichel break; 29248c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_PRESENT: 29258c0984e5SSebastian Reichel val->intval = di->ac.charger_connected; 29268c0984e5SSebastian Reichel break; 29278c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_NOW: 29288c0984e5SSebastian Reichel ret = ab8500_charger_get_ac_voltage(di); 29298c0984e5SSebastian Reichel if (ret >= 0) 2930bc6e0287SLinus Walleij di->ac.charger_voltage_uv = ret; 29318c0984e5SSebastian Reichel /* On error, use previous value */ 2932bc6e0287SLinus Walleij val->intval = di->ac.charger_voltage_uv; 29338c0984e5SSebastian Reichel break; 29348c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_AVG: 29358c0984e5SSebastian Reichel /* 29368c0984e5SSebastian Reichel * This property is used to indicate when CV mode is entered 29378c0984e5SSebastian Reichel * for the AC charger 29388c0984e5SSebastian Reichel */ 29398c0984e5SSebastian Reichel di->ac.cv_active = ab8500_charger_ac_cv(di); 29408c0984e5SSebastian Reichel val->intval = di->ac.cv_active; 29418c0984e5SSebastian Reichel break; 29428c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CURRENT_NOW: 29438c0984e5SSebastian Reichel ret = ab8500_charger_get_ac_current(di); 29448c0984e5SSebastian Reichel if (ret >= 0) 294583e5aa77SLinus Walleij di->ac.charger_current_ua = ret; 294683e5aa77SLinus Walleij val->intval = di->ac.charger_current_ua; 29478c0984e5SSebastian Reichel break; 29488c0984e5SSebastian Reichel default: 29498c0984e5SSebastian Reichel return -EINVAL; 29508c0984e5SSebastian Reichel } 29518c0984e5SSebastian Reichel return 0; 29528c0984e5SSebastian Reichel } 29538c0984e5SSebastian Reichel 29548c0984e5SSebastian Reichel /** 29558c0984e5SSebastian Reichel * ab8500_charger_usb_get_property() - get the usb properties 29568c0984e5SSebastian Reichel * @psy: pointer to the power_supply structure 29578c0984e5SSebastian Reichel * @psp: pointer to the power_supply_property structure 29588c0984e5SSebastian Reichel * @val: pointer to the power_supply_propval union 29598c0984e5SSebastian Reichel * 29608c0984e5SSebastian Reichel * This function gets called when an application tries to get the usb 29618c0984e5SSebastian Reichel * properties by reading the sysfs files. 29628c0984e5SSebastian Reichel * USB properties are online, present and voltage. 29638c0984e5SSebastian Reichel * online: usb charging is in progress or not 29648c0984e5SSebastian Reichel * present: presence of the usb 29658c0984e5SSebastian Reichel * voltage: vbus voltage 29668c0984e5SSebastian Reichel * Returns error code in case of failure else 0(on success) 29678c0984e5SSebastian Reichel */ 29688c0984e5SSebastian Reichel static int ab8500_charger_usb_get_property(struct power_supply *psy, 29698c0984e5SSebastian Reichel enum power_supply_property psp, 29708c0984e5SSebastian Reichel union power_supply_propval *val) 29718c0984e5SSebastian Reichel { 29728c0984e5SSebastian Reichel struct ab8500_charger *di; 29738c0984e5SSebastian Reichel int ret; 29748c0984e5SSebastian Reichel 29758c0984e5SSebastian Reichel di = to_ab8500_charger_usb_device_info(psy_to_ux500_charger(psy)); 29768c0984e5SSebastian Reichel 29778c0984e5SSebastian Reichel switch (psp) { 29788c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_HEALTH: 29798c0984e5SSebastian Reichel if (di->flags.usbchargernotok) 29808c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 29818c0984e5SSebastian Reichel else if (di->ac.wd_expired || di->usb.wd_expired) 29828c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_DEAD; 29838c0984e5SSebastian Reichel else if (di->flags.usb_thermal_prot) 29848c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 29858c0984e5SSebastian Reichel else if (di->flags.vbus_ovv) 29868c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 29878c0984e5SSebastian Reichel else 29888c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_HEALTH_GOOD; 29898c0984e5SSebastian Reichel break; 29908c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_ONLINE: 29918c0984e5SSebastian Reichel val->intval = di->usb.charger_online; 29928c0984e5SSebastian Reichel break; 29938c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_PRESENT: 29948c0984e5SSebastian Reichel val->intval = di->usb.charger_connected; 29958c0984e5SSebastian Reichel break; 29968c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_NOW: 29978c0984e5SSebastian Reichel ret = ab8500_charger_get_vbus_voltage(di); 29988c0984e5SSebastian Reichel if (ret >= 0) 2999bc6e0287SLinus Walleij di->usb.charger_voltage_uv = ret; 3000bc6e0287SLinus Walleij val->intval = di->usb.charger_voltage_uv; 30018c0984e5SSebastian Reichel break; 30028c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_AVG: 30038c0984e5SSebastian Reichel /* 30048c0984e5SSebastian Reichel * This property is used to indicate when CV mode is entered 30058c0984e5SSebastian Reichel * for the USB charger 30068c0984e5SSebastian Reichel */ 30078c0984e5SSebastian Reichel di->usb.cv_active = ab8500_charger_usb_cv(di); 30088c0984e5SSebastian Reichel val->intval = di->usb.cv_active; 30098c0984e5SSebastian Reichel break; 30108c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CURRENT_NOW: 30118c0984e5SSebastian Reichel ret = ab8500_charger_get_usb_current(di); 30128c0984e5SSebastian Reichel if (ret >= 0) 301383e5aa77SLinus Walleij di->usb.charger_current_ua = ret; 301483e5aa77SLinus Walleij val->intval = di->usb.charger_current_ua; 30158c0984e5SSebastian Reichel break; 30168c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CURRENT_AVG: 30178c0984e5SSebastian Reichel /* 30188c0984e5SSebastian Reichel * This property is used to indicate when VBUS has collapsed 30198c0984e5SSebastian Reichel * due to too high output current from the USB charger 30208c0984e5SSebastian Reichel */ 30218c0984e5SSebastian Reichel if (di->flags.vbus_collapse) 30228c0984e5SSebastian Reichel val->intval = 1; 30238c0984e5SSebastian Reichel else 30248c0984e5SSebastian Reichel val->intval = 0; 30258c0984e5SSebastian Reichel break; 30268c0984e5SSebastian Reichel default: 30278c0984e5SSebastian Reichel return -EINVAL; 30288c0984e5SSebastian Reichel } 30298c0984e5SSebastian Reichel return 0; 30308c0984e5SSebastian Reichel } 30318c0984e5SSebastian Reichel 30328c0984e5SSebastian Reichel /** 30338c0984e5SSebastian Reichel * ab8500_charger_init_hw_registers() - Set up charger related registers 30348c0984e5SSebastian Reichel * @di: pointer to the ab8500_charger structure 30358c0984e5SSebastian Reichel * 30368c0984e5SSebastian Reichel * Set up charger OVV, watchdog and maximum voltage registers as well as 30378c0984e5SSebastian Reichel * charging of the backup battery 30388c0984e5SSebastian Reichel */ 30398c0984e5SSebastian Reichel static int ab8500_charger_init_hw_registers(struct ab8500_charger *di) 30408c0984e5SSebastian Reichel { 30418c0984e5SSebastian Reichel int ret = 0; 30428c0984e5SSebastian Reichel 30438c0984e5SSebastian Reichel /* Setup maximum charger current and voltage for ABB cut2.0 */ 30448c0984e5SSebastian Reichel if (!is_ab8500_1p1_or_earlier(di->parent)) { 30458c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 30468c0984e5SSebastian Reichel AB8500_CHARGER, 30478c0984e5SSebastian Reichel AB8500_CH_VOLT_LVL_MAX_REG, CH_VOL_LVL_4P6); 30488c0984e5SSebastian Reichel if (ret) { 30498c0984e5SSebastian Reichel dev_err(di->dev, 30508c0984e5SSebastian Reichel "failed to set CH_VOLT_LVL_MAX_REG\n"); 30518c0984e5SSebastian Reichel goto out; 30528c0984e5SSebastian Reichel } 30538c0984e5SSebastian Reichel 30548c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 30558c0984e5SSebastian Reichel AB8500_CHARGER, AB8500_CH_OPT_CRNTLVL_MAX_REG, 30568c0984e5SSebastian Reichel CH_OP_CUR_LVL_1P6); 30578c0984e5SSebastian Reichel if (ret) { 30588c0984e5SSebastian Reichel dev_err(di->dev, 30598c0984e5SSebastian Reichel "failed to set CH_OPT_CRNTLVL_MAX_REG\n"); 30608c0984e5SSebastian Reichel goto out; 30618c0984e5SSebastian Reichel } 30628c0984e5SSebastian Reichel } 30638c0984e5SSebastian Reichel 30644c4268dcSLinus Walleij if (is_ab8505_2p0(di->parent)) 30658c0984e5SSebastian Reichel ret = abx500_mask_and_set_register_interruptible(di->dev, 30668c0984e5SSebastian Reichel AB8500_CHARGER, 30678c0984e5SSebastian Reichel AB8500_USBCH_CTRL2_REG, 30688c0984e5SSebastian Reichel VBUS_AUTO_IN_CURR_LIM_ENA, 30698c0984e5SSebastian Reichel VBUS_AUTO_IN_CURR_LIM_ENA); 30708c0984e5SSebastian Reichel else 30718c0984e5SSebastian Reichel /* 30728c0984e5SSebastian Reichel * VBUS OVV set to 6.3V and enable automatic current limitation 30738c0984e5SSebastian Reichel */ 30748c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 30758c0984e5SSebastian Reichel AB8500_CHARGER, 30768c0984e5SSebastian Reichel AB8500_USBCH_CTRL2_REG, 30778c0984e5SSebastian Reichel VBUS_OVV_SELECT_6P3V | VBUS_AUTO_IN_CURR_LIM_ENA); 30788c0984e5SSebastian Reichel if (ret) { 30798c0984e5SSebastian Reichel dev_err(di->dev, 30808c0984e5SSebastian Reichel "failed to set automatic current limitation\n"); 30818c0984e5SSebastian Reichel goto out; 30828c0984e5SSebastian Reichel } 30838c0984e5SSebastian Reichel 30848c0984e5SSebastian Reichel /* Enable main watchdog in OTP */ 30858c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 30868c0984e5SSebastian Reichel AB8500_OTP_EMUL, AB8500_OTP_CONF_15, OTP_ENABLE_WD); 30878c0984e5SSebastian Reichel if (ret) { 30888c0984e5SSebastian Reichel dev_err(di->dev, "failed to enable main WD in OTP\n"); 30898c0984e5SSebastian Reichel goto out; 30908c0984e5SSebastian Reichel } 30918c0984e5SSebastian Reichel 30928c0984e5SSebastian Reichel /* Enable main watchdog */ 30938c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 30948c0984e5SSebastian Reichel AB8500_SYS_CTRL2_BLOCK, 30958c0984e5SSebastian Reichel AB8500_MAIN_WDOG_CTRL_REG, MAIN_WDOG_ENA); 30968c0984e5SSebastian Reichel if (ret) { 3097b5e11cc1SColin Ian King dev_err(di->dev, "failed to enable main watchdog\n"); 30988c0984e5SSebastian Reichel goto out; 30998c0984e5SSebastian Reichel } 31008c0984e5SSebastian Reichel 31018c0984e5SSebastian Reichel /* 31028c0984e5SSebastian Reichel * Due to internal synchronisation, Enable and Kick watchdog bits 31038c0984e5SSebastian Reichel * cannot be enabled in a single write. 31048c0984e5SSebastian Reichel * A minimum delay of 2*32 kHz period (62.5µs) must be inserted 31058c0984e5SSebastian Reichel * between writing Enable then Kick bits. 31068c0984e5SSebastian Reichel */ 31078c0984e5SSebastian Reichel udelay(63); 31088c0984e5SSebastian Reichel 31098c0984e5SSebastian Reichel /* Kick main watchdog */ 31108c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 31118c0984e5SSebastian Reichel AB8500_SYS_CTRL2_BLOCK, 31128c0984e5SSebastian Reichel AB8500_MAIN_WDOG_CTRL_REG, 31138c0984e5SSebastian Reichel (MAIN_WDOG_ENA | MAIN_WDOG_KICK)); 31148c0984e5SSebastian Reichel if (ret) { 31158c0984e5SSebastian Reichel dev_err(di->dev, "failed to kick main watchdog\n"); 31168c0984e5SSebastian Reichel goto out; 31178c0984e5SSebastian Reichel } 31188c0984e5SSebastian Reichel 31198c0984e5SSebastian Reichel /* Disable main watchdog */ 31208c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 31218c0984e5SSebastian Reichel AB8500_SYS_CTRL2_BLOCK, 31228c0984e5SSebastian Reichel AB8500_MAIN_WDOG_CTRL_REG, MAIN_WDOG_DIS); 31238c0984e5SSebastian Reichel if (ret) { 31248c0984e5SSebastian Reichel dev_err(di->dev, "failed to disable main watchdog\n"); 31258c0984e5SSebastian Reichel goto out; 31268c0984e5SSebastian Reichel } 31278c0984e5SSebastian Reichel 31288c0984e5SSebastian Reichel /* Set watchdog timeout */ 31298c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 31308c0984e5SSebastian Reichel AB8500_CH_WD_TIMER_REG, WD_TIMER); 31318c0984e5SSebastian Reichel if (ret) { 31328c0984e5SSebastian Reichel dev_err(di->dev, "failed to set charger watchdog timeout\n"); 31338c0984e5SSebastian Reichel goto out; 31348c0984e5SSebastian Reichel } 31358c0984e5SSebastian Reichel 31368c0984e5SSebastian Reichel ret = ab8500_charger_led_en(di, false); 31378c0984e5SSebastian Reichel if (ret < 0) { 31388c0984e5SSebastian Reichel dev_err(di->dev, "failed to disable LED\n"); 31398c0984e5SSebastian Reichel goto out; 31408c0984e5SSebastian Reichel } 31418c0984e5SSebastian Reichel 31428c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, 31438c0984e5SSebastian Reichel AB8500_RTC, 31448c0984e5SSebastian Reichel AB8500_RTC_BACKUP_CHG_REG, 31458c0984e5SSebastian Reichel (di->bm->bkup_bat_v & 0x3) | di->bm->bkup_bat_i); 31468c0984e5SSebastian Reichel if (ret) { 31478c0984e5SSebastian Reichel dev_err(di->dev, "failed to setup backup battery charging\n"); 31488c0984e5SSebastian Reichel goto out; 31498c0984e5SSebastian Reichel } 31508c0984e5SSebastian Reichel 31518c0984e5SSebastian Reichel /* Enable backup battery charging */ 3152bf59fdddSChristophe JAILLET ret = abx500_mask_and_set_register_interruptible(di->dev, 31538c0984e5SSebastian Reichel AB8500_RTC, AB8500_RTC_CTRL_REG, 31548c0984e5SSebastian Reichel RTC_BUP_CH_ENA, RTC_BUP_CH_ENA); 315509edcb64SChristophe JAILLET if (ret < 0) { 31568c0984e5SSebastian Reichel dev_err(di->dev, "%s mask and set failed\n", __func__); 315709edcb64SChristophe JAILLET goto out; 315809edcb64SChristophe JAILLET } 31598c0984e5SSebastian Reichel 31608c0984e5SSebastian Reichel out: 31618c0984e5SSebastian Reichel return ret; 31628c0984e5SSebastian Reichel } 31638c0984e5SSebastian Reichel 31648c0984e5SSebastian Reichel /* 31658c0984e5SSebastian Reichel * ab8500 charger driver interrupts and their respective isr 31668c0984e5SSebastian Reichel */ 31678c0984e5SSebastian Reichel static struct ab8500_charger_interrupts ab8500_charger_irq[] = { 31688c0984e5SSebastian Reichel {"MAIN_CH_UNPLUG_DET", ab8500_charger_mainchunplugdet_handler}, 31698c0984e5SSebastian Reichel {"MAIN_CHARGE_PLUG_DET", ab8500_charger_mainchplugdet_handler}, 31708c0984e5SSebastian Reichel {"MAIN_EXT_CH_NOT_OK", ab8500_charger_mainextchnotok_handler}, 31718c0984e5SSebastian Reichel {"MAIN_CH_TH_PROT_R", ab8500_charger_mainchthprotr_handler}, 31728c0984e5SSebastian Reichel {"MAIN_CH_TH_PROT_F", ab8500_charger_mainchthprotf_handler}, 31738c0984e5SSebastian Reichel {"VBUS_DET_F", ab8500_charger_vbusdetf_handler}, 31748c0984e5SSebastian Reichel {"VBUS_DET_R", ab8500_charger_vbusdetr_handler}, 31758c0984e5SSebastian Reichel {"USB_LINK_STATUS", ab8500_charger_usblinkstatus_handler}, 31768c0984e5SSebastian Reichel {"USB_CH_TH_PROT_R", ab8500_charger_usbchthprotr_handler}, 31778c0984e5SSebastian Reichel {"USB_CH_TH_PROT_F", ab8500_charger_usbchthprotf_handler}, 31788c0984e5SSebastian Reichel {"USB_CHARGER_NOT_OKR", ab8500_charger_usbchargernotokr_handler}, 31798c0984e5SSebastian Reichel {"VBUS_OVV", ab8500_charger_vbusovv_handler}, 31808c0984e5SSebastian Reichel {"CH_WD_EXP", ab8500_charger_chwdexp_handler}, 31818c0984e5SSebastian Reichel {"VBUS_CH_DROP_END", ab8500_charger_vbuschdropend_handler}, 31828c0984e5SSebastian Reichel }; 31838c0984e5SSebastian Reichel 31848c0984e5SSebastian Reichel static int ab8500_charger_usb_notifier_call(struct notifier_block *nb, 31858c0984e5SSebastian Reichel unsigned long event, void *power) 31868c0984e5SSebastian Reichel { 31878c0984e5SSebastian Reichel struct ab8500_charger *di = 31888c0984e5SSebastian Reichel container_of(nb, struct ab8500_charger, nb); 31898c0984e5SSebastian Reichel enum ab8500_usb_state bm_usb_state; 319083e5aa77SLinus Walleij /* 319183e5aa77SLinus Walleij * FIXME: it appears the AB8500 PHY never sends what it should here. 319283e5aa77SLinus Walleij * Fix the PHY driver to properly notify the desired current. 319383e5aa77SLinus Walleij * Also broadcast microampere and not milliampere. 319483e5aa77SLinus Walleij */ 31958c0984e5SSebastian Reichel unsigned mA = *((unsigned *)power); 31968c0984e5SSebastian Reichel 31978c0984e5SSebastian Reichel if (event != USB_EVENT_VBUS) { 31988c0984e5SSebastian Reichel dev_dbg(di->dev, "not a standard host, returning\n"); 31998c0984e5SSebastian Reichel return NOTIFY_DONE; 32008c0984e5SSebastian Reichel } 32018c0984e5SSebastian Reichel 32028c0984e5SSebastian Reichel /* TODO: State is fabricate here. See if charger really needs USB 32038c0984e5SSebastian Reichel * state or if mA is enough 32048c0984e5SSebastian Reichel */ 320583e5aa77SLinus Walleij if ((di->usb_state.usb_current_ua == 2000) && (mA > 2)) 32068c0984e5SSebastian Reichel bm_usb_state = AB8500_BM_USB_STATE_RESUME; 32078c0984e5SSebastian Reichel else if (mA == 0) 32088c0984e5SSebastian Reichel bm_usb_state = AB8500_BM_USB_STATE_RESET_HS; 32098c0984e5SSebastian Reichel else if (mA == 2) 32108c0984e5SSebastian Reichel bm_usb_state = AB8500_BM_USB_STATE_SUSPEND; 32118c0984e5SSebastian Reichel else if (mA >= 8) /* 8, 100, 500 */ 32128c0984e5SSebastian Reichel bm_usb_state = AB8500_BM_USB_STATE_CONFIGURED; 32138c0984e5SSebastian Reichel else /* Should never occur */ 32148c0984e5SSebastian Reichel bm_usb_state = AB8500_BM_USB_STATE_RESET_FS; 32158c0984e5SSebastian Reichel 32168c0984e5SSebastian Reichel dev_dbg(di->dev, "%s usb_state: 0x%02x mA: %d\n", 32178c0984e5SSebastian Reichel __func__, bm_usb_state, mA); 32188c0984e5SSebastian Reichel 32198c0984e5SSebastian Reichel spin_lock(&di->usb_state.usb_lock); 32208c0984e5SSebastian Reichel di->usb_state.state_tmp = bm_usb_state; 322183e5aa77SLinus Walleij /* FIXME: broadcast ua instead, see above */ 322283e5aa77SLinus Walleij di->usb_state.usb_current_tmp_ua = mA * 1000; 32238c0984e5SSebastian Reichel spin_unlock(&di->usb_state.usb_lock); 32248c0984e5SSebastian Reichel 32258c0984e5SSebastian Reichel /* 32268c0984e5SSebastian Reichel * wait for some time until you get updates from the usb stack 32278c0984e5SSebastian Reichel * and negotiations are completed 32288c0984e5SSebastian Reichel */ 32298c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->usb_state_changed_work, HZ/2); 32308c0984e5SSebastian Reichel 32318c0984e5SSebastian Reichel return NOTIFY_OK; 32328c0984e5SSebastian Reichel } 32338c0984e5SSebastian Reichel 3234f8efa0a8SLinus Walleij static int __maybe_unused ab8500_charger_resume(struct device *dev) 32358c0984e5SSebastian Reichel { 32368c0984e5SSebastian Reichel int ret; 3237f8efa0a8SLinus Walleij struct ab8500_charger *di = dev_get_drvdata(dev); 32388c0984e5SSebastian Reichel 32398c0984e5SSebastian Reichel /* 32408c0984e5SSebastian Reichel * For ABB revision 1.0 and 1.1 there is a bug in the watchdog 3241ddb74e98SAshish Chavan * logic. That means we have to continuously kick the charger 32428c0984e5SSebastian Reichel * watchdog even when no charger is connected. This is only 32438c0984e5SSebastian Reichel * valid once the AC charger has been enabled. This is 32448c0984e5SSebastian Reichel * a bug that is not handled by the algorithm and the 32458c0984e5SSebastian Reichel * watchdog have to be kicked by the charger driver 32468c0984e5SSebastian Reichel * when the AC charger is disabled 32478c0984e5SSebastian Reichel */ 32488c0984e5SSebastian Reichel if (di->ac_conn && is_ab8500_1p1_or_earlier(di->parent)) { 32498c0984e5SSebastian Reichel ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, 32508c0984e5SSebastian Reichel AB8500_CHARG_WD_CTRL, CHARG_WD_KICK); 32518c0984e5SSebastian Reichel if (ret) 32528c0984e5SSebastian Reichel dev_err(di->dev, "Failed to kick WD!\n"); 32538c0984e5SSebastian Reichel 32548c0984e5SSebastian Reichel /* If not already pending start a new timer */ 32558c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->kick_wd_work, 32568c0984e5SSebastian Reichel round_jiffies(WD_KICK_INTERVAL)); 32578c0984e5SSebastian Reichel } 32588c0984e5SSebastian Reichel 32598c0984e5SSebastian Reichel /* If we still have a HW failure, schedule a new check */ 32608c0984e5SSebastian Reichel if (di->flags.mainextchnotok || di->flags.vbus_ovv) { 32618c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, 32628c0984e5SSebastian Reichel &di->check_hw_failure_work, 0); 32638c0984e5SSebastian Reichel } 32648c0984e5SSebastian Reichel 32658c0984e5SSebastian Reichel if (di->flags.vbus_drop_end) 32668c0984e5SSebastian Reichel queue_delayed_work(di->charger_wq, &di->vbus_drop_end_work, 0); 32678c0984e5SSebastian Reichel 32688c0984e5SSebastian Reichel return 0; 32698c0984e5SSebastian Reichel } 32708c0984e5SSebastian Reichel 3271f8efa0a8SLinus Walleij static int __maybe_unused ab8500_charger_suspend(struct device *dev) 32728c0984e5SSebastian Reichel { 3273f8efa0a8SLinus Walleij struct ab8500_charger *di = dev_get_drvdata(dev); 32748c0984e5SSebastian Reichel 32758c0984e5SSebastian Reichel /* Cancel any pending jobs */ 32768c0984e5SSebastian Reichel cancel_delayed_work(&di->check_hw_failure_work); 32778c0984e5SSebastian Reichel cancel_delayed_work(&di->vbus_drop_end_work); 32788c0984e5SSebastian Reichel 32798c0984e5SSebastian Reichel flush_delayed_work(&di->attach_work); 32808c0984e5SSebastian Reichel flush_delayed_work(&di->usb_charger_attached_work); 32818c0984e5SSebastian Reichel flush_delayed_work(&di->ac_charger_attached_work); 32828c0984e5SSebastian Reichel flush_delayed_work(&di->check_usbchgnotok_work); 32838c0984e5SSebastian Reichel flush_delayed_work(&di->check_vbat_work); 32848c0984e5SSebastian Reichel flush_delayed_work(&di->kick_wd_work); 32858c0984e5SSebastian Reichel 32868c0984e5SSebastian Reichel flush_work(&di->usb_link_status_work); 32878c0984e5SSebastian Reichel flush_work(&di->ac_work); 32888c0984e5SSebastian Reichel flush_work(&di->detect_usb_type_work); 32898c0984e5SSebastian Reichel 32908c0984e5SSebastian Reichel if (atomic_read(&di->current_stepping_sessions)) 32918c0984e5SSebastian Reichel return -EAGAIN; 32928c0984e5SSebastian Reichel 32938c0984e5SSebastian Reichel return 0; 32948c0984e5SSebastian Reichel } 32958c0984e5SSebastian Reichel 32968c0984e5SSebastian Reichel static char *supply_interface[] = { 32978c0984e5SSebastian Reichel "ab8500_chargalg", 32988c0984e5SSebastian Reichel "ab8500_fg", 32998c0984e5SSebastian Reichel "ab8500_btemp", 33008c0984e5SSebastian Reichel }; 33018c0984e5SSebastian Reichel 33028c0984e5SSebastian Reichel static const struct power_supply_desc ab8500_ac_chg_desc = { 33038c0984e5SSebastian Reichel .name = "ab8500_ac", 33048c0984e5SSebastian Reichel .type = POWER_SUPPLY_TYPE_MAINS, 33058c0984e5SSebastian Reichel .properties = ab8500_charger_ac_props, 33068c0984e5SSebastian Reichel .num_properties = ARRAY_SIZE(ab8500_charger_ac_props), 33078c0984e5SSebastian Reichel .get_property = ab8500_charger_ac_get_property, 33088c0984e5SSebastian Reichel }; 33098c0984e5SSebastian Reichel 33108c0984e5SSebastian Reichel static const struct power_supply_desc ab8500_usb_chg_desc = { 33118c0984e5SSebastian Reichel .name = "ab8500_usb", 33128c0984e5SSebastian Reichel .type = POWER_SUPPLY_TYPE_USB, 33138c0984e5SSebastian Reichel .properties = ab8500_charger_usb_props, 33148c0984e5SSebastian Reichel .num_properties = ARRAY_SIZE(ab8500_charger_usb_props), 33158c0984e5SSebastian Reichel .get_property = ab8500_charger_usb_get_property, 33168c0984e5SSebastian Reichel }; 33178c0984e5SSebastian Reichel 33181c1f13a0SLinus Walleij static int ab8500_charger_bind(struct device *dev) 33191c1f13a0SLinus Walleij { 33201c1f13a0SLinus Walleij struct ab8500_charger *di = dev_get_drvdata(dev); 33211c1f13a0SLinus Walleij int ch_stat; 33221c1f13a0SLinus Walleij int ret; 33231c1f13a0SLinus Walleij 33241c1f13a0SLinus Walleij /* Create a work queue for the charger */ 33251c1f13a0SLinus Walleij di->charger_wq = alloc_ordered_workqueue("ab8500_charger_wq", 33261c1f13a0SLinus Walleij WQ_MEM_RECLAIM); 33271c1f13a0SLinus Walleij if (di->charger_wq == NULL) { 33281c1f13a0SLinus Walleij dev_err(dev, "failed to create work queue\n"); 33291c1f13a0SLinus Walleij return -ENOMEM; 33301c1f13a0SLinus Walleij } 33311c1f13a0SLinus Walleij 33321c1f13a0SLinus Walleij ch_stat = ab8500_charger_detect_chargers(di, false); 33331c1f13a0SLinus Walleij 33341c1f13a0SLinus Walleij if (ch_stat & AC_PW_CONN) { 33351c1f13a0SLinus Walleij if (is_ab8500(di->parent)) 33361c1f13a0SLinus Walleij queue_delayed_work(di->charger_wq, 33371c1f13a0SLinus Walleij &di->ac_charger_attached_work, 33381c1f13a0SLinus Walleij HZ); 33391c1f13a0SLinus Walleij } 33401c1f13a0SLinus Walleij if (ch_stat & USB_PW_CONN) { 33411c1f13a0SLinus Walleij if (is_ab8500(di->parent)) 33421c1f13a0SLinus Walleij queue_delayed_work(di->charger_wq, 33431c1f13a0SLinus Walleij &di->usb_charger_attached_work, 33441c1f13a0SLinus Walleij HZ); 33451c1f13a0SLinus Walleij di->vbus_detected = true; 33461c1f13a0SLinus Walleij di->vbus_detected_start = true; 33471c1f13a0SLinus Walleij queue_work(di->charger_wq, 33481c1f13a0SLinus Walleij &di->detect_usb_type_work); 33491c1f13a0SLinus Walleij } 33501c1f13a0SLinus Walleij 33511c1f13a0SLinus Walleij ret = component_bind_all(dev, di); 33521c1f13a0SLinus Walleij if (ret) { 33531c1f13a0SLinus Walleij dev_err(dev, "can't bind component devices\n"); 335438d45444SZheng Bin destroy_workqueue(di->charger_wq); 33551c1f13a0SLinus Walleij return ret; 33561c1f13a0SLinus Walleij } 33571c1f13a0SLinus Walleij 33581c1f13a0SLinus Walleij return 0; 33591c1f13a0SLinus Walleij } 33601c1f13a0SLinus Walleij 33611c1f13a0SLinus Walleij static void ab8500_charger_unbind(struct device *dev) 33621c1f13a0SLinus Walleij { 33631c1f13a0SLinus Walleij struct ab8500_charger *di = dev_get_drvdata(dev); 33641c1f13a0SLinus Walleij int ret; 33651c1f13a0SLinus Walleij 33661c1f13a0SLinus Walleij /* Disable AC charging */ 33671c1f13a0SLinus Walleij ab8500_charger_ac_en(&di->ac_chg, false, 0, 0); 33681c1f13a0SLinus Walleij 33691c1f13a0SLinus Walleij /* Disable USB charging */ 33701c1f13a0SLinus Walleij ab8500_charger_usb_en(&di->usb_chg, false, 0, 0); 33711c1f13a0SLinus Walleij 33721c1f13a0SLinus Walleij /* Backup battery voltage and current disable */ 33731c1f13a0SLinus Walleij ret = abx500_mask_and_set_register_interruptible(di->dev, 33741c1f13a0SLinus Walleij AB8500_RTC, AB8500_RTC_CTRL_REG, RTC_BUP_CH_ENA, 0); 33751c1f13a0SLinus Walleij if (ret < 0) 33761c1f13a0SLinus Walleij dev_err(di->dev, "%s mask and set failed\n", __func__); 33771c1f13a0SLinus Walleij 33781c1f13a0SLinus Walleij /* Delete the work queue */ 33791c1f13a0SLinus Walleij destroy_workqueue(di->charger_wq); 33801c1f13a0SLinus Walleij 33811c1f13a0SLinus Walleij /* Unbind fg, btemp, algorithm */ 33821c1f13a0SLinus Walleij component_unbind_all(dev, di); 33831c1f13a0SLinus Walleij } 33841c1f13a0SLinus Walleij 33851c1f13a0SLinus Walleij static const struct component_master_ops ab8500_charger_comp_ops = { 33861c1f13a0SLinus Walleij .bind = ab8500_charger_bind, 33871c1f13a0SLinus Walleij .unbind = ab8500_charger_unbind, 33881c1f13a0SLinus Walleij }; 33891c1f13a0SLinus Walleij 33901c1f13a0SLinus Walleij static struct platform_driver *const ab8500_charger_component_drivers[] = { 33911c1f13a0SLinus Walleij &ab8500_fg_driver, 33921c1f13a0SLinus Walleij &ab8500_btemp_driver, 3393c5b64a99SLinus Walleij &ab8500_chargalg_driver, 33941c1f13a0SLinus Walleij }; 33951c1f13a0SLinus Walleij 33968c0984e5SSebastian Reichel static int ab8500_charger_probe(struct platform_device *pdev) 33978c0984e5SSebastian Reichel { 33981c1f13a0SLinus Walleij struct device *dev = &pdev->dev; 33991c1f13a0SLinus Walleij struct device_node *np = dev->of_node; 34001c1f13a0SLinus Walleij struct component_match *match = NULL; 34018c0984e5SSebastian Reichel struct power_supply_config ac_psy_cfg = {}, usb_psy_cfg = {}; 34028c0984e5SSebastian Reichel struct ab8500_charger *di; 34031c1f13a0SLinus Walleij int charger_status; 34041c1f13a0SLinus Walleij int i, irq; 34051c1f13a0SLinus Walleij int ret; 34068c0984e5SSebastian Reichel 3407ad89cb5fSLinus Walleij di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL); 3408ad89cb5fSLinus Walleij if (!di) 34098c0984e5SSebastian Reichel return -ENOMEM; 34108c0984e5SSebastian Reichel 3411417c0fc2SLinus Walleij di->bm = &ab8500_bm_data; 34128c0984e5SSebastian Reichel 34138c0984e5SSebastian Reichel di->autopower_cfg = of_property_read_bool(np, "autopower_cfg"); 34148c0984e5SSebastian Reichel 34158c0984e5SSebastian Reichel /* get parent data */ 3416ad89cb5fSLinus Walleij di->dev = dev; 34178c0984e5SSebastian Reichel di->parent = dev_get_drvdata(pdev->dev.parent); 341897ab78baSLinus Walleij 341997ab78baSLinus Walleij /* Get ADC channels */ 34200f6dad11SLinus Walleij if (!is_ab8505(di->parent)) { 342136f1de0dSLinus Walleij di->adc_main_charger_v = devm_iio_channel_get(dev, "main_charger_v"); 342297ab78baSLinus Walleij if (IS_ERR(di->adc_main_charger_v)) { 342336f1de0dSLinus Walleij ret = dev_err_probe(dev, PTR_ERR(di->adc_main_charger_v), 342436f1de0dSLinus Walleij "failed to get ADC main charger voltage\n"); 342536f1de0dSLinus Walleij return ret; 342697ab78baSLinus Walleij } 342736f1de0dSLinus Walleij di->adc_main_charger_c = devm_iio_channel_get(dev, "main_charger_c"); 342897ab78baSLinus Walleij if (IS_ERR(di->adc_main_charger_c)) { 342936f1de0dSLinus Walleij ret = dev_err_probe(dev, PTR_ERR(di->adc_main_charger_c), 343036f1de0dSLinus Walleij "failed to get ADC main charger current\n"); 343136f1de0dSLinus Walleij return ret; 343297ab78baSLinus Walleij } 34330f6dad11SLinus Walleij } 3434ad89cb5fSLinus Walleij di->adc_vbus_v = devm_iio_channel_get(dev, "vbus_v"); 343597ab78baSLinus Walleij if (IS_ERR(di->adc_vbus_v)) { 343636f1de0dSLinus Walleij ret = dev_err_probe(dev, PTR_ERR(di->adc_vbus_v), 343736f1de0dSLinus Walleij "failed to get ADC USB charger voltage\n"); 343836f1de0dSLinus Walleij return ret; 343997ab78baSLinus Walleij } 344036f1de0dSLinus Walleij di->adc_usb_charger_c = devm_iio_channel_get(dev, "usb_charger_c"); 344197ab78baSLinus Walleij if (IS_ERR(di->adc_usb_charger_c)) { 344236f1de0dSLinus Walleij ret = dev_err_probe(dev, PTR_ERR(di->adc_usb_charger_c), 344336f1de0dSLinus Walleij "failed to get ADC USB charger current\n"); 344436f1de0dSLinus Walleij return ret; 344597ab78baSLinus Walleij } 34468c0984e5SSebastian Reichel 34471c1f13a0SLinus Walleij /* 34481c1f13a0SLinus Walleij * VDD ADC supply needs to be enabled from this driver when there 34491c1f13a0SLinus Walleij * is a charger connected to avoid erroneous BTEMP_HIGH/LOW 34501c1f13a0SLinus Walleij * interrupts during charging 34511c1f13a0SLinus Walleij */ 34521c1f13a0SLinus Walleij di->regu = devm_regulator_get(dev, "vddadc"); 34531c1f13a0SLinus Walleij if (IS_ERR(di->regu)) { 34541c1f13a0SLinus Walleij ret = PTR_ERR(di->regu); 34551c1f13a0SLinus Walleij dev_err(dev, "failed to get vddadc regulator\n"); 34561c1f13a0SLinus Walleij return ret; 34571c1f13a0SLinus Walleij } 34581c1f13a0SLinus Walleij 34591c1f13a0SLinus Walleij /* Request interrupts */ 34601c1f13a0SLinus Walleij for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) { 34611c1f13a0SLinus Walleij irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name); 34621c1f13a0SLinus Walleij if (irq < 0) 34631c1f13a0SLinus Walleij return irq; 34641c1f13a0SLinus Walleij 34651c1f13a0SLinus Walleij ret = devm_request_threaded_irq(dev, 34661c1f13a0SLinus Walleij irq, NULL, ab8500_charger_irq[i].isr, 34671c1f13a0SLinus Walleij IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, 34681c1f13a0SLinus Walleij ab8500_charger_irq[i].name, di); 34691c1f13a0SLinus Walleij 34701c1f13a0SLinus Walleij if (ret != 0) { 34711c1f13a0SLinus Walleij dev_err(dev, "failed to request %s IRQ %d: %d\n" 34721c1f13a0SLinus Walleij , ab8500_charger_irq[i].name, irq, ret); 34731c1f13a0SLinus Walleij return ret; 34741c1f13a0SLinus Walleij } 34751c1f13a0SLinus Walleij dev_dbg(dev, "Requested %s IRQ %d: %d\n", 34761c1f13a0SLinus Walleij ab8500_charger_irq[i].name, irq, ret); 34771c1f13a0SLinus Walleij } 34781c1f13a0SLinus Walleij 34798c0984e5SSebastian Reichel /* initialize lock */ 34808c0984e5SSebastian Reichel spin_lock_init(&di->usb_state.usb_lock); 34818c0984e5SSebastian Reichel mutex_init(&di->usb_ipt_crnt_lock); 34828c0984e5SSebastian Reichel 34838c0984e5SSebastian Reichel di->autopower = false; 34848c0984e5SSebastian Reichel di->invalid_charger_detect_state = 0; 34858c0984e5SSebastian Reichel 34868c0984e5SSebastian Reichel /* AC and USB supply config */ 348759f1b854SLinus Walleij ac_psy_cfg.of_node = np; 34888c0984e5SSebastian Reichel ac_psy_cfg.supplied_to = supply_interface; 34898c0984e5SSebastian Reichel ac_psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); 34908c0984e5SSebastian Reichel ac_psy_cfg.drv_data = &di->ac_chg; 349159f1b854SLinus Walleij usb_psy_cfg.of_node = np; 34928c0984e5SSebastian Reichel usb_psy_cfg.supplied_to = supply_interface; 34938c0984e5SSebastian Reichel usb_psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); 34948c0984e5SSebastian Reichel usb_psy_cfg.drv_data = &di->usb_chg; 34958c0984e5SSebastian Reichel 34968c0984e5SSebastian Reichel /* AC supply */ 34978c0984e5SSebastian Reichel /* ux500_charger sub-class */ 34988c0984e5SSebastian Reichel di->ac_chg.ops.enable = &ab8500_charger_ac_en; 34998c0984e5SSebastian Reichel di->ac_chg.ops.check_enable = &ab8500_charger_ac_check_enable; 35008c0984e5SSebastian Reichel di->ac_chg.ops.kick_wd = &ab8500_charger_watchdog_kick; 35018c0984e5SSebastian Reichel di->ac_chg.ops.update_curr = &ab8500_charger_update_charger_current; 3502bc6e0287SLinus Walleij di->ac_chg.max_out_volt_uv = ab8500_charger_voltage_map[ 35038c0984e5SSebastian Reichel ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; 350483e5aa77SLinus Walleij di->ac_chg.max_out_curr_ua = 35053aca6ecdSLinus Walleij ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1]; 35068c0984e5SSebastian Reichel di->ac_chg.wdt_refresh = CHG_WD_INTERVAL; 3507f9184a22SLinus Walleij /* 3508f9184a22SLinus Walleij * The AB8505 only supports USB charging. If we are not the 3509f9184a22SLinus Walleij * AB8505, register an AC charger. 3510f9184a22SLinus Walleij * 3511f9184a22SLinus Walleij * TODO: if this should be opt-in, add DT properties for this. 3512f9184a22SLinus Walleij */ 3513f9184a22SLinus Walleij if (!is_ab8505(di->parent)) 3514f9184a22SLinus Walleij di->ac_chg.enabled = true; 35158c0984e5SSebastian Reichel 35168c0984e5SSebastian Reichel /* USB supply */ 35178c0984e5SSebastian Reichel /* ux500_charger sub-class */ 35188c0984e5SSebastian Reichel di->usb_chg.ops.enable = &ab8500_charger_usb_en; 35198c0984e5SSebastian Reichel di->usb_chg.ops.check_enable = &ab8500_charger_usb_check_enable; 35208c0984e5SSebastian Reichel di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick; 35218c0984e5SSebastian Reichel di->usb_chg.ops.update_curr = &ab8500_charger_update_charger_current; 3522bc6e0287SLinus Walleij di->usb_chg.max_out_volt_uv = ab8500_charger_voltage_map[ 35238c0984e5SSebastian Reichel ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; 352483e5aa77SLinus Walleij di->usb_chg.max_out_curr_ua = 35253aca6ecdSLinus Walleij ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1]; 35268c0984e5SSebastian Reichel di->usb_chg.wdt_refresh = CHG_WD_INTERVAL; 352783e5aa77SLinus Walleij di->usb_state.usb_current_ua = -1; 35288c0984e5SSebastian Reichel 35298c0984e5SSebastian Reichel mutex_init(&di->charger_attached_mutex); 35308c0984e5SSebastian Reichel 35318c0984e5SSebastian Reichel /* Init work for HW failure check */ 35328c0984e5SSebastian Reichel INIT_DEFERRABLE_WORK(&di->check_hw_failure_work, 35338c0984e5SSebastian Reichel ab8500_charger_check_hw_failure_work); 35348c0984e5SSebastian Reichel INIT_DEFERRABLE_WORK(&di->check_usbchgnotok_work, 35358c0984e5SSebastian Reichel ab8500_charger_check_usbchargernotok_work); 35368c0984e5SSebastian Reichel 35378c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->ac_charger_attached_work, 35388c0984e5SSebastian Reichel ab8500_charger_ac_attached_work); 35398c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->usb_charger_attached_work, 35408c0984e5SSebastian Reichel ab8500_charger_usb_attached_work); 35418c0984e5SSebastian Reichel 35428c0984e5SSebastian Reichel /* 35438c0984e5SSebastian Reichel * For ABB revision 1.0 and 1.1 there is a bug in the watchdog 3544ddb74e98SAshish Chavan * logic. That means we have to continuously kick the charger 35458c0984e5SSebastian Reichel * watchdog even when no charger is connected. This is only 35468c0984e5SSebastian Reichel * valid once the AC charger has been enabled. This is 35478c0984e5SSebastian Reichel * a bug that is not handled by the algorithm and the 35488c0984e5SSebastian Reichel * watchdog have to be kicked by the charger driver 35498c0984e5SSebastian Reichel * when the AC charger is disabled 35508c0984e5SSebastian Reichel */ 35518c0984e5SSebastian Reichel INIT_DEFERRABLE_WORK(&di->kick_wd_work, 35528c0984e5SSebastian Reichel ab8500_charger_kick_watchdog_work); 35538c0984e5SSebastian Reichel 35548c0984e5SSebastian Reichel INIT_DEFERRABLE_WORK(&di->check_vbat_work, 35558c0984e5SSebastian Reichel ab8500_charger_check_vbat_work); 35568c0984e5SSebastian Reichel 35578c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->attach_work, 35588c0984e5SSebastian Reichel ab8500_charger_usb_link_attach_work); 35598c0984e5SSebastian Reichel 35608c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->usb_state_changed_work, 35618c0984e5SSebastian Reichel ab8500_charger_usb_state_changed_work); 35628c0984e5SSebastian Reichel 35638c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->vbus_drop_end_work, 35648c0984e5SSebastian Reichel ab8500_charger_vbus_drop_end_work); 35658c0984e5SSebastian Reichel 35668c0984e5SSebastian Reichel /* Init work for charger detection */ 35678c0984e5SSebastian Reichel INIT_WORK(&di->usb_link_status_work, 35688c0984e5SSebastian Reichel ab8500_charger_usb_link_status_work); 35698c0984e5SSebastian Reichel INIT_WORK(&di->ac_work, ab8500_charger_ac_work); 35708c0984e5SSebastian Reichel INIT_WORK(&di->detect_usb_type_work, 35718c0984e5SSebastian Reichel ab8500_charger_detect_usb_type_work); 35728c0984e5SSebastian Reichel 35738c0984e5SSebastian Reichel /* Init work for checking HW status */ 35748c0984e5SSebastian Reichel INIT_WORK(&di->check_main_thermal_prot_work, 35758c0984e5SSebastian Reichel ab8500_charger_check_main_thermal_prot_work); 35768c0984e5SSebastian Reichel INIT_WORK(&di->check_usb_thermal_prot_work, 35778c0984e5SSebastian Reichel ab8500_charger_check_usb_thermal_prot_work); 35788c0984e5SSebastian Reichel 35798c0984e5SSebastian Reichel 35808c0984e5SSebastian Reichel /* Initialize OVV, and other registers */ 35818c0984e5SSebastian Reichel ret = ab8500_charger_init_hw_registers(di); 35828c0984e5SSebastian Reichel if (ret) { 3583ad89cb5fSLinus Walleij dev_err(dev, "failed to initialize ABB registers\n"); 35841c1f13a0SLinus Walleij return ret; 35858c0984e5SSebastian Reichel } 35868c0984e5SSebastian Reichel 35878c0984e5SSebastian Reichel /* Register AC charger class */ 35888c0984e5SSebastian Reichel if (di->ac_chg.enabled) { 35891c1f13a0SLinus Walleij di->ac_chg.psy = devm_power_supply_register(dev, 35908c0984e5SSebastian Reichel &ab8500_ac_chg_desc, 35918c0984e5SSebastian Reichel &ac_psy_cfg); 35928c0984e5SSebastian Reichel if (IS_ERR(di->ac_chg.psy)) { 3593ad89cb5fSLinus Walleij dev_err(dev, "failed to register AC charger\n"); 35941c1f13a0SLinus Walleij return PTR_ERR(di->ac_chg.psy); 35958c0984e5SSebastian Reichel } 35968c0984e5SSebastian Reichel } 35978c0984e5SSebastian Reichel 35988c0984e5SSebastian Reichel /* Register USB charger class */ 35991c1f13a0SLinus Walleij di->usb_chg.psy = devm_power_supply_register(dev, 36008c0984e5SSebastian Reichel &ab8500_usb_chg_desc, 36018c0984e5SSebastian Reichel &usb_psy_cfg); 36028c0984e5SSebastian Reichel if (IS_ERR(di->usb_chg.psy)) { 3603ad89cb5fSLinus Walleij dev_err(dev, "failed to register USB charger\n"); 36041c1f13a0SLinus Walleij return PTR_ERR(di->usb_chg.psy); 36058c0984e5SSebastian Reichel } 36068c0984e5SSebastian Reichel 360759f1b854SLinus Walleij /* 360859f1b854SLinus Walleij * Check what battery we have, since we always have the USB 360959f1b854SLinus Walleij * psy, use that as a handle. 361059f1b854SLinus Walleij */ 361159f1b854SLinus Walleij ret = ab8500_bm_of_probe(di->usb_chg.psy, di->bm); 361259f1b854SLinus Walleij if (ret) 361359f1b854SLinus Walleij return dev_err_probe(dev, ret, 361459f1b854SLinus Walleij "failed to get battery information\n"); 361559f1b854SLinus Walleij 36168c0984e5SSebastian Reichel /* Identify the connected charger types during startup */ 36178c0984e5SSebastian Reichel charger_status = ab8500_charger_detect_chargers(di, true); 36188c0984e5SSebastian Reichel if (charger_status & AC_PW_CONN) { 36198c0984e5SSebastian Reichel di->ac.charger_connected = 1; 36208c0984e5SSebastian Reichel di->ac_conn = true; 36218c0984e5SSebastian Reichel ab8500_power_supply_changed(di, di->ac_chg.psy); 36228c0984e5SSebastian Reichel sysfs_notify(&di->ac_chg.psy->dev.kobj, NULL, "present"); 36238c0984e5SSebastian Reichel } 36248c0984e5SSebastian Reichel 36258c0984e5SSebastian Reichel platform_set_drvdata(pdev, di); 36268c0984e5SSebastian Reichel 36271c1f13a0SLinus Walleij /* Create something that will match the subdrivers when we bind */ 36281c1f13a0SLinus Walleij for (i = 0; i < ARRAY_SIZE(ab8500_charger_component_drivers); i++) { 36291c1f13a0SLinus Walleij struct device_driver *drv = &ab8500_charger_component_drivers[i]->driver; 36301c1f13a0SLinus Walleij struct device *p = NULL, *d; 36318c0984e5SSebastian Reichel 36321c1f13a0SLinus Walleij while ((d = platform_find_device_by_driver(p, drv))) { 36331c1f13a0SLinus Walleij put_device(p); 36345730c81dSYong Wu component_match_add(dev, &match, component_compare_dev, d); 36351c1f13a0SLinus Walleij p = d; 36368c0984e5SSebastian Reichel } 36371c1f13a0SLinus Walleij put_device(p); 36381c1f13a0SLinus Walleij } 36391c1f13a0SLinus Walleij if (!match) { 36401c1f13a0SLinus Walleij dev_err(dev, "no matching components\n"); 3641be2c0d54SChristophe JAILLET ret = -ENODEV; 3642be2c0d54SChristophe JAILLET goto remove_ab8500_bm; 36431c1f13a0SLinus Walleij } 36441c1f13a0SLinus Walleij if (IS_ERR(match)) { 36451c1f13a0SLinus Walleij dev_err(dev, "could not create component match\n"); 3646be2c0d54SChristophe JAILLET ret = PTR_ERR(match); 3647be2c0d54SChristophe JAILLET goto remove_ab8500_bm; 36488c0984e5SSebastian Reichel } 36498c0984e5SSebastian Reichel 36501c1f13a0SLinus Walleij di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2); 36511c1f13a0SLinus Walleij if (IS_ERR_OR_NULL(di->usb_phy)) { 36521c1f13a0SLinus Walleij dev_err(dev, "failed to get usb transceiver\n"); 36531c1f13a0SLinus Walleij ret = -EINVAL; 36546c50a08dSLinus Walleij goto remove_ab8500_bm; 36551c1f13a0SLinus Walleij } 36561c1f13a0SLinus Walleij di->nb.notifier_call = ab8500_charger_usb_notifier_call; 36571c1f13a0SLinus Walleij ret = usb_register_notifier(di->usb_phy, &di->nb); 36581c1f13a0SLinus Walleij if (ret) { 36591c1f13a0SLinus Walleij dev_err(dev, "failed to register usb notifier\n"); 36601c1f13a0SLinus Walleij goto put_usb_phy; 36611c1f13a0SLinus Walleij } 36621c1f13a0SLinus Walleij 36631c1f13a0SLinus Walleij ret = component_master_add_with_match(&pdev->dev, 36641c1f13a0SLinus Walleij &ab8500_charger_comp_ops, 36651c1f13a0SLinus Walleij match); 36661c1f13a0SLinus Walleij if (ret) { 36671c1f13a0SLinus Walleij dev_err(dev, "failed to add component master\n"); 36681c1f13a0SLinus Walleij goto free_notifier; 36691c1f13a0SLinus Walleij } 36701c1f13a0SLinus Walleij 36711c1f13a0SLinus Walleij return 0; 36721c1f13a0SLinus Walleij 36731c1f13a0SLinus Walleij free_notifier: 36748c0984e5SSebastian Reichel usb_unregister_notifier(di->usb_phy, &di->nb); 36758c0984e5SSebastian Reichel put_usb_phy: 36768c0984e5SSebastian Reichel usb_put_phy(di->usb_phy); 3677be2c0d54SChristophe JAILLET remove_ab8500_bm: 3678be2c0d54SChristophe JAILLET ab8500_bm_of_remove(di->usb_chg.psy, di->bm); 36798c0984e5SSebastian Reichel return ret; 36808c0984e5SSebastian Reichel } 36818c0984e5SSebastian Reichel 36821c1f13a0SLinus Walleij static int ab8500_charger_remove(struct platform_device *pdev) 36831c1f13a0SLinus Walleij { 36841c1f13a0SLinus Walleij struct ab8500_charger *di = platform_get_drvdata(pdev); 36851c1f13a0SLinus Walleij 36861c1f13a0SLinus Walleij component_master_del(&pdev->dev, &ab8500_charger_comp_ops); 36871c1f13a0SLinus Walleij 36881c1f13a0SLinus Walleij usb_unregister_notifier(di->usb_phy, &di->nb); 36896252c706SLinus Walleij ab8500_bm_of_remove(di->usb_chg.psy, di->bm); 36901c1f13a0SLinus Walleij usb_put_phy(di->usb_phy); 36911c1f13a0SLinus Walleij 36921c1f13a0SLinus Walleij return 0; 36931c1f13a0SLinus Walleij } 36941c1f13a0SLinus Walleij 3695f8efa0a8SLinus Walleij static SIMPLE_DEV_PM_OPS(ab8500_charger_pm_ops, ab8500_charger_suspend, ab8500_charger_resume); 3696f8efa0a8SLinus Walleij 36978c0984e5SSebastian Reichel static const struct of_device_id ab8500_charger_match[] = { 36988c0984e5SSebastian Reichel { .compatible = "stericsson,ab8500-charger", }, 36998c0984e5SSebastian Reichel { }, 37008c0984e5SSebastian Reichel }; 3701dfe52db1SZou Wei MODULE_DEVICE_TABLE(of, ab8500_charger_match); 37028c0984e5SSebastian Reichel 37038c0984e5SSebastian Reichel static struct platform_driver ab8500_charger_driver = { 37048c0984e5SSebastian Reichel .probe = ab8500_charger_probe, 37058c0984e5SSebastian Reichel .remove = ab8500_charger_remove, 37068c0984e5SSebastian Reichel .driver = { 37078c0984e5SSebastian Reichel .name = "ab8500-charger", 37088c0984e5SSebastian Reichel .of_match_table = ab8500_charger_match, 3709f8efa0a8SLinus Walleij .pm = &ab8500_charger_pm_ops, 37108c0984e5SSebastian Reichel }, 37118c0984e5SSebastian Reichel }; 37128c0984e5SSebastian Reichel 37138c0984e5SSebastian Reichel static int __init ab8500_charger_init(void) 37148c0984e5SSebastian Reichel { 37151c1f13a0SLinus Walleij int ret; 37161c1f13a0SLinus Walleij 37171c1f13a0SLinus Walleij ret = platform_register_drivers(ab8500_charger_component_drivers, 37181c1f13a0SLinus Walleij ARRAY_SIZE(ab8500_charger_component_drivers)); 37191c1f13a0SLinus Walleij if (ret) 37201c1f13a0SLinus Walleij return ret; 37211c1f13a0SLinus Walleij 3722*c4d33381SYuan Can ret = platform_driver_register(&ab8500_charger_driver); 3723*c4d33381SYuan Can if (ret) { 3724*c4d33381SYuan Can platform_unregister_drivers(ab8500_charger_component_drivers, 3725*c4d33381SYuan Can ARRAY_SIZE(ab8500_charger_component_drivers)); 3726*c4d33381SYuan Can return ret; 3727*c4d33381SYuan Can } 3728*c4d33381SYuan Can 3729*c4d33381SYuan Can return 0; 37308c0984e5SSebastian Reichel } 37318c0984e5SSebastian Reichel 37328c0984e5SSebastian Reichel static void __exit ab8500_charger_exit(void) 37338c0984e5SSebastian Reichel { 37341c1f13a0SLinus Walleij platform_unregister_drivers(ab8500_charger_component_drivers, 37351c1f13a0SLinus Walleij ARRAY_SIZE(ab8500_charger_component_drivers)); 37368c0984e5SSebastian Reichel platform_driver_unregister(&ab8500_charger_driver); 37378c0984e5SSebastian Reichel } 37388c0984e5SSebastian Reichel 37391c1f13a0SLinus Walleij module_init(ab8500_charger_init); 37408c0984e5SSebastian Reichel module_exit(ab8500_charger_exit); 37418c0984e5SSebastian Reichel 37428c0984e5SSebastian Reichel MODULE_LICENSE("GPL v2"); 37438c0984e5SSebastian Reichel MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy"); 37448c0984e5SSebastian Reichel MODULE_ALIAS("platform:ab8500-charger"); 37458c0984e5SSebastian Reichel MODULE_DESCRIPTION("AB8500 charger management driver"); 3746