162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) ST-Ericsson SA 2012
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Charger driver for AB8500
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author:
862306a36Sopenharmony_ci *	Johan Palsson <johan.palsson@stericsson.com>
962306a36Sopenharmony_ci *	Karl Komierowski <karl.komierowski@stericsson.com>
1062306a36Sopenharmony_ci *	Arun R Murthy <arun.murthy@stericsson.com>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/device.h>
1662306a36Sopenharmony_ci#include <linux/component.h>
1762306a36Sopenharmony_ci#include <linux/interrupt.h>
1862306a36Sopenharmony_ci#include <linux/delay.h>
1962306a36Sopenharmony_ci#include <linux/notifier.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci#include <linux/platform_device.h>
2262306a36Sopenharmony_ci#include <linux/power_supply.h>
2362306a36Sopenharmony_ci#include <linux/completion.h>
2462306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
2562306a36Sopenharmony_ci#include <linux/err.h>
2662306a36Sopenharmony_ci#include <linux/workqueue.h>
2762306a36Sopenharmony_ci#include <linux/kobject.h>
2862306a36Sopenharmony_ci#include <linux/of.h>
2962306a36Sopenharmony_ci#include <linux/mfd/core.h>
3062306a36Sopenharmony_ci#include <linux/mfd/abx500/ab8500.h>
3162306a36Sopenharmony_ci#include <linux/mfd/abx500.h>
3262306a36Sopenharmony_ci#include <linux/usb/otg.h>
3362306a36Sopenharmony_ci#include <linux/mutex.h>
3462306a36Sopenharmony_ci#include <linux/iio/consumer.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include "ab8500-bm.h"
3762306a36Sopenharmony_ci#include "ab8500-chargalg.h"
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* Charger constants */
4062306a36Sopenharmony_ci#define NO_PW_CONN			0
4162306a36Sopenharmony_ci#define AC_PW_CONN			1
4262306a36Sopenharmony_ci#define USB_PW_CONN			2
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define MAIN_WDOG_ENA			0x01
4562306a36Sopenharmony_ci#define MAIN_WDOG_KICK			0x02
4662306a36Sopenharmony_ci#define MAIN_WDOG_DIS			0x00
4762306a36Sopenharmony_ci#define CHARG_WD_KICK			0x01
4862306a36Sopenharmony_ci#define MAIN_CH_ENA			0x01
4962306a36Sopenharmony_ci#define MAIN_CH_NO_OVERSHOOT_ENA_N	0x02
5062306a36Sopenharmony_ci#define USB_CH_ENA			0x01
5162306a36Sopenharmony_ci#define USB_CHG_NO_OVERSHOOT_ENA_N	0x02
5262306a36Sopenharmony_ci#define MAIN_CH_DET			0x01
5362306a36Sopenharmony_ci#define MAIN_CH_CV_ON			0x04
5462306a36Sopenharmony_ci#define USB_CH_CV_ON			0x08
5562306a36Sopenharmony_ci#define VBUS_DET_DBNC100		0x02
5662306a36Sopenharmony_ci#define VBUS_DET_DBNC1			0x01
5762306a36Sopenharmony_ci#define OTP_ENABLE_WD			0x01
5862306a36Sopenharmony_ci#define DROP_COUNT_RESET		0x01
5962306a36Sopenharmony_ci#define USB_CH_DET			0x01
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define MAIN_CH_INPUT_CURR_SHIFT	4
6262306a36Sopenharmony_ci#define VBUS_IN_CURR_LIM_SHIFT		4
6362306a36Sopenharmony_ci#define AUTO_VBUS_IN_CURR_LIM_SHIFT	4
6462306a36Sopenharmony_ci#define VBUS_IN_CURR_LIM_RETRY_SET_TIME	30 /* seconds */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define LED_INDICATOR_PWM_ENA		0x01
6762306a36Sopenharmony_ci#define LED_INDICATOR_PWM_DIS		0x00
6862306a36Sopenharmony_ci#define LED_IND_CUR_5MA			0x04
6962306a36Sopenharmony_ci#define LED_INDICATOR_PWM_DUTY_252_256	0xBF
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* HW failure constants */
7262306a36Sopenharmony_ci#define MAIN_CH_TH_PROT			0x02
7362306a36Sopenharmony_ci#define VBUS_CH_NOK			0x08
7462306a36Sopenharmony_ci#define USB_CH_TH_PROT			0x02
7562306a36Sopenharmony_ci#define VBUS_OVV_TH			0x01
7662306a36Sopenharmony_ci#define MAIN_CH_NOK			0x01
7762306a36Sopenharmony_ci#define VBUS_DET			0x80
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#define MAIN_CH_STATUS2_MAINCHGDROP		0x80
8062306a36Sopenharmony_ci#define MAIN_CH_STATUS2_MAINCHARGERDETDBNC	0x40
8162306a36Sopenharmony_ci#define USB_CH_VBUSDROP				0x40
8262306a36Sopenharmony_ci#define USB_CH_VBUSDETDBNC			0x01
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/* UsbLineStatus register bit masks */
8562306a36Sopenharmony_ci#define AB8500_USB_LINK_STATUS		0x78
8662306a36Sopenharmony_ci#define AB8505_USB_LINK_STATUS		0xF8
8762306a36Sopenharmony_ci#define AB8500_STD_HOST_SUSP		0x18
8862306a36Sopenharmony_ci#define USB_LINK_STATUS_SHIFT		3
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/* Watchdog timeout constant */
9162306a36Sopenharmony_ci#define WD_TIMER			0x30 /* 4min */
9262306a36Sopenharmony_ci#define WD_KICK_INTERVAL		(60 * HZ)
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/* Lowest charger voltage is 3.39V -> 0x4E */
9562306a36Sopenharmony_ci#define LOW_VOLT_REG			0x4E
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci/* Step up/down delay in us */
9862306a36Sopenharmony_ci#define STEP_UDELAY			1000
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define CHARGER_STATUS_POLL 10 /* in ms */
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci#define CHG_WD_INTERVAL			(60 * HZ)
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define AB8500_SW_CONTROL_FALLBACK	0x03
10562306a36Sopenharmony_ci/* Wait for enumeration before charing in us */
10662306a36Sopenharmony_ci#define WAIT_ACA_RID_ENUMERATION	(5 * 1000)
10762306a36Sopenharmony_ci/*External charger control*/
10862306a36Sopenharmony_ci#define AB8500_SYS_CHARGER_CONTROL_REG		0x52
10962306a36Sopenharmony_ci#define EXTERNAL_CHARGER_DISABLE_REG_VAL	0x03
11062306a36Sopenharmony_ci#define EXTERNAL_CHARGER_ENABLE_REG_VAL		0x07
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci/* UsbLineStatus register - usb types */
11362306a36Sopenharmony_cienum ab8500_charger_link_status {
11462306a36Sopenharmony_ci	USB_STAT_NOT_CONFIGURED,
11562306a36Sopenharmony_ci	USB_STAT_STD_HOST_NC,
11662306a36Sopenharmony_ci	USB_STAT_STD_HOST_C_NS,
11762306a36Sopenharmony_ci	USB_STAT_STD_HOST_C_S,
11862306a36Sopenharmony_ci	USB_STAT_HOST_CHG_NM,
11962306a36Sopenharmony_ci	USB_STAT_HOST_CHG_HS,
12062306a36Sopenharmony_ci	USB_STAT_HOST_CHG_HS_CHIRP,
12162306a36Sopenharmony_ci	USB_STAT_DEDICATED_CHG,
12262306a36Sopenharmony_ci	USB_STAT_ACA_RID_A,
12362306a36Sopenharmony_ci	USB_STAT_ACA_RID_B,
12462306a36Sopenharmony_ci	USB_STAT_ACA_RID_C_NM,
12562306a36Sopenharmony_ci	USB_STAT_ACA_RID_C_HS,
12662306a36Sopenharmony_ci	USB_STAT_ACA_RID_C_HS_CHIRP,
12762306a36Sopenharmony_ci	USB_STAT_HM_IDGND,
12862306a36Sopenharmony_ci	USB_STAT_RESERVED,
12962306a36Sopenharmony_ci	USB_STAT_NOT_VALID_LINK,
13062306a36Sopenharmony_ci	USB_STAT_PHY_EN,
13162306a36Sopenharmony_ci	USB_STAT_SUP_NO_IDGND_VBUS,
13262306a36Sopenharmony_ci	USB_STAT_SUP_IDGND_VBUS,
13362306a36Sopenharmony_ci	USB_STAT_CHARGER_LINE_1,
13462306a36Sopenharmony_ci	USB_STAT_CARKIT_1,
13562306a36Sopenharmony_ci	USB_STAT_CARKIT_2,
13662306a36Sopenharmony_ci	USB_STAT_ACA_DOCK_CHARGER,
13762306a36Sopenharmony_ci};
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cienum ab8500_usb_state {
14062306a36Sopenharmony_ci	AB8500_BM_USB_STATE_RESET_HS,	/* HighSpeed Reset */
14162306a36Sopenharmony_ci	AB8500_BM_USB_STATE_RESET_FS,	/* FullSpeed/LowSpeed Reset */
14262306a36Sopenharmony_ci	AB8500_BM_USB_STATE_CONFIGURED,
14362306a36Sopenharmony_ci	AB8500_BM_USB_STATE_SUSPEND,
14462306a36Sopenharmony_ci	AB8500_BM_USB_STATE_RESUME,
14562306a36Sopenharmony_ci	AB8500_BM_USB_STATE_MAX,
14662306a36Sopenharmony_ci};
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci/* VBUS input current limits supported in AB8500 in uA */
14962306a36Sopenharmony_ci#define USB_CH_IP_CUR_LVL_0P05		50000
15062306a36Sopenharmony_ci#define USB_CH_IP_CUR_LVL_0P09		98000
15162306a36Sopenharmony_ci#define USB_CH_IP_CUR_LVL_0P19		193000
15262306a36Sopenharmony_ci#define USB_CH_IP_CUR_LVL_0P29		290000
15362306a36Sopenharmony_ci#define USB_CH_IP_CUR_LVL_0P38		380000
15462306a36Sopenharmony_ci#define USB_CH_IP_CUR_LVL_0P45		450000
15562306a36Sopenharmony_ci#define USB_CH_IP_CUR_LVL_0P5		500000
15662306a36Sopenharmony_ci#define USB_CH_IP_CUR_LVL_0P6		600000
15762306a36Sopenharmony_ci#define USB_CH_IP_CUR_LVL_0P7		700000
15862306a36Sopenharmony_ci#define USB_CH_IP_CUR_LVL_0P8		800000
15962306a36Sopenharmony_ci#define USB_CH_IP_CUR_LVL_0P9		900000
16062306a36Sopenharmony_ci#define USB_CH_IP_CUR_LVL_1P0		1000000
16162306a36Sopenharmony_ci#define USB_CH_IP_CUR_LVL_1P1		1100000
16262306a36Sopenharmony_ci#define USB_CH_IP_CUR_LVL_1P3		1300000
16362306a36Sopenharmony_ci#define USB_CH_IP_CUR_LVL_1P4		1400000
16462306a36Sopenharmony_ci#define USB_CH_IP_CUR_LVL_1P5		1500000
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci#define VBAT_TRESH_IP_CUR_RED		3800000
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci#define to_ab8500_charger_usb_device_info(x) container_of((x), \
16962306a36Sopenharmony_ci	struct ab8500_charger, usb_chg)
17062306a36Sopenharmony_ci#define to_ab8500_charger_ac_device_info(x) container_of((x), \
17162306a36Sopenharmony_ci	struct ab8500_charger, ac_chg)
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/**
17462306a36Sopenharmony_ci * struct ab8500_charger_interrupts - ab8500 interrupts
17562306a36Sopenharmony_ci * @name:	name of the interrupt
17662306a36Sopenharmony_ci * @isr		function pointer to the isr
17762306a36Sopenharmony_ci */
17862306a36Sopenharmony_cistruct ab8500_charger_interrupts {
17962306a36Sopenharmony_ci	char *name;
18062306a36Sopenharmony_ci	irqreturn_t (*isr)(int irq, void *data);
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistruct ab8500_charger_info {
18462306a36Sopenharmony_ci	int charger_connected;
18562306a36Sopenharmony_ci	int charger_online;
18662306a36Sopenharmony_ci	int charger_voltage_uv;
18762306a36Sopenharmony_ci	int cv_active;
18862306a36Sopenharmony_ci	bool wd_expired;
18962306a36Sopenharmony_ci	int charger_current_ua;
19062306a36Sopenharmony_ci};
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistruct ab8500_charger_event_flags {
19362306a36Sopenharmony_ci	bool mainextchnotok;
19462306a36Sopenharmony_ci	bool main_thermal_prot;
19562306a36Sopenharmony_ci	bool usb_thermal_prot;
19662306a36Sopenharmony_ci	bool vbus_ovv;
19762306a36Sopenharmony_ci	bool usbchargernotok;
19862306a36Sopenharmony_ci	bool chgwdexp;
19962306a36Sopenharmony_ci	bool vbus_collapse;
20062306a36Sopenharmony_ci	bool vbus_drop_end;
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistruct ab8500_charger_usb_state {
20462306a36Sopenharmony_ci	int usb_current_ua;
20562306a36Sopenharmony_ci	int usb_current_tmp_ua;
20662306a36Sopenharmony_ci	enum ab8500_usb_state state;
20762306a36Sopenharmony_ci	enum ab8500_usb_state state_tmp;
20862306a36Sopenharmony_ci	spinlock_t usb_lock;
20962306a36Sopenharmony_ci};
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistruct ab8500_charger_max_usb_in_curr {
21262306a36Sopenharmony_ci	int usb_type_max_ua;
21362306a36Sopenharmony_ci	int set_max_ua;
21462306a36Sopenharmony_ci	int calculated_max_ua;
21562306a36Sopenharmony_ci};
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/**
21862306a36Sopenharmony_ci * struct ab8500_charger - ab8500 Charger device information
21962306a36Sopenharmony_ci * @dev:		Pointer to the structure device
22062306a36Sopenharmony_ci * @vbus_detected:	VBUS detected
22162306a36Sopenharmony_ci * @vbus_detected_start:
22262306a36Sopenharmony_ci *			VBUS detected during startup
22362306a36Sopenharmony_ci * @ac_conn:		This will be true when the AC charger has been plugged
22462306a36Sopenharmony_ci * @vddadc_en_ac:	Indicate if VDD ADC supply is enabled because AC
22562306a36Sopenharmony_ci *			charger is enabled
22662306a36Sopenharmony_ci * @vddadc_en_usb:	Indicate if VDD ADC supply is enabled because USB
22762306a36Sopenharmony_ci *			charger is enabled
22862306a36Sopenharmony_ci * @vbat		Battery voltage
22962306a36Sopenharmony_ci * @old_vbat		Previously measured battery voltage
23062306a36Sopenharmony_ci * @usb_device_is_unrecognised	USB device is unrecognised by the hardware
23162306a36Sopenharmony_ci * @autopower		Indicate if we should have automatic pwron after pwrloss
23262306a36Sopenharmony_ci * @autopower_cfg	platform specific power config support for "pwron after pwrloss"
23362306a36Sopenharmony_ci * @invalid_charger_detect_state State when forcing AB to use invalid charger
23462306a36Sopenharmony_ci * @is_aca_rid:		Incicate if accessory is ACA type
23562306a36Sopenharmony_ci * @current_stepping_sessions:
23662306a36Sopenharmony_ci *			Counter for current stepping sessions
23762306a36Sopenharmony_ci * @parent:		Pointer to the struct ab8500
23862306a36Sopenharmony_ci * @adc_main_charger_v	ADC channel for main charger voltage
23962306a36Sopenharmony_ci * @adc_main_charger_c	ADC channel for main charger current
24062306a36Sopenharmony_ci * @adc_vbus_v		ADC channel for USB charger voltage
24162306a36Sopenharmony_ci * @adc_usb_charger_c	ADC channel for USB charger current
24262306a36Sopenharmony_ci * @bm:           	Platform specific battery management information
24362306a36Sopenharmony_ci * @flags:		Structure for information about events triggered
24462306a36Sopenharmony_ci * @usb_state:		Structure for usb stack information
24562306a36Sopenharmony_ci * @max_usb_in_curr:	Max USB charger input current
24662306a36Sopenharmony_ci * @ac_chg:		AC charger power supply
24762306a36Sopenharmony_ci * @usb_chg:		USB charger power supply
24862306a36Sopenharmony_ci * @ac:			Structure that holds the AC charger properties
24962306a36Sopenharmony_ci * @usb:		Structure that holds the USB charger properties
25062306a36Sopenharmony_ci * @regu:		Pointer to the struct regulator
25162306a36Sopenharmony_ci * @charger_wq:		Work queue for the IRQs and checking HW state
25262306a36Sopenharmony_ci * @usb_ipt_crnt_lock:	Lock to protect VBUS input current setting from mutuals
25362306a36Sopenharmony_ci * @pm_lock:		Lock to prevent system to suspend
25462306a36Sopenharmony_ci * @check_vbat_work	Work for checking vbat threshold to adjust vbus current
25562306a36Sopenharmony_ci * @check_hw_failure_work:	Work for checking HW state
25662306a36Sopenharmony_ci * @check_usbchgnotok_work:	Work for checking USB charger not ok status
25762306a36Sopenharmony_ci * @kick_wd_work:		Work for kicking the charger watchdog in case
25862306a36Sopenharmony_ci *				of ABB rev 1.* due to the watchog logic bug
25962306a36Sopenharmony_ci * @ac_charger_attached_work:	Work for checking if AC charger is still
26062306a36Sopenharmony_ci *				connected
26162306a36Sopenharmony_ci * @usb_charger_attached_work:	Work for checking if USB charger is still
26262306a36Sopenharmony_ci *				connected
26362306a36Sopenharmony_ci * @ac_work:			Work for checking AC charger connection
26462306a36Sopenharmony_ci * @detect_usb_type_work:	Work for detecting the USB type connected
26562306a36Sopenharmony_ci * @usb_link_status_work:	Work for checking the new USB link status
26662306a36Sopenharmony_ci * @usb_state_changed_work:	Work for checking USB state
26762306a36Sopenharmony_ci * @attach_work:		Work for detecting USB type
26862306a36Sopenharmony_ci * @vbus_drop_end_work:		Work for detecting VBUS drop end
26962306a36Sopenharmony_ci * @check_main_thermal_prot_work:
27062306a36Sopenharmony_ci *				Work for checking Main thermal status
27162306a36Sopenharmony_ci * @check_usb_thermal_prot_work:
27262306a36Sopenharmony_ci *				Work for checking USB thermal status
27362306a36Sopenharmony_ci * @charger_attached_mutex:	For controlling the wakelock
27462306a36Sopenharmony_ci */
27562306a36Sopenharmony_cistruct ab8500_charger {
27662306a36Sopenharmony_ci	struct device *dev;
27762306a36Sopenharmony_ci	bool vbus_detected;
27862306a36Sopenharmony_ci	bool vbus_detected_start;
27962306a36Sopenharmony_ci	bool ac_conn;
28062306a36Sopenharmony_ci	bool vddadc_en_ac;
28162306a36Sopenharmony_ci	bool vddadc_en_usb;
28262306a36Sopenharmony_ci	int vbat;
28362306a36Sopenharmony_ci	int old_vbat;
28462306a36Sopenharmony_ci	bool usb_device_is_unrecognised;
28562306a36Sopenharmony_ci	bool autopower;
28662306a36Sopenharmony_ci	bool autopower_cfg;
28762306a36Sopenharmony_ci	int invalid_charger_detect_state;
28862306a36Sopenharmony_ci	int is_aca_rid;
28962306a36Sopenharmony_ci	atomic_t current_stepping_sessions;
29062306a36Sopenharmony_ci	struct ab8500 *parent;
29162306a36Sopenharmony_ci	struct iio_channel *adc_main_charger_v;
29262306a36Sopenharmony_ci	struct iio_channel *adc_main_charger_c;
29362306a36Sopenharmony_ci	struct iio_channel *adc_vbus_v;
29462306a36Sopenharmony_ci	struct iio_channel *adc_usb_charger_c;
29562306a36Sopenharmony_ci	struct ab8500_bm_data *bm;
29662306a36Sopenharmony_ci	struct ab8500_charger_event_flags flags;
29762306a36Sopenharmony_ci	struct ab8500_charger_usb_state usb_state;
29862306a36Sopenharmony_ci	struct ab8500_charger_max_usb_in_curr max_usb_in_curr;
29962306a36Sopenharmony_ci	struct ux500_charger ac_chg;
30062306a36Sopenharmony_ci	struct ux500_charger usb_chg;
30162306a36Sopenharmony_ci	struct ab8500_charger_info ac;
30262306a36Sopenharmony_ci	struct ab8500_charger_info usb;
30362306a36Sopenharmony_ci	struct regulator *regu;
30462306a36Sopenharmony_ci	struct workqueue_struct *charger_wq;
30562306a36Sopenharmony_ci	struct mutex usb_ipt_crnt_lock;
30662306a36Sopenharmony_ci	struct delayed_work check_vbat_work;
30762306a36Sopenharmony_ci	struct delayed_work check_hw_failure_work;
30862306a36Sopenharmony_ci	struct delayed_work check_usbchgnotok_work;
30962306a36Sopenharmony_ci	struct delayed_work kick_wd_work;
31062306a36Sopenharmony_ci	struct delayed_work usb_state_changed_work;
31162306a36Sopenharmony_ci	struct delayed_work attach_work;
31262306a36Sopenharmony_ci	struct delayed_work ac_charger_attached_work;
31362306a36Sopenharmony_ci	struct delayed_work usb_charger_attached_work;
31462306a36Sopenharmony_ci	struct delayed_work vbus_drop_end_work;
31562306a36Sopenharmony_ci	struct work_struct ac_work;
31662306a36Sopenharmony_ci	struct work_struct detect_usb_type_work;
31762306a36Sopenharmony_ci	struct work_struct usb_link_status_work;
31862306a36Sopenharmony_ci	struct work_struct check_main_thermal_prot_work;
31962306a36Sopenharmony_ci	struct work_struct check_usb_thermal_prot_work;
32062306a36Sopenharmony_ci	struct usb_phy *usb_phy;
32162306a36Sopenharmony_ci	struct notifier_block nb;
32262306a36Sopenharmony_ci	struct mutex charger_attached_mutex;
32362306a36Sopenharmony_ci};
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci/* AC properties */
32662306a36Sopenharmony_cistatic enum power_supply_property ab8500_charger_ac_props[] = {
32762306a36Sopenharmony_ci	POWER_SUPPLY_PROP_HEALTH,
32862306a36Sopenharmony_ci	POWER_SUPPLY_PROP_PRESENT,
32962306a36Sopenharmony_ci	POWER_SUPPLY_PROP_ONLINE,
33062306a36Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_NOW,
33162306a36Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_AVG,
33262306a36Sopenharmony_ci	POWER_SUPPLY_PROP_CURRENT_NOW,
33362306a36Sopenharmony_ci};
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci/* USB properties */
33662306a36Sopenharmony_cistatic enum power_supply_property ab8500_charger_usb_props[] = {
33762306a36Sopenharmony_ci	POWER_SUPPLY_PROP_HEALTH,
33862306a36Sopenharmony_ci	POWER_SUPPLY_PROP_CURRENT_AVG,
33962306a36Sopenharmony_ci	POWER_SUPPLY_PROP_PRESENT,
34062306a36Sopenharmony_ci	POWER_SUPPLY_PROP_ONLINE,
34162306a36Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_NOW,
34262306a36Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_AVG,
34362306a36Sopenharmony_ci	POWER_SUPPLY_PROP_CURRENT_NOW,
34462306a36Sopenharmony_ci};
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci/*
34762306a36Sopenharmony_ci * Function for enabling and disabling sw fallback mode
34862306a36Sopenharmony_ci * should always be disabled when no charger is connected.
34962306a36Sopenharmony_ci */
35062306a36Sopenharmony_cistatic void ab8500_enable_disable_sw_fallback(struct ab8500_charger *di,
35162306a36Sopenharmony_ci		bool fallback)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	u8 val;
35462306a36Sopenharmony_ci	u8 reg;
35562306a36Sopenharmony_ci	u8 bank;
35662306a36Sopenharmony_ci	u8 bit;
35762306a36Sopenharmony_ci	int ret;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	dev_dbg(di->dev, "SW Fallback: %d\n", fallback);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (is_ab8500(di->parent)) {
36262306a36Sopenharmony_ci		bank = 0x15;
36362306a36Sopenharmony_ci		reg = 0x0;
36462306a36Sopenharmony_ci		bit = 3;
36562306a36Sopenharmony_ci	} else {
36662306a36Sopenharmony_ci		bank = AB8500_SYS_CTRL1_BLOCK;
36762306a36Sopenharmony_ci		reg = AB8500_SW_CONTROL_FALLBACK;
36862306a36Sopenharmony_ci		bit = 0;
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	/* read the register containing fallback bit */
37262306a36Sopenharmony_ci	ret = abx500_get_register_interruptible(di->dev, bank, reg, &val);
37362306a36Sopenharmony_ci	if (ret < 0) {
37462306a36Sopenharmony_ci		dev_err(di->dev, "%d read failed\n", __LINE__);
37562306a36Sopenharmony_ci		return;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	if (is_ab8500(di->parent)) {
37962306a36Sopenharmony_ci		/* enable the OPT emulation registers */
38062306a36Sopenharmony_ci		ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x2);
38162306a36Sopenharmony_ci		if (ret) {
38262306a36Sopenharmony_ci			dev_err(di->dev, "%d write failed\n", __LINE__);
38362306a36Sopenharmony_ci			goto disable_otp;
38462306a36Sopenharmony_ci		}
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (fallback)
38862306a36Sopenharmony_ci		val |= (1 << bit);
38962306a36Sopenharmony_ci	else
39062306a36Sopenharmony_ci		val &= ~(1 << bit);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	/* write back the changed fallback bit value to register */
39362306a36Sopenharmony_ci	ret = abx500_set_register_interruptible(di->dev, bank, reg, val);
39462306a36Sopenharmony_ci	if (ret) {
39562306a36Sopenharmony_ci		dev_err(di->dev, "%d write failed\n", __LINE__);
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cidisable_otp:
39962306a36Sopenharmony_ci	if (is_ab8500(di->parent)) {
40062306a36Sopenharmony_ci		/* disable the set OTP registers again */
40162306a36Sopenharmony_ci		ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x0);
40262306a36Sopenharmony_ci		if (ret) {
40362306a36Sopenharmony_ci			dev_err(di->dev, "%d write failed\n", __LINE__);
40462306a36Sopenharmony_ci		}
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci/**
40962306a36Sopenharmony_ci * ab8500_power_supply_changed - a wrapper with local extensions for
41062306a36Sopenharmony_ci * power_supply_changed
41162306a36Sopenharmony_ci * @di:	  pointer to the ab8500_charger structure
41262306a36Sopenharmony_ci * @psy:  pointer to power_supply_that have changed.
41362306a36Sopenharmony_ci *
41462306a36Sopenharmony_ci */
41562306a36Sopenharmony_cistatic void ab8500_power_supply_changed(struct ab8500_charger *di,
41662306a36Sopenharmony_ci					struct power_supply *psy)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	/*
41962306a36Sopenharmony_ci	 * This happens if we get notifications or interrupts and
42062306a36Sopenharmony_ci	 * the platform has been configured not to support one or
42162306a36Sopenharmony_ci	 * other type of charging.
42262306a36Sopenharmony_ci	 */
42362306a36Sopenharmony_ci	if (!psy)
42462306a36Sopenharmony_ci		return;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (di->autopower_cfg) {
42762306a36Sopenharmony_ci		if (!di->usb.charger_connected &&
42862306a36Sopenharmony_ci		    !di->ac.charger_connected &&
42962306a36Sopenharmony_ci		    di->autopower) {
43062306a36Sopenharmony_ci			di->autopower = false;
43162306a36Sopenharmony_ci			ab8500_enable_disable_sw_fallback(di, false);
43262306a36Sopenharmony_ci		} else if (!di->autopower &&
43362306a36Sopenharmony_ci			   (di->ac.charger_connected ||
43462306a36Sopenharmony_ci			    di->usb.charger_connected)) {
43562306a36Sopenharmony_ci			di->autopower = true;
43662306a36Sopenharmony_ci			ab8500_enable_disable_sw_fallback(di, true);
43762306a36Sopenharmony_ci		}
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci	power_supply_changed(psy);
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic void ab8500_charger_set_usb_connected(struct ab8500_charger *di,
44362306a36Sopenharmony_ci	bool connected)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	if (connected != di->usb.charger_connected) {
44662306a36Sopenharmony_ci		dev_dbg(di->dev, "USB connected:%i\n", connected);
44762306a36Sopenharmony_ci		di->usb.charger_connected = connected;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci		if (!connected)
45062306a36Sopenharmony_ci			di->flags.vbus_drop_end = false;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci		/*
45362306a36Sopenharmony_ci		 * Sometimes the platform is configured not to support
45462306a36Sopenharmony_ci		 * USB charging and no psy has been created, but we still
45562306a36Sopenharmony_ci		 * will get these notifications.
45662306a36Sopenharmony_ci		 */
45762306a36Sopenharmony_ci		if (di->usb_chg.psy) {
45862306a36Sopenharmony_ci			sysfs_notify(&di->usb_chg.psy->dev.kobj, NULL,
45962306a36Sopenharmony_ci				     "present");
46062306a36Sopenharmony_ci		}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci		if (connected) {
46362306a36Sopenharmony_ci			mutex_lock(&di->charger_attached_mutex);
46462306a36Sopenharmony_ci			mutex_unlock(&di->charger_attached_mutex);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci			if (is_ab8500(di->parent))
46762306a36Sopenharmony_ci				queue_delayed_work(di->charger_wq,
46862306a36Sopenharmony_ci					   &di->usb_charger_attached_work,
46962306a36Sopenharmony_ci					   HZ);
47062306a36Sopenharmony_ci		} else {
47162306a36Sopenharmony_ci			cancel_delayed_work_sync(&di->usb_charger_attached_work);
47262306a36Sopenharmony_ci			mutex_lock(&di->charger_attached_mutex);
47362306a36Sopenharmony_ci			mutex_unlock(&di->charger_attached_mutex);
47462306a36Sopenharmony_ci		}
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/**
47962306a36Sopenharmony_ci * ab8500_charger_get_ac_voltage() - get ac charger voltage
48062306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
48162306a36Sopenharmony_ci *
48262306a36Sopenharmony_ci * Returns ac charger voltage in microvolt (on success)
48362306a36Sopenharmony_ci */
48462306a36Sopenharmony_cistatic int ab8500_charger_get_ac_voltage(struct ab8500_charger *di)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	int vch, ret;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	/* Only measure voltage if the charger is connected */
48962306a36Sopenharmony_ci	if (di->ac.charger_connected) {
49062306a36Sopenharmony_ci		ret = iio_read_channel_processed(di->adc_main_charger_v, &vch);
49162306a36Sopenharmony_ci		if (ret < 0)
49262306a36Sopenharmony_ci			dev_err(di->dev, "%s ADC conv failed,\n", __func__);
49362306a36Sopenharmony_ci	} else {
49462306a36Sopenharmony_ci		vch = 0;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci	/* Convert to microvolt, IIO returns millivolt */
49762306a36Sopenharmony_ci	return vch * 1000;
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci/**
50162306a36Sopenharmony_ci * ab8500_charger_ac_cv() - check if the main charger is in CV mode
50262306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
50362306a36Sopenharmony_ci *
50462306a36Sopenharmony_ci * Returns ac charger CV mode (on success) else error code
50562306a36Sopenharmony_ci */
50662306a36Sopenharmony_cistatic int ab8500_charger_ac_cv(struct ab8500_charger *di)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	u8 val;
50962306a36Sopenharmony_ci	int ret = 0;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/* Only check CV mode if the charger is online */
51262306a36Sopenharmony_ci	if (di->ac.charger_online) {
51362306a36Sopenharmony_ci		ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
51462306a36Sopenharmony_ci			AB8500_CH_STATUS1_REG, &val);
51562306a36Sopenharmony_ci		if (ret < 0) {
51662306a36Sopenharmony_ci			dev_err(di->dev, "%s ab8500 read failed\n", __func__);
51762306a36Sopenharmony_ci			return 0;
51862306a36Sopenharmony_ci		}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci		if (val & MAIN_CH_CV_ON)
52162306a36Sopenharmony_ci			ret = 1;
52262306a36Sopenharmony_ci		else
52362306a36Sopenharmony_ci			ret = 0;
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	return ret;
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci/**
53062306a36Sopenharmony_ci * ab8500_charger_get_vbus_voltage() - get vbus voltage
53162306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
53262306a36Sopenharmony_ci *
53362306a36Sopenharmony_ci * This function returns the vbus voltage.
53462306a36Sopenharmony_ci * Returns vbus voltage in microvolt (on success)
53562306a36Sopenharmony_ci */
53662306a36Sopenharmony_cistatic int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	int vch, ret;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	/* Only measure voltage if the charger is connected */
54162306a36Sopenharmony_ci	if (di->usb.charger_connected) {
54262306a36Sopenharmony_ci		ret = iio_read_channel_processed(di->adc_vbus_v, &vch);
54362306a36Sopenharmony_ci		if (ret < 0)
54462306a36Sopenharmony_ci			dev_err(di->dev, "%s ADC conv failed,\n", __func__);
54562306a36Sopenharmony_ci	} else {
54662306a36Sopenharmony_ci		vch = 0;
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci	/* Convert to microvolt, IIO returns millivolt */
54962306a36Sopenharmony_ci	return vch * 1000;
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci/**
55362306a36Sopenharmony_ci * ab8500_charger_get_usb_current() - get usb charger current
55462306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
55562306a36Sopenharmony_ci *
55662306a36Sopenharmony_ci * This function returns the usb charger current.
55762306a36Sopenharmony_ci * Returns usb current in microamperes (on success) and error code on failure
55862306a36Sopenharmony_ci */
55962306a36Sopenharmony_cistatic int ab8500_charger_get_usb_current(struct ab8500_charger *di)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	int ich, ret;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	/* Only measure current if the charger is online */
56462306a36Sopenharmony_ci	if (di->usb.charger_online) {
56562306a36Sopenharmony_ci		ret = iio_read_channel_processed(di->adc_usb_charger_c, &ich);
56662306a36Sopenharmony_ci		if (ret < 0)
56762306a36Sopenharmony_ci			dev_err(di->dev, "%s ADC conv failed,\n", __func__);
56862306a36Sopenharmony_ci	} else {
56962306a36Sopenharmony_ci		ich = 0;
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci	/* Return microamperes */
57262306a36Sopenharmony_ci	return ich * 1000;
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci/**
57662306a36Sopenharmony_ci * ab8500_charger_get_ac_current() - get ac charger current
57762306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
57862306a36Sopenharmony_ci *
57962306a36Sopenharmony_ci * This function returns the ac charger current.
58062306a36Sopenharmony_ci * Returns ac current in microamperes (on success) and error code on failure.
58162306a36Sopenharmony_ci */
58262306a36Sopenharmony_cistatic int ab8500_charger_get_ac_current(struct ab8500_charger *di)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	int ich, ret;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	/* Only measure current if the charger is online */
58762306a36Sopenharmony_ci	if (di->ac.charger_online) {
58862306a36Sopenharmony_ci		ret = iio_read_channel_processed(di->adc_main_charger_c, &ich);
58962306a36Sopenharmony_ci		if (ret < 0)
59062306a36Sopenharmony_ci			dev_err(di->dev, "%s ADC conv failed,\n", __func__);
59162306a36Sopenharmony_ci	} else {
59262306a36Sopenharmony_ci		ich = 0;
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci	/* Return microamperes */
59562306a36Sopenharmony_ci	return ich * 1000;
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci/**
59962306a36Sopenharmony_ci * ab8500_charger_usb_cv() - check if the usb charger is in CV mode
60062306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
60162306a36Sopenharmony_ci *
60262306a36Sopenharmony_ci * Returns ac charger CV mode (on success) else error code
60362306a36Sopenharmony_ci */
60462306a36Sopenharmony_cistatic int ab8500_charger_usb_cv(struct ab8500_charger *di)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	int ret;
60762306a36Sopenharmony_ci	u8 val;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* Only check CV mode if the charger is online */
61062306a36Sopenharmony_ci	if (di->usb.charger_online) {
61162306a36Sopenharmony_ci		ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
61262306a36Sopenharmony_ci			AB8500_CH_USBCH_STAT1_REG, &val);
61362306a36Sopenharmony_ci		if (ret < 0) {
61462306a36Sopenharmony_ci			dev_err(di->dev, "%s ab8500 read failed\n", __func__);
61562306a36Sopenharmony_ci			return 0;
61662306a36Sopenharmony_ci		}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci		if (val & USB_CH_CV_ON)
61962306a36Sopenharmony_ci			ret = 1;
62062306a36Sopenharmony_ci		else
62162306a36Sopenharmony_ci			ret = 0;
62262306a36Sopenharmony_ci	} else {
62362306a36Sopenharmony_ci		ret = 0;
62462306a36Sopenharmony_ci	}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	return ret;
62762306a36Sopenharmony_ci}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci/**
63062306a36Sopenharmony_ci * ab8500_charger_detect_chargers() - Detect the connected chargers
63162306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
63262306a36Sopenharmony_ci * @probe:	if probe, don't delay and wait for HW
63362306a36Sopenharmony_ci *
63462306a36Sopenharmony_ci * Returns the type of charger connected.
63562306a36Sopenharmony_ci * For USB it will not mean we can actually charge from it
63662306a36Sopenharmony_ci * but that there is a USB cable connected that we have to
63762306a36Sopenharmony_ci * identify. This is used during startup when we don't get
63862306a36Sopenharmony_ci * interrupts of the charger detection
63962306a36Sopenharmony_ci *
64062306a36Sopenharmony_ci * Returns an integer value, that means,
64162306a36Sopenharmony_ci * NO_PW_CONN  no power supply is connected
64262306a36Sopenharmony_ci * AC_PW_CONN  if the AC power supply is connected
64362306a36Sopenharmony_ci * USB_PW_CONN  if the USB power supply is connected
64462306a36Sopenharmony_ci * AC_PW_CONN + USB_PW_CONN if USB and AC power supplies are both connected
64562306a36Sopenharmony_ci */
64662306a36Sopenharmony_cistatic int ab8500_charger_detect_chargers(struct ab8500_charger *di, bool probe)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	int result = NO_PW_CONN;
64962306a36Sopenharmony_ci	int ret;
65062306a36Sopenharmony_ci	u8 val;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	/* Check for AC charger */
65362306a36Sopenharmony_ci	ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
65462306a36Sopenharmony_ci		AB8500_CH_STATUS1_REG, &val);
65562306a36Sopenharmony_ci	if (ret < 0) {
65662306a36Sopenharmony_ci		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
65762306a36Sopenharmony_ci		return ret;
65862306a36Sopenharmony_ci	}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	if (val & MAIN_CH_DET)
66162306a36Sopenharmony_ci		result = AC_PW_CONN;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	/* Check for USB charger */
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	if (!probe) {
66662306a36Sopenharmony_ci		/*
66762306a36Sopenharmony_ci		 * AB8500 says VBUS_DET_DBNC1 & VBUS_DET_DBNC100
66862306a36Sopenharmony_ci		 * when disconnecting ACA even though no
66962306a36Sopenharmony_ci		 * charger was connected. Try waiting a little
67062306a36Sopenharmony_ci		 * longer than the 100 ms of VBUS_DET_DBNC100...
67162306a36Sopenharmony_ci		 */
67262306a36Sopenharmony_ci		msleep(110);
67362306a36Sopenharmony_ci	}
67462306a36Sopenharmony_ci	ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
67562306a36Sopenharmony_ci		AB8500_CH_USBCH_STAT1_REG, &val);
67662306a36Sopenharmony_ci	if (ret < 0) {
67762306a36Sopenharmony_ci		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
67862306a36Sopenharmony_ci		return ret;
67962306a36Sopenharmony_ci	}
68062306a36Sopenharmony_ci	dev_dbg(di->dev,
68162306a36Sopenharmony_ci		"%s AB8500_CH_USBCH_STAT1_REG %x\n", __func__,
68262306a36Sopenharmony_ci		val);
68362306a36Sopenharmony_ci	if ((val & VBUS_DET_DBNC1) && (val & VBUS_DET_DBNC100))
68462306a36Sopenharmony_ci		result |= USB_PW_CONN;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	return result;
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci/**
69062306a36Sopenharmony_ci * ab8500_charger_max_usb_curr() - get the max curr for the USB type
69162306a36Sopenharmony_ci * @di:			pointer to the ab8500_charger structure
69262306a36Sopenharmony_ci * @link_status:	the identified USB type
69362306a36Sopenharmony_ci *
69462306a36Sopenharmony_ci * Get the maximum current that is allowed to be drawn from the host
69562306a36Sopenharmony_ci * based on the USB type.
69662306a36Sopenharmony_ci * Returns error code in case of failure else 0 on success
69762306a36Sopenharmony_ci */
69862306a36Sopenharmony_cistatic int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
69962306a36Sopenharmony_ci		enum ab8500_charger_link_status link_status)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	int ret = 0;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	di->usb_device_is_unrecognised = false;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	/*
70662306a36Sopenharmony_ci	 * Platform only supports USB 2.0.
70762306a36Sopenharmony_ci	 * This means that charging current from USB source
70862306a36Sopenharmony_ci	 * is maximum 500 mA. Every occurrence of USB_STAT_*_HOST_*
70962306a36Sopenharmony_ci	 * should set USB_CH_IP_CUR_LVL_0P5.
71062306a36Sopenharmony_ci	 */
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	switch (link_status) {
71362306a36Sopenharmony_ci	case USB_STAT_STD_HOST_NC:
71462306a36Sopenharmony_ci	case USB_STAT_STD_HOST_C_NS:
71562306a36Sopenharmony_ci	case USB_STAT_STD_HOST_C_S:
71662306a36Sopenharmony_ci		dev_dbg(di->dev, "USB Type - Standard host is "
71762306a36Sopenharmony_ci			"detected through USB driver\n");
71862306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5;
71962306a36Sopenharmony_ci		di->is_aca_rid = 0;
72062306a36Sopenharmony_ci		break;
72162306a36Sopenharmony_ci	case USB_STAT_HOST_CHG_HS_CHIRP:
72262306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5;
72362306a36Sopenharmony_ci		di->is_aca_rid = 0;
72462306a36Sopenharmony_ci		break;
72562306a36Sopenharmony_ci	case USB_STAT_HOST_CHG_HS:
72662306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5;
72762306a36Sopenharmony_ci		di->is_aca_rid = 0;
72862306a36Sopenharmony_ci		break;
72962306a36Sopenharmony_ci	case USB_STAT_ACA_RID_C_HS:
73062306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P9;
73162306a36Sopenharmony_ci		di->is_aca_rid = 0;
73262306a36Sopenharmony_ci		break;
73362306a36Sopenharmony_ci	case USB_STAT_ACA_RID_A:
73462306a36Sopenharmony_ci		/*
73562306a36Sopenharmony_ci		 * Dedicated charger level minus maximum current accessory
73662306a36Sopenharmony_ci		 * can consume (900mA). Closest level is 500mA
73762306a36Sopenharmony_ci		 */
73862306a36Sopenharmony_ci		dev_dbg(di->dev, "USB_STAT_ACA_RID_A detected\n");
73962306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5;
74062306a36Sopenharmony_ci		di->is_aca_rid = 1;
74162306a36Sopenharmony_ci		break;
74262306a36Sopenharmony_ci	case USB_STAT_ACA_RID_B:
74362306a36Sopenharmony_ci		/*
74462306a36Sopenharmony_ci		 * Dedicated charger level minus 120mA (20mA for ACA and
74562306a36Sopenharmony_ci		 * 100mA for potential accessory). Closest level is 1300mA
74662306a36Sopenharmony_ci		 */
74762306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_1P3;
74862306a36Sopenharmony_ci		dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
74962306a36Sopenharmony_ci				di->max_usb_in_curr.usb_type_max_ua);
75062306a36Sopenharmony_ci		di->is_aca_rid = 1;
75162306a36Sopenharmony_ci		break;
75262306a36Sopenharmony_ci	case USB_STAT_HOST_CHG_NM:
75362306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5;
75462306a36Sopenharmony_ci		di->is_aca_rid = 0;
75562306a36Sopenharmony_ci		break;
75662306a36Sopenharmony_ci	case USB_STAT_DEDICATED_CHG:
75762306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_1P5;
75862306a36Sopenharmony_ci		di->is_aca_rid = 0;
75962306a36Sopenharmony_ci		break;
76062306a36Sopenharmony_ci	case USB_STAT_ACA_RID_C_HS_CHIRP:
76162306a36Sopenharmony_ci	case USB_STAT_ACA_RID_C_NM:
76262306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_1P5;
76362306a36Sopenharmony_ci		di->is_aca_rid = 1;
76462306a36Sopenharmony_ci		break;
76562306a36Sopenharmony_ci	case USB_STAT_NOT_CONFIGURED:
76662306a36Sopenharmony_ci		if (di->vbus_detected) {
76762306a36Sopenharmony_ci			di->usb_device_is_unrecognised = true;
76862306a36Sopenharmony_ci			dev_dbg(di->dev, "USB Type - Legacy charger.\n");
76962306a36Sopenharmony_ci			di->max_usb_in_curr.usb_type_max_ua =
77062306a36Sopenharmony_ci						USB_CH_IP_CUR_LVL_1P5;
77162306a36Sopenharmony_ci			break;
77262306a36Sopenharmony_ci		}
77362306a36Sopenharmony_ci		fallthrough;
77462306a36Sopenharmony_ci	case USB_STAT_HM_IDGND:
77562306a36Sopenharmony_ci		dev_err(di->dev, "USB Type - Charging not allowed\n");
77662306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P05;
77762306a36Sopenharmony_ci		ret = -ENXIO;
77862306a36Sopenharmony_ci		break;
77962306a36Sopenharmony_ci	case USB_STAT_RESERVED:
78062306a36Sopenharmony_ci		if (is_ab8500(di->parent)) {
78162306a36Sopenharmony_ci			di->flags.vbus_collapse = true;
78262306a36Sopenharmony_ci			dev_err(di->dev, "USB Type - USB_STAT_RESERVED "
78362306a36Sopenharmony_ci						"VBUS has collapsed\n");
78462306a36Sopenharmony_ci			ret = -ENXIO;
78562306a36Sopenharmony_ci			break;
78662306a36Sopenharmony_ci		} else {
78762306a36Sopenharmony_ci			dev_dbg(di->dev, "USB Type - Charging not allowed\n");
78862306a36Sopenharmony_ci			di->max_usb_in_curr.usb_type_max_ua =
78962306a36Sopenharmony_ci						USB_CH_IP_CUR_LVL_0P05;
79062306a36Sopenharmony_ci			dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d",
79162306a36Sopenharmony_ci				link_status,
79262306a36Sopenharmony_ci				di->max_usb_in_curr.usb_type_max_ua);
79362306a36Sopenharmony_ci			ret = -ENXIO;
79462306a36Sopenharmony_ci			break;
79562306a36Sopenharmony_ci		}
79662306a36Sopenharmony_ci	case USB_STAT_CARKIT_1:
79762306a36Sopenharmony_ci	case USB_STAT_CARKIT_2:
79862306a36Sopenharmony_ci	case USB_STAT_ACA_DOCK_CHARGER:
79962306a36Sopenharmony_ci	case USB_STAT_CHARGER_LINE_1:
80062306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5;
80162306a36Sopenharmony_ci		dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
80262306a36Sopenharmony_ci				di->max_usb_in_curr.usb_type_max_ua);
80362306a36Sopenharmony_ci		break;
80462306a36Sopenharmony_ci	case USB_STAT_NOT_VALID_LINK:
80562306a36Sopenharmony_ci		dev_err(di->dev, "USB Type invalid - try charging anyway\n");
80662306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5;
80762306a36Sopenharmony_ci		break;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	default:
81062306a36Sopenharmony_ci		dev_err(di->dev, "USB Type - Unknown\n");
81162306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P05;
81262306a36Sopenharmony_ci		ret = -ENXIO;
81362306a36Sopenharmony_ci		break;
81462306a36Sopenharmony_ci	}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	di->max_usb_in_curr.set_max_ua = di->max_usb_in_curr.usb_type_max_ua;
81762306a36Sopenharmony_ci	dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d",
81862306a36Sopenharmony_ci		link_status, di->max_usb_in_curr.set_max_ua);
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	return ret;
82162306a36Sopenharmony_ci}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci/**
82462306a36Sopenharmony_ci * ab8500_charger_read_usb_type() - read the type of usb connected
82562306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
82662306a36Sopenharmony_ci *
82762306a36Sopenharmony_ci * Detect the type of the plugged USB
82862306a36Sopenharmony_ci * Returns error code in case of failure else 0 on success
82962306a36Sopenharmony_ci */
83062306a36Sopenharmony_cistatic int ab8500_charger_read_usb_type(struct ab8500_charger *di)
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	int ret;
83362306a36Sopenharmony_ci	u8 val;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	ret = abx500_get_register_interruptible(di->dev,
83662306a36Sopenharmony_ci		AB8500_INTERRUPT, AB8500_IT_SOURCE21_REG, &val);
83762306a36Sopenharmony_ci	if (ret < 0) {
83862306a36Sopenharmony_ci		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
83962306a36Sopenharmony_ci		return ret;
84062306a36Sopenharmony_ci	}
84162306a36Sopenharmony_ci	if (is_ab8500(di->parent))
84262306a36Sopenharmony_ci		ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
84362306a36Sopenharmony_ci			AB8500_USB_LINE_STAT_REG, &val);
84462306a36Sopenharmony_ci	else
84562306a36Sopenharmony_ci		ret = abx500_get_register_interruptible(di->dev,
84662306a36Sopenharmony_ci			AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val);
84762306a36Sopenharmony_ci	if (ret < 0) {
84862306a36Sopenharmony_ci		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
84962306a36Sopenharmony_ci		return ret;
85062306a36Sopenharmony_ci	}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	/* get the USB type */
85362306a36Sopenharmony_ci	if (is_ab8500(di->parent))
85462306a36Sopenharmony_ci		val = (val & AB8500_USB_LINK_STATUS) >> USB_LINK_STATUS_SHIFT;
85562306a36Sopenharmony_ci	else
85662306a36Sopenharmony_ci		val = (val & AB8505_USB_LINK_STATUS) >> USB_LINK_STATUS_SHIFT;
85762306a36Sopenharmony_ci	ret = ab8500_charger_max_usb_curr(di,
85862306a36Sopenharmony_ci		(enum ab8500_charger_link_status) val);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	return ret;
86162306a36Sopenharmony_ci}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci/**
86462306a36Sopenharmony_ci * ab8500_charger_detect_usb_type() - get the type of usb connected
86562306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
86662306a36Sopenharmony_ci *
86762306a36Sopenharmony_ci * Detect the type of the plugged USB
86862306a36Sopenharmony_ci * Returns error code in case of failure else 0 on success
86962306a36Sopenharmony_ci */
87062306a36Sopenharmony_cistatic int ab8500_charger_detect_usb_type(struct ab8500_charger *di)
87162306a36Sopenharmony_ci{
87262306a36Sopenharmony_ci	int i, ret;
87362306a36Sopenharmony_ci	u8 val;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	/*
87662306a36Sopenharmony_ci	 * On getting the VBUS rising edge detect interrupt there
87762306a36Sopenharmony_ci	 * is a 250ms delay after which the register UsbLineStatus
87862306a36Sopenharmony_ci	 * is filled with valid data.
87962306a36Sopenharmony_ci	 */
88062306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
88162306a36Sopenharmony_ci		msleep(250);
88262306a36Sopenharmony_ci		ret = abx500_get_register_interruptible(di->dev,
88362306a36Sopenharmony_ci			AB8500_INTERRUPT, AB8500_IT_SOURCE21_REG,
88462306a36Sopenharmony_ci			&val);
88562306a36Sopenharmony_ci		dev_dbg(di->dev, "%s AB8500_IT_SOURCE21_REG %x\n",
88662306a36Sopenharmony_ci			__func__, val);
88762306a36Sopenharmony_ci		if (ret < 0) {
88862306a36Sopenharmony_ci			dev_err(di->dev, "%s ab8500 read failed\n", __func__);
88962306a36Sopenharmony_ci			return ret;
89062306a36Sopenharmony_ci		}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci		if (is_ab8500(di->parent))
89362306a36Sopenharmony_ci			ret = abx500_get_register_interruptible(di->dev,
89462306a36Sopenharmony_ci				AB8500_USB, AB8500_USB_LINE_STAT_REG, &val);
89562306a36Sopenharmony_ci		else
89662306a36Sopenharmony_ci			ret = abx500_get_register_interruptible(di->dev,
89762306a36Sopenharmony_ci				AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val);
89862306a36Sopenharmony_ci		if (ret < 0) {
89962306a36Sopenharmony_ci			dev_err(di->dev, "%s ab8500 read failed\n", __func__);
90062306a36Sopenharmony_ci			return ret;
90162306a36Sopenharmony_ci		}
90262306a36Sopenharmony_ci		dev_dbg(di->dev, "%s AB8500_USB_LINE_STAT_REG %x\n", __func__,
90362306a36Sopenharmony_ci			val);
90462306a36Sopenharmony_ci		/*
90562306a36Sopenharmony_ci		 * Until the IT source register is read the UsbLineStatus
90662306a36Sopenharmony_ci		 * register is not updated, hence doing the same
90762306a36Sopenharmony_ci		 * Revisit this:
90862306a36Sopenharmony_ci		 */
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci		/* get the USB type */
91162306a36Sopenharmony_ci		if (is_ab8500(di->parent))
91262306a36Sopenharmony_ci			val = (val & AB8500_USB_LINK_STATUS) >>
91362306a36Sopenharmony_ci							USB_LINK_STATUS_SHIFT;
91462306a36Sopenharmony_ci		else
91562306a36Sopenharmony_ci			val = (val & AB8505_USB_LINK_STATUS) >>
91662306a36Sopenharmony_ci							USB_LINK_STATUS_SHIFT;
91762306a36Sopenharmony_ci		if (val)
91862306a36Sopenharmony_ci			break;
91962306a36Sopenharmony_ci	}
92062306a36Sopenharmony_ci	ret = ab8500_charger_max_usb_curr(di,
92162306a36Sopenharmony_ci		(enum ab8500_charger_link_status) val);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	return ret;
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci/*
92762306a36Sopenharmony_ci * This array maps the raw hex value to charger voltage used by the AB8500
92862306a36Sopenharmony_ci * Values taken from the UM0836, in microvolt.
92962306a36Sopenharmony_ci */
93062306a36Sopenharmony_cistatic int ab8500_charger_voltage_map[] = {
93162306a36Sopenharmony_ci	3500000,
93262306a36Sopenharmony_ci	3525000,
93362306a36Sopenharmony_ci	3550000,
93462306a36Sopenharmony_ci	3575000,
93562306a36Sopenharmony_ci	3600000,
93662306a36Sopenharmony_ci	3625000,
93762306a36Sopenharmony_ci	3650000,
93862306a36Sopenharmony_ci	3675000,
93962306a36Sopenharmony_ci	3700000,
94062306a36Sopenharmony_ci	3725000,
94162306a36Sopenharmony_ci	3750000,
94262306a36Sopenharmony_ci	3775000,
94362306a36Sopenharmony_ci	3800000,
94462306a36Sopenharmony_ci	3825000,
94562306a36Sopenharmony_ci	3850000,
94662306a36Sopenharmony_ci	3875000,
94762306a36Sopenharmony_ci	3900000,
94862306a36Sopenharmony_ci	3925000,
94962306a36Sopenharmony_ci	3950000,
95062306a36Sopenharmony_ci	3975000,
95162306a36Sopenharmony_ci	4000000,
95262306a36Sopenharmony_ci	4025000,
95362306a36Sopenharmony_ci	4050000,
95462306a36Sopenharmony_ci	4060000,
95562306a36Sopenharmony_ci	4070000,
95662306a36Sopenharmony_ci	4080000,
95762306a36Sopenharmony_ci	4090000,
95862306a36Sopenharmony_ci	4100000,
95962306a36Sopenharmony_ci	4110000,
96062306a36Sopenharmony_ci	4120000,
96162306a36Sopenharmony_ci	4130000,
96262306a36Sopenharmony_ci	4140000,
96362306a36Sopenharmony_ci	4150000,
96462306a36Sopenharmony_ci	4160000,
96562306a36Sopenharmony_ci	4170000,
96662306a36Sopenharmony_ci	4180000,
96762306a36Sopenharmony_ci	4190000,
96862306a36Sopenharmony_ci	4200000,
96962306a36Sopenharmony_ci	4210000,
97062306a36Sopenharmony_ci	4220000,
97162306a36Sopenharmony_ci	4230000,
97262306a36Sopenharmony_ci	4240000,
97362306a36Sopenharmony_ci	4250000,
97462306a36Sopenharmony_ci	4260000,
97562306a36Sopenharmony_ci	4270000,
97662306a36Sopenharmony_ci	4280000,
97762306a36Sopenharmony_ci	4290000,
97862306a36Sopenharmony_ci	4300000,
97962306a36Sopenharmony_ci	4310000,
98062306a36Sopenharmony_ci	4320000,
98162306a36Sopenharmony_ci	4330000,
98262306a36Sopenharmony_ci	4340000,
98362306a36Sopenharmony_ci	4350000,
98462306a36Sopenharmony_ci	4360000,
98562306a36Sopenharmony_ci	4370000,
98662306a36Sopenharmony_ci	4380000,
98762306a36Sopenharmony_ci	4390000,
98862306a36Sopenharmony_ci	4400000,
98962306a36Sopenharmony_ci	4410000,
99062306a36Sopenharmony_ci	4420000,
99162306a36Sopenharmony_ci	4430000,
99262306a36Sopenharmony_ci	4440000,
99362306a36Sopenharmony_ci	4450000,
99462306a36Sopenharmony_ci	4460000,
99562306a36Sopenharmony_ci	4470000,
99662306a36Sopenharmony_ci	4480000,
99762306a36Sopenharmony_ci	4490000,
99862306a36Sopenharmony_ci	4500000,
99962306a36Sopenharmony_ci	4510000,
100062306a36Sopenharmony_ci	4520000,
100162306a36Sopenharmony_ci	4530000,
100262306a36Sopenharmony_ci	4540000,
100362306a36Sopenharmony_ci	4550000,
100462306a36Sopenharmony_ci	4560000,
100562306a36Sopenharmony_ci	4570000,
100662306a36Sopenharmony_ci	4580000,
100762306a36Sopenharmony_ci	4590000,
100862306a36Sopenharmony_ci	4600000,
100962306a36Sopenharmony_ci};
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_cistatic int ab8500_voltage_to_regval(int voltage_uv)
101262306a36Sopenharmony_ci{
101362306a36Sopenharmony_ci	int i;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	/* Special case for voltage below 3.5V */
101662306a36Sopenharmony_ci	if (voltage_uv < ab8500_charger_voltage_map[0])
101762306a36Sopenharmony_ci		return LOW_VOLT_REG;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	for (i = 1; i < ARRAY_SIZE(ab8500_charger_voltage_map); i++) {
102062306a36Sopenharmony_ci		if (voltage_uv < ab8500_charger_voltage_map[i])
102162306a36Sopenharmony_ci			return i - 1;
102262306a36Sopenharmony_ci	}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	/* If not last element, return error */
102562306a36Sopenharmony_ci	i = ARRAY_SIZE(ab8500_charger_voltage_map) - 1;
102662306a36Sopenharmony_ci	if (voltage_uv == ab8500_charger_voltage_map[i])
102762306a36Sopenharmony_ci		return i;
102862306a36Sopenharmony_ci	else
102962306a36Sopenharmony_ci		return -1;
103062306a36Sopenharmony_ci}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci/* This array maps the raw register value to charger input current */
103362306a36Sopenharmony_cistatic int ab8500_charge_input_curr_map[] = {
103462306a36Sopenharmony_ci	50000, 98000, 193000, 290000, 380000, 450000, 500000, 600000,
103562306a36Sopenharmony_ci	700000, 800000, 900000, 1000000, 1100000, 1300000, 1400000, 1500000,
103662306a36Sopenharmony_ci};
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci/* This array maps the raw register value to charger output current */
103962306a36Sopenharmony_cistatic int ab8500_charge_output_curr_map[] = {
104062306a36Sopenharmony_ci	100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000,
104162306a36Sopenharmony_ci	900000, 1000000, 1100000, 1200000, 1300000, 1400000, 1500000, 1500000,
104262306a36Sopenharmony_ci};
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_cistatic int ab8500_current_to_regval(struct ab8500_charger *di, int curr_ua)
104562306a36Sopenharmony_ci{
104662306a36Sopenharmony_ci	int i;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	if (curr_ua < ab8500_charge_output_curr_map[0])
104962306a36Sopenharmony_ci		return 0;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ab8500_charge_output_curr_map); i++) {
105262306a36Sopenharmony_ci		if (curr_ua < ab8500_charge_output_curr_map[i])
105362306a36Sopenharmony_ci			return i - 1;
105462306a36Sopenharmony_ci	}
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	/* If not last element, return error */
105762306a36Sopenharmony_ci	i =  ARRAY_SIZE(ab8500_charge_output_curr_map) - 1;
105862306a36Sopenharmony_ci	if (curr_ua == ab8500_charge_output_curr_map[i])
105962306a36Sopenharmony_ci		return i;
106062306a36Sopenharmony_ci	else
106162306a36Sopenharmony_ci		return -1;
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_cistatic int ab8500_vbus_in_curr_to_regval(struct ab8500_charger *di, int curr_ua)
106562306a36Sopenharmony_ci{
106662306a36Sopenharmony_ci	int i;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	if (curr_ua < ab8500_charge_input_curr_map[0])
106962306a36Sopenharmony_ci		return 0;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ab8500_charge_input_curr_map); i++) {
107262306a36Sopenharmony_ci		if (curr_ua < ab8500_charge_input_curr_map[i])
107362306a36Sopenharmony_ci			return i - 1;
107462306a36Sopenharmony_ci	}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	/* If not last element, return error */
107762306a36Sopenharmony_ci	i =  ARRAY_SIZE(ab8500_charge_input_curr_map) - 1;
107862306a36Sopenharmony_ci	if (curr_ua == ab8500_charge_input_curr_map[i])
107962306a36Sopenharmony_ci		return i;
108062306a36Sopenharmony_ci	else
108162306a36Sopenharmony_ci		return -1;
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci/**
108562306a36Sopenharmony_ci * ab8500_charger_get_usb_cur() - get usb current
108662306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
108762306a36Sopenharmony_ci *
108862306a36Sopenharmony_ci * The usb stack provides the maximum current that can be drawn from
108962306a36Sopenharmony_ci * the standard usb host. This will be in uA.
109062306a36Sopenharmony_ci * This function converts current in uA to a value that can be written
109162306a36Sopenharmony_ci * to the register. Returns -1 if charging is not allowed
109262306a36Sopenharmony_ci */
109362306a36Sopenharmony_cistatic int ab8500_charger_get_usb_cur(struct ab8500_charger *di)
109462306a36Sopenharmony_ci{
109562306a36Sopenharmony_ci	int ret = 0;
109662306a36Sopenharmony_ci	switch (di->usb_state.usb_current_ua) {
109762306a36Sopenharmony_ci	case 100000:
109862306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P09;
109962306a36Sopenharmony_ci		break;
110062306a36Sopenharmony_ci	case 200000:
110162306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P19;
110262306a36Sopenharmony_ci		break;
110362306a36Sopenharmony_ci	case 300000:
110462306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P29;
110562306a36Sopenharmony_ci		break;
110662306a36Sopenharmony_ci	case 400000:
110762306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P38;
110862306a36Sopenharmony_ci		break;
110962306a36Sopenharmony_ci	case 500000:
111062306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5;
111162306a36Sopenharmony_ci		break;
111262306a36Sopenharmony_ci	default:
111362306a36Sopenharmony_ci		di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P05;
111462306a36Sopenharmony_ci		ret = -EPERM;
111562306a36Sopenharmony_ci		break;
111662306a36Sopenharmony_ci	}
111762306a36Sopenharmony_ci	di->max_usb_in_curr.set_max_ua = di->max_usb_in_curr.usb_type_max_ua;
111862306a36Sopenharmony_ci	return ret;
111962306a36Sopenharmony_ci}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci/**
112262306a36Sopenharmony_ci * ab8500_charger_check_continue_stepping() - Check to allow stepping
112362306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
112462306a36Sopenharmony_ci * @reg:	select what charger register to check
112562306a36Sopenharmony_ci *
112662306a36Sopenharmony_ci * Check if current stepping should be allowed to continue.
112762306a36Sopenharmony_ci * Checks if charger source has not collapsed. If it has, further stepping
112862306a36Sopenharmony_ci * is not allowed.
112962306a36Sopenharmony_ci */
113062306a36Sopenharmony_cistatic bool ab8500_charger_check_continue_stepping(struct ab8500_charger *di,
113162306a36Sopenharmony_ci						   int reg)
113262306a36Sopenharmony_ci{
113362306a36Sopenharmony_ci	if (reg == AB8500_USBCH_IPT_CRNTLVL_REG)
113462306a36Sopenharmony_ci		return !di->flags.vbus_drop_end;
113562306a36Sopenharmony_ci	else
113662306a36Sopenharmony_ci		return true;
113762306a36Sopenharmony_ci}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci/**
114062306a36Sopenharmony_ci * ab8500_charger_set_current() - set charger current
114162306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
114262306a36Sopenharmony_ci * @ich_ua:	charger current, in uA
114362306a36Sopenharmony_ci * @reg:	select what charger register to set
114462306a36Sopenharmony_ci *
114562306a36Sopenharmony_ci * Set charger current.
114662306a36Sopenharmony_ci * There is no state machine in the AB to step up/down the charger
114762306a36Sopenharmony_ci * current to avoid dips and spikes on MAIN, VBUS and VBAT when
114862306a36Sopenharmony_ci * charging is started. Instead we need to implement
114962306a36Sopenharmony_ci * this charger current step-up/down here.
115062306a36Sopenharmony_ci * Returns error code in case of failure else 0(on success)
115162306a36Sopenharmony_ci */
115262306a36Sopenharmony_cistatic int ab8500_charger_set_current(struct ab8500_charger *di,
115362306a36Sopenharmony_ci	int ich_ua, int reg)
115462306a36Sopenharmony_ci{
115562306a36Sopenharmony_ci	int ret = 0;
115662306a36Sopenharmony_ci	int curr_index, prev_curr_index, shift_value, i;
115762306a36Sopenharmony_ci	u8 reg_value;
115862306a36Sopenharmony_ci	u32 step_udelay;
115962306a36Sopenharmony_ci	bool no_stepping = false;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	atomic_inc(&di->current_stepping_sessions);
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
116462306a36Sopenharmony_ci		reg, &reg_value);
116562306a36Sopenharmony_ci	if (ret < 0) {
116662306a36Sopenharmony_ci		dev_err(di->dev, "%s read failed\n", __func__);
116762306a36Sopenharmony_ci		goto exit_set_current;
116862306a36Sopenharmony_ci	}
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	switch (reg) {
117162306a36Sopenharmony_ci	case AB8500_MCH_IPT_CURLVL_REG:
117262306a36Sopenharmony_ci		shift_value = MAIN_CH_INPUT_CURR_SHIFT;
117362306a36Sopenharmony_ci		prev_curr_index = (reg_value >> shift_value);
117462306a36Sopenharmony_ci		curr_index = ab8500_current_to_regval(di, ich_ua);
117562306a36Sopenharmony_ci		step_udelay = STEP_UDELAY;
117662306a36Sopenharmony_ci		if (!di->ac.charger_connected)
117762306a36Sopenharmony_ci			no_stepping = true;
117862306a36Sopenharmony_ci		break;
117962306a36Sopenharmony_ci	case AB8500_USBCH_IPT_CRNTLVL_REG:
118062306a36Sopenharmony_ci		shift_value = VBUS_IN_CURR_LIM_SHIFT;
118162306a36Sopenharmony_ci		prev_curr_index = (reg_value >> shift_value);
118262306a36Sopenharmony_ci		curr_index = ab8500_vbus_in_curr_to_regval(di, ich_ua);
118362306a36Sopenharmony_ci		step_udelay = STEP_UDELAY * 100;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci		if (!di->usb.charger_connected)
118662306a36Sopenharmony_ci			no_stepping = true;
118762306a36Sopenharmony_ci		break;
118862306a36Sopenharmony_ci	case AB8500_CH_OPT_CRNTLVL_REG:
118962306a36Sopenharmony_ci		shift_value = 0;
119062306a36Sopenharmony_ci		prev_curr_index = (reg_value >> shift_value);
119162306a36Sopenharmony_ci		curr_index = ab8500_current_to_regval(di, ich_ua);
119262306a36Sopenharmony_ci		step_udelay = STEP_UDELAY;
119362306a36Sopenharmony_ci		if (curr_index && (curr_index - prev_curr_index) > 1)
119462306a36Sopenharmony_ci			step_udelay *= 100;
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci		if (!di->usb.charger_connected && !di->ac.charger_connected)
119762306a36Sopenharmony_ci			no_stepping = true;
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci		break;
120062306a36Sopenharmony_ci	default:
120162306a36Sopenharmony_ci		dev_err(di->dev, "%s current register not valid\n", __func__);
120262306a36Sopenharmony_ci		ret = -ENXIO;
120362306a36Sopenharmony_ci		goto exit_set_current;
120462306a36Sopenharmony_ci	}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	if (curr_index < 0) {
120762306a36Sopenharmony_ci		dev_err(di->dev, "requested current limit out-of-range\n");
120862306a36Sopenharmony_ci		ret = -ENXIO;
120962306a36Sopenharmony_ci		goto exit_set_current;
121062306a36Sopenharmony_ci	}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	/* only update current if it's been changed */
121362306a36Sopenharmony_ci	if (prev_curr_index == curr_index) {
121462306a36Sopenharmony_ci		dev_dbg(di->dev, "%s current not changed for reg: 0x%02x\n",
121562306a36Sopenharmony_ci			__func__, reg);
121662306a36Sopenharmony_ci		ret = 0;
121762306a36Sopenharmony_ci		goto exit_set_current;
121862306a36Sopenharmony_ci	}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	dev_dbg(di->dev, "%s set charger current: %d uA for reg: 0x%02x\n",
122162306a36Sopenharmony_ci		__func__, ich_ua, reg);
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	if (no_stepping) {
122462306a36Sopenharmony_ci		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
122562306a36Sopenharmony_ci					reg, (u8)curr_index << shift_value);
122662306a36Sopenharmony_ci		if (ret)
122762306a36Sopenharmony_ci			dev_err(di->dev, "%s write failed\n", __func__);
122862306a36Sopenharmony_ci	} else if (prev_curr_index > curr_index) {
122962306a36Sopenharmony_ci		for (i = prev_curr_index - 1; i >= curr_index; i--) {
123062306a36Sopenharmony_ci			dev_dbg(di->dev, "curr change_1 to: %x for 0x%02x\n",
123162306a36Sopenharmony_ci				(u8) i << shift_value, reg);
123262306a36Sopenharmony_ci			ret = abx500_set_register_interruptible(di->dev,
123362306a36Sopenharmony_ci				AB8500_CHARGER, reg, (u8)i << shift_value);
123462306a36Sopenharmony_ci			if (ret) {
123562306a36Sopenharmony_ci				dev_err(di->dev, "%s write failed\n", __func__);
123662306a36Sopenharmony_ci				goto exit_set_current;
123762306a36Sopenharmony_ci			}
123862306a36Sopenharmony_ci			if (i != curr_index)
123962306a36Sopenharmony_ci				usleep_range(step_udelay, step_udelay * 2);
124062306a36Sopenharmony_ci		}
124162306a36Sopenharmony_ci	} else {
124262306a36Sopenharmony_ci		bool allow = true;
124362306a36Sopenharmony_ci		for (i = prev_curr_index + 1; i <= curr_index && allow; i++) {
124462306a36Sopenharmony_ci			dev_dbg(di->dev, "curr change_2 to: %x for 0x%02x\n",
124562306a36Sopenharmony_ci				(u8)i << shift_value, reg);
124662306a36Sopenharmony_ci			ret = abx500_set_register_interruptible(di->dev,
124762306a36Sopenharmony_ci				AB8500_CHARGER, reg, (u8)i << shift_value);
124862306a36Sopenharmony_ci			if (ret) {
124962306a36Sopenharmony_ci				dev_err(di->dev, "%s write failed\n", __func__);
125062306a36Sopenharmony_ci				goto exit_set_current;
125162306a36Sopenharmony_ci			}
125262306a36Sopenharmony_ci			if (i != curr_index)
125362306a36Sopenharmony_ci				usleep_range(step_udelay, step_udelay * 2);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci			allow = ab8500_charger_check_continue_stepping(di, reg);
125662306a36Sopenharmony_ci		}
125762306a36Sopenharmony_ci	}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ciexit_set_current:
126062306a36Sopenharmony_ci	atomic_dec(&di->current_stepping_sessions);
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	return ret;
126362306a36Sopenharmony_ci}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci/**
126662306a36Sopenharmony_ci * ab8500_charger_set_vbus_in_curr() - set VBUS input current limit
126762306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
126862306a36Sopenharmony_ci * @ich_in_ua:	charger input current limit in microampere
126962306a36Sopenharmony_ci *
127062306a36Sopenharmony_ci * Sets the current that can be drawn from the USB host
127162306a36Sopenharmony_ci * Returns error code in case of failure else 0(on success)
127262306a36Sopenharmony_ci */
127362306a36Sopenharmony_cistatic int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di,
127462306a36Sopenharmony_ci		int ich_in_ua)
127562306a36Sopenharmony_ci{
127662306a36Sopenharmony_ci	int min_value;
127762306a36Sopenharmony_ci	int ret;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	/* We should always use to lowest current limit */
128062306a36Sopenharmony_ci	min_value = min(di->bm->chg_params->usb_curr_max_ua, ich_in_ua);
128162306a36Sopenharmony_ci	if (di->max_usb_in_curr.set_max_ua > 0)
128262306a36Sopenharmony_ci		min_value = min(di->max_usb_in_curr.set_max_ua, min_value);
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	if (di->usb_state.usb_current_ua >= 0)
128562306a36Sopenharmony_ci		min_value = min(di->usb_state.usb_current_ua, min_value);
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	switch (min_value) {
128862306a36Sopenharmony_ci	case 100000:
128962306a36Sopenharmony_ci		if (di->vbat < VBAT_TRESH_IP_CUR_RED)
129062306a36Sopenharmony_ci			min_value = USB_CH_IP_CUR_LVL_0P05;
129162306a36Sopenharmony_ci		break;
129262306a36Sopenharmony_ci	case 500000:
129362306a36Sopenharmony_ci		if (di->vbat < VBAT_TRESH_IP_CUR_RED)
129462306a36Sopenharmony_ci			min_value = USB_CH_IP_CUR_LVL_0P45;
129562306a36Sopenharmony_ci		break;
129662306a36Sopenharmony_ci	default:
129762306a36Sopenharmony_ci		break;
129862306a36Sopenharmony_ci	}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	dev_info(di->dev, "VBUS input current limit set to %d uA\n", min_value);
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	mutex_lock(&di->usb_ipt_crnt_lock);
130362306a36Sopenharmony_ci	ret = ab8500_charger_set_current(di, min_value,
130462306a36Sopenharmony_ci		AB8500_USBCH_IPT_CRNTLVL_REG);
130562306a36Sopenharmony_ci	mutex_unlock(&di->usb_ipt_crnt_lock);
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	return ret;
130862306a36Sopenharmony_ci}
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci/**
131162306a36Sopenharmony_ci * ab8500_charger_set_main_in_curr() - set main charger input current
131262306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
131362306a36Sopenharmony_ci * @ich_in_ua:	input charger current, in uA
131462306a36Sopenharmony_ci *
131562306a36Sopenharmony_ci * Set main charger input current.
131662306a36Sopenharmony_ci * Returns error code in case of failure else 0(on success)
131762306a36Sopenharmony_ci */
131862306a36Sopenharmony_cistatic int ab8500_charger_set_main_in_curr(struct ab8500_charger *di,
131962306a36Sopenharmony_ci	int ich_in_ua)
132062306a36Sopenharmony_ci{
132162306a36Sopenharmony_ci	return ab8500_charger_set_current(di, ich_in_ua,
132262306a36Sopenharmony_ci		AB8500_MCH_IPT_CURLVL_REG);
132362306a36Sopenharmony_ci}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci/**
132662306a36Sopenharmony_ci * ab8500_charger_set_output_curr() - set charger output current
132762306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
132862306a36Sopenharmony_ci * @ich_out_ua:	output charger current, in uA
132962306a36Sopenharmony_ci *
133062306a36Sopenharmony_ci * Set charger output current.
133162306a36Sopenharmony_ci * Returns error code in case of failure else 0(on success)
133262306a36Sopenharmony_ci */
133362306a36Sopenharmony_cistatic int ab8500_charger_set_output_curr(struct ab8500_charger *di,
133462306a36Sopenharmony_ci	int ich_out_ua)
133562306a36Sopenharmony_ci{
133662306a36Sopenharmony_ci	return ab8500_charger_set_current(di, ich_out_ua,
133762306a36Sopenharmony_ci		AB8500_CH_OPT_CRNTLVL_REG);
133862306a36Sopenharmony_ci}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci/**
134162306a36Sopenharmony_ci * ab8500_charger_led_en() - turn on/off chargign led
134262306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
134362306a36Sopenharmony_ci * @on:		flag to turn on/off the chargign led
134462306a36Sopenharmony_ci *
134562306a36Sopenharmony_ci * Power ON/OFF charging LED indication
134662306a36Sopenharmony_ci * Returns error code in case of failure else 0(on success)
134762306a36Sopenharmony_ci */
134862306a36Sopenharmony_cistatic int ab8500_charger_led_en(struct ab8500_charger *di, int on)
134962306a36Sopenharmony_ci{
135062306a36Sopenharmony_ci	int ret;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	if (on) {
135362306a36Sopenharmony_ci		/* Power ON charging LED indicator, set LED current to 5mA */
135462306a36Sopenharmony_ci		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
135562306a36Sopenharmony_ci			AB8500_LED_INDICATOR_PWM_CTRL,
135662306a36Sopenharmony_ci			(LED_IND_CUR_5MA | LED_INDICATOR_PWM_ENA));
135762306a36Sopenharmony_ci		if (ret) {
135862306a36Sopenharmony_ci			dev_err(di->dev, "Power ON LED failed\n");
135962306a36Sopenharmony_ci			return ret;
136062306a36Sopenharmony_ci		}
136162306a36Sopenharmony_ci		/* LED indicator PWM duty cycle 252/256 */
136262306a36Sopenharmony_ci		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
136362306a36Sopenharmony_ci			AB8500_LED_INDICATOR_PWM_DUTY,
136462306a36Sopenharmony_ci			LED_INDICATOR_PWM_DUTY_252_256);
136562306a36Sopenharmony_ci		if (ret) {
136662306a36Sopenharmony_ci			dev_err(di->dev, "Set LED PWM duty cycle failed\n");
136762306a36Sopenharmony_ci			return ret;
136862306a36Sopenharmony_ci		}
136962306a36Sopenharmony_ci	} else {
137062306a36Sopenharmony_ci		/* Power off charging LED indicator */
137162306a36Sopenharmony_ci		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
137262306a36Sopenharmony_ci			AB8500_LED_INDICATOR_PWM_CTRL,
137362306a36Sopenharmony_ci			LED_INDICATOR_PWM_DIS);
137462306a36Sopenharmony_ci		if (ret) {
137562306a36Sopenharmony_ci			dev_err(di->dev, "Power-off LED failed\n");
137662306a36Sopenharmony_ci			return ret;
137762306a36Sopenharmony_ci		}
137862306a36Sopenharmony_ci	}
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	return ret;
138162306a36Sopenharmony_ci}
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci/**
138462306a36Sopenharmony_ci * ab8500_charger_ac_en() - enable or disable ac charging
138562306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
138662306a36Sopenharmony_ci * @enable:	enable/disable flag
138762306a36Sopenharmony_ci * @vset_uv:	charging voltage in microvolt
138862306a36Sopenharmony_ci * @iset_ua:	charging current in microampere
138962306a36Sopenharmony_ci *
139062306a36Sopenharmony_ci * Enable/Disable AC/Mains charging and turns on/off the charging led
139162306a36Sopenharmony_ci * respectively.
139262306a36Sopenharmony_ci **/
139362306a36Sopenharmony_cistatic int ab8500_charger_ac_en(struct ux500_charger *charger,
139462306a36Sopenharmony_ci	int enable, int vset_uv, int iset_ua)
139562306a36Sopenharmony_ci{
139662306a36Sopenharmony_ci	int ret;
139762306a36Sopenharmony_ci	int volt_index;
139862306a36Sopenharmony_ci	int curr_index;
139962306a36Sopenharmony_ci	int input_curr_index;
140062306a36Sopenharmony_ci	u8 overshoot = 0;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	struct ab8500_charger *di = to_ab8500_charger_ac_device_info(charger);
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	if (enable) {
140562306a36Sopenharmony_ci		/* Check if AC is connected */
140662306a36Sopenharmony_ci		if (!di->ac.charger_connected) {
140762306a36Sopenharmony_ci			dev_err(di->dev, "AC charger not connected\n");
140862306a36Sopenharmony_ci			return -ENXIO;
140962306a36Sopenharmony_ci		}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci		/* Enable AC charging */
141262306a36Sopenharmony_ci		dev_dbg(di->dev, "Enable AC: %duV %duA\n", vset_uv, iset_ua);
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci		/*
141562306a36Sopenharmony_ci		 * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts
141662306a36Sopenharmony_ci		 * will be triggered every time we enable the VDD ADC supply.
141762306a36Sopenharmony_ci		 * This will turn off charging for a short while.
141862306a36Sopenharmony_ci		 * It can be avoided by having the supply on when
141962306a36Sopenharmony_ci		 * there is a charger enabled. Normally the VDD ADC supply
142062306a36Sopenharmony_ci		 * is enabled every time a GPADC conversion is triggered.
142162306a36Sopenharmony_ci		 * We will force it to be enabled from this driver to have
142262306a36Sopenharmony_ci		 * the GPADC module independent of the AB8500 chargers
142362306a36Sopenharmony_ci		 */
142462306a36Sopenharmony_ci		if (!di->vddadc_en_ac) {
142562306a36Sopenharmony_ci			ret = regulator_enable(di->regu);
142662306a36Sopenharmony_ci			if (ret)
142762306a36Sopenharmony_ci				dev_warn(di->dev,
142862306a36Sopenharmony_ci					"Failed to enable regulator\n");
142962306a36Sopenharmony_ci			else
143062306a36Sopenharmony_ci				di->vddadc_en_ac = true;
143162306a36Sopenharmony_ci		}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci		/* Check if the requested voltage or current is valid */
143462306a36Sopenharmony_ci		volt_index = ab8500_voltage_to_regval(vset_uv);
143562306a36Sopenharmony_ci		curr_index = ab8500_current_to_regval(di, iset_ua);
143662306a36Sopenharmony_ci		input_curr_index = ab8500_current_to_regval(di,
143762306a36Sopenharmony_ci			di->bm->chg_params->ac_curr_max_ua);
143862306a36Sopenharmony_ci		if (volt_index < 0 || curr_index < 0 || input_curr_index < 0) {
143962306a36Sopenharmony_ci			dev_err(di->dev,
144062306a36Sopenharmony_ci				"Charger voltage or current too high, "
144162306a36Sopenharmony_ci				"charging not started\n");
144262306a36Sopenharmony_ci			return -ENXIO;
144362306a36Sopenharmony_ci		}
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci		/* ChVoltLevel: maximum battery charging voltage */
144662306a36Sopenharmony_ci		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
144762306a36Sopenharmony_ci			AB8500_CH_VOLT_LVL_REG, (u8) volt_index);
144862306a36Sopenharmony_ci		if (ret) {
144962306a36Sopenharmony_ci			dev_err(di->dev, "%s write failed\n", __func__);
145062306a36Sopenharmony_ci			return ret;
145162306a36Sopenharmony_ci		}
145262306a36Sopenharmony_ci		/* MainChInputCurr: current that can be drawn from the charger*/
145362306a36Sopenharmony_ci		ret = ab8500_charger_set_main_in_curr(di,
145462306a36Sopenharmony_ci			di->bm->chg_params->ac_curr_max_ua);
145562306a36Sopenharmony_ci		if (ret) {
145662306a36Sopenharmony_ci			dev_err(di->dev, "%s Failed to set MainChInputCurr\n",
145762306a36Sopenharmony_ci				__func__);
145862306a36Sopenharmony_ci			return ret;
145962306a36Sopenharmony_ci		}
146062306a36Sopenharmony_ci		/* ChOutputCurentLevel: protected output current */
146162306a36Sopenharmony_ci		ret = ab8500_charger_set_output_curr(di, iset_ua);
146262306a36Sopenharmony_ci		if (ret) {
146362306a36Sopenharmony_ci			dev_err(di->dev, "%s "
146462306a36Sopenharmony_ci				"Failed to set ChOutputCurentLevel\n",
146562306a36Sopenharmony_ci				__func__);
146662306a36Sopenharmony_ci			return ret;
146762306a36Sopenharmony_ci		}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci		/* Check if VBAT overshoot control should be enabled */
147062306a36Sopenharmony_ci		if (!di->bm->enable_overshoot)
147162306a36Sopenharmony_ci			overshoot = MAIN_CH_NO_OVERSHOOT_ENA_N;
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci		/* Enable Main Charger */
147462306a36Sopenharmony_ci		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
147562306a36Sopenharmony_ci			AB8500_MCH_CTRL1, MAIN_CH_ENA | overshoot);
147662306a36Sopenharmony_ci		if (ret) {
147762306a36Sopenharmony_ci			dev_err(di->dev, "%s write failed\n", __func__);
147862306a36Sopenharmony_ci			return ret;
147962306a36Sopenharmony_ci		}
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci		/* Power on charging LED indication */
148262306a36Sopenharmony_ci		ret = ab8500_charger_led_en(di, true);
148362306a36Sopenharmony_ci		if (ret < 0)
148462306a36Sopenharmony_ci			dev_err(di->dev, "failed to enable LED\n");
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci		di->ac.charger_online = 1;
148762306a36Sopenharmony_ci	} else {
148862306a36Sopenharmony_ci		/* Disable AC charging */
148962306a36Sopenharmony_ci		if (is_ab8500_1p1_or_earlier(di->parent)) {
149062306a36Sopenharmony_ci			/*
149162306a36Sopenharmony_ci			 * For ABB revision 1.0 and 1.1 there is a bug in the
149262306a36Sopenharmony_ci			 * watchdog logic. That means we have to continuously
149362306a36Sopenharmony_ci			 * kick the charger watchdog even when no charger is
149462306a36Sopenharmony_ci			 * connected. This is only valid once the AC charger
149562306a36Sopenharmony_ci			 * has been enabled. This is a bug that is not handled
149662306a36Sopenharmony_ci			 * by the algorithm and the watchdog have to be kicked
149762306a36Sopenharmony_ci			 * by the charger driver when the AC charger
149862306a36Sopenharmony_ci			 * is disabled
149962306a36Sopenharmony_ci			 */
150062306a36Sopenharmony_ci			if (di->ac_conn) {
150162306a36Sopenharmony_ci				queue_delayed_work(di->charger_wq,
150262306a36Sopenharmony_ci					&di->kick_wd_work,
150362306a36Sopenharmony_ci					round_jiffies(WD_KICK_INTERVAL));
150462306a36Sopenharmony_ci			}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci			/*
150762306a36Sopenharmony_ci			 * We can't turn off charging completely
150862306a36Sopenharmony_ci			 * due to a bug in AB8500 cut1.
150962306a36Sopenharmony_ci			 * If we do, charging will not start again.
151062306a36Sopenharmony_ci			 * That is why we set the lowest voltage
151162306a36Sopenharmony_ci			 * and current possible
151262306a36Sopenharmony_ci			 */
151362306a36Sopenharmony_ci			ret = abx500_set_register_interruptible(di->dev,
151462306a36Sopenharmony_ci				AB8500_CHARGER,
151562306a36Sopenharmony_ci				AB8500_CH_VOLT_LVL_REG, CH_VOL_LVL_3P5);
151662306a36Sopenharmony_ci			if (ret) {
151762306a36Sopenharmony_ci				dev_err(di->dev,
151862306a36Sopenharmony_ci					"%s write failed\n", __func__);
151962306a36Sopenharmony_ci				return ret;
152062306a36Sopenharmony_ci			}
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci			ret = ab8500_charger_set_output_curr(di, 0);
152362306a36Sopenharmony_ci			if (ret) {
152462306a36Sopenharmony_ci				dev_err(di->dev, "%s "
152562306a36Sopenharmony_ci					"Failed to set ChOutputCurentLevel\n",
152662306a36Sopenharmony_ci					__func__);
152762306a36Sopenharmony_ci				return ret;
152862306a36Sopenharmony_ci			}
152962306a36Sopenharmony_ci		} else {
153062306a36Sopenharmony_ci			ret = abx500_set_register_interruptible(di->dev,
153162306a36Sopenharmony_ci				AB8500_CHARGER,
153262306a36Sopenharmony_ci				AB8500_MCH_CTRL1, 0);
153362306a36Sopenharmony_ci			if (ret) {
153462306a36Sopenharmony_ci				dev_err(di->dev,
153562306a36Sopenharmony_ci					"%s write failed\n", __func__);
153662306a36Sopenharmony_ci				return ret;
153762306a36Sopenharmony_ci			}
153862306a36Sopenharmony_ci		}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci		ret = ab8500_charger_led_en(di, false);
154162306a36Sopenharmony_ci		if (ret < 0)
154262306a36Sopenharmony_ci			dev_err(di->dev, "failed to disable LED\n");
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci		di->ac.charger_online = 0;
154562306a36Sopenharmony_ci		di->ac.wd_expired = false;
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci		/* Disable regulator if enabled */
154862306a36Sopenharmony_ci		if (di->vddadc_en_ac) {
154962306a36Sopenharmony_ci			regulator_disable(di->regu);
155062306a36Sopenharmony_ci			di->vddadc_en_ac = false;
155162306a36Sopenharmony_ci		}
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci		dev_dbg(di->dev, "%s Disabled AC charging\n", __func__);
155462306a36Sopenharmony_ci	}
155562306a36Sopenharmony_ci	ab8500_power_supply_changed(di, di->ac_chg.psy);
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	return ret;
155862306a36Sopenharmony_ci}
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci/**
156162306a36Sopenharmony_ci * ab8500_charger_usb_en() - enable usb charging
156262306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
156362306a36Sopenharmony_ci * @enable:	enable/disable flag
156462306a36Sopenharmony_ci * @vset_uv:	charging voltage in microvolt
156562306a36Sopenharmony_ci * @ich_out_ua:	charger output current in microampere
156662306a36Sopenharmony_ci *
156762306a36Sopenharmony_ci * Enable/Disable USB charging and turns on/off the charging led respectively.
156862306a36Sopenharmony_ci * Returns error code in case of failure else 0(on success)
156962306a36Sopenharmony_ci */
157062306a36Sopenharmony_cistatic int ab8500_charger_usb_en(struct ux500_charger *charger,
157162306a36Sopenharmony_ci	int enable, int vset_uv, int ich_out_ua)
157262306a36Sopenharmony_ci{
157362306a36Sopenharmony_ci	int ret;
157462306a36Sopenharmony_ci	int volt_index;
157562306a36Sopenharmony_ci	int curr_index;
157662306a36Sopenharmony_ci	u8 overshoot = 0;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	struct ab8500_charger *di = to_ab8500_charger_usb_device_info(charger);
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	if (enable) {
158162306a36Sopenharmony_ci		/* Check if USB is connected */
158262306a36Sopenharmony_ci		if (!di->usb.charger_connected) {
158362306a36Sopenharmony_ci			dev_err(di->dev, "USB charger not connected\n");
158462306a36Sopenharmony_ci			return -ENXIO;
158562306a36Sopenharmony_ci		}
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci		/*
158862306a36Sopenharmony_ci		 * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts
158962306a36Sopenharmony_ci		 * will be triggered every time we enable the VDD ADC supply.
159062306a36Sopenharmony_ci		 * This will turn off charging for a short while.
159162306a36Sopenharmony_ci		 * It can be avoided by having the supply on when
159262306a36Sopenharmony_ci		 * there is a charger enabled. Normally the VDD ADC supply
159362306a36Sopenharmony_ci		 * is enabled every time a GPADC conversion is triggered.
159462306a36Sopenharmony_ci		 * We will force it to be enabled from this driver to have
159562306a36Sopenharmony_ci		 * the GPADC module independent of the AB8500 chargers
159662306a36Sopenharmony_ci		 */
159762306a36Sopenharmony_ci		if (!di->vddadc_en_usb) {
159862306a36Sopenharmony_ci			ret = regulator_enable(di->regu);
159962306a36Sopenharmony_ci			if (ret)
160062306a36Sopenharmony_ci				dev_warn(di->dev,
160162306a36Sopenharmony_ci					"Failed to enable regulator\n");
160262306a36Sopenharmony_ci			else
160362306a36Sopenharmony_ci				di->vddadc_en_usb = true;
160462306a36Sopenharmony_ci		}
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci		/* Enable USB charging */
160762306a36Sopenharmony_ci		dev_dbg(di->dev, "Enable USB: %d uV %d uA\n", vset_uv, ich_out_ua);
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci		/* Check if the requested voltage or current is valid */
161062306a36Sopenharmony_ci		volt_index = ab8500_voltage_to_regval(vset_uv);
161162306a36Sopenharmony_ci		curr_index = ab8500_current_to_regval(di, ich_out_ua);
161262306a36Sopenharmony_ci		if (volt_index < 0 || curr_index < 0) {
161362306a36Sopenharmony_ci			dev_err(di->dev,
161462306a36Sopenharmony_ci				"Charger voltage or current too high, "
161562306a36Sopenharmony_ci				"charging not started\n");
161662306a36Sopenharmony_ci			return -ENXIO;
161762306a36Sopenharmony_ci		}
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci		/*
162062306a36Sopenharmony_ci		 * ChVoltLevel: max voltage up to which battery can be
162162306a36Sopenharmony_ci		 * charged
162262306a36Sopenharmony_ci		 */
162362306a36Sopenharmony_ci		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
162462306a36Sopenharmony_ci			AB8500_CH_VOLT_LVL_REG, (u8) volt_index);
162562306a36Sopenharmony_ci		if (ret) {
162662306a36Sopenharmony_ci			dev_err(di->dev, "%s write failed\n", __func__);
162762306a36Sopenharmony_ci			return ret;
162862306a36Sopenharmony_ci		}
162962306a36Sopenharmony_ci		/* Check if VBAT overshoot control should be enabled */
163062306a36Sopenharmony_ci		if (!di->bm->enable_overshoot)
163162306a36Sopenharmony_ci			overshoot = USB_CHG_NO_OVERSHOOT_ENA_N;
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci		/* Enable USB Charger */
163462306a36Sopenharmony_ci		dev_dbg(di->dev,
163562306a36Sopenharmony_ci			"Enabling USB with write to AB8500_USBCH_CTRL1_REG\n");
163662306a36Sopenharmony_ci		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
163762306a36Sopenharmony_ci			AB8500_USBCH_CTRL1_REG, USB_CH_ENA | overshoot);
163862306a36Sopenharmony_ci		if (ret) {
163962306a36Sopenharmony_ci			dev_err(di->dev, "%s write failed\n", __func__);
164062306a36Sopenharmony_ci			return ret;
164162306a36Sopenharmony_ci		}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci		/* If success power on charging LED indication */
164462306a36Sopenharmony_ci		ret = ab8500_charger_led_en(di, true);
164562306a36Sopenharmony_ci		if (ret < 0)
164662306a36Sopenharmony_ci			dev_err(di->dev, "failed to enable LED\n");
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci		di->usb.charger_online = 1;
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci		/* USBChInputCurr: current that can be drawn from the usb */
165162306a36Sopenharmony_ci		ret = ab8500_charger_set_vbus_in_curr(di,
165262306a36Sopenharmony_ci					di->max_usb_in_curr.usb_type_max_ua);
165362306a36Sopenharmony_ci		if (ret) {
165462306a36Sopenharmony_ci			dev_err(di->dev, "setting USBChInputCurr failed\n");
165562306a36Sopenharmony_ci			return ret;
165662306a36Sopenharmony_ci		}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci		/* ChOutputCurentLevel: protected output current */
165962306a36Sopenharmony_ci		ret = ab8500_charger_set_output_curr(di, ich_out_ua);
166062306a36Sopenharmony_ci		if (ret) {
166162306a36Sopenharmony_ci			dev_err(di->dev, "%s "
166262306a36Sopenharmony_ci				"Failed to set ChOutputCurentLevel\n",
166362306a36Sopenharmony_ci				__func__);
166462306a36Sopenharmony_ci			return ret;
166562306a36Sopenharmony_ci		}
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci		queue_delayed_work(di->charger_wq, &di->check_vbat_work, HZ);
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	} else {
167062306a36Sopenharmony_ci		/* Disable USB charging */
167162306a36Sopenharmony_ci		dev_dbg(di->dev, "%s Disabled USB charging\n", __func__);
167262306a36Sopenharmony_ci		ret = abx500_set_register_interruptible(di->dev,
167362306a36Sopenharmony_ci			AB8500_CHARGER,
167462306a36Sopenharmony_ci			AB8500_USBCH_CTRL1_REG, 0);
167562306a36Sopenharmony_ci		if (ret) {
167662306a36Sopenharmony_ci			dev_err(di->dev,
167762306a36Sopenharmony_ci				"%s write failed\n", __func__);
167862306a36Sopenharmony_ci			return ret;
167962306a36Sopenharmony_ci		}
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci		ret = ab8500_charger_led_en(di, false);
168262306a36Sopenharmony_ci		if (ret < 0)
168362306a36Sopenharmony_ci			dev_err(di->dev, "failed to disable LED\n");
168462306a36Sopenharmony_ci		/* USBChInputCurr: current that can be drawn from the usb */
168562306a36Sopenharmony_ci		ret = ab8500_charger_set_vbus_in_curr(di, 0);
168662306a36Sopenharmony_ci		if (ret) {
168762306a36Sopenharmony_ci			dev_err(di->dev, "setting USBChInputCurr failed\n");
168862306a36Sopenharmony_ci			return ret;
168962306a36Sopenharmony_ci		}
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci		/* ChOutputCurentLevel: protected output current */
169262306a36Sopenharmony_ci		ret = ab8500_charger_set_output_curr(di, 0);
169362306a36Sopenharmony_ci		if (ret) {
169462306a36Sopenharmony_ci			dev_err(di->dev, "%s "
169562306a36Sopenharmony_ci				"Failed to reset ChOutputCurentLevel\n",
169662306a36Sopenharmony_ci				__func__);
169762306a36Sopenharmony_ci			return ret;
169862306a36Sopenharmony_ci		}
169962306a36Sopenharmony_ci		di->usb.charger_online = 0;
170062306a36Sopenharmony_ci		di->usb.wd_expired = false;
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci		/* Disable regulator if enabled */
170362306a36Sopenharmony_ci		if (di->vddadc_en_usb) {
170462306a36Sopenharmony_ci			regulator_disable(di->regu);
170562306a36Sopenharmony_ci			di->vddadc_en_usb = false;
170662306a36Sopenharmony_ci		}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci		dev_dbg(di->dev, "%s Disabled USB charging\n", __func__);
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci		/* Cancel any pending Vbat check work */
171162306a36Sopenharmony_ci		cancel_delayed_work(&di->check_vbat_work);
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	}
171462306a36Sopenharmony_ci	ab8500_power_supply_changed(di, di->usb_chg.psy);
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	return ret;
171762306a36Sopenharmony_ci}
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci/**
172062306a36Sopenharmony_ci * ab8500_charger_usb_check_enable() - enable usb charging
172162306a36Sopenharmony_ci * @charger:	pointer to the ux500_charger structure
172262306a36Sopenharmony_ci * @vset_uv:	charging voltage in microvolt
172362306a36Sopenharmony_ci * @iset_ua:	charger output current in microampere
172462306a36Sopenharmony_ci *
172562306a36Sopenharmony_ci * Check if the VBUS charger has been disconnected and reconnected without
172662306a36Sopenharmony_ci * AB8500 rising an interrupt. Returns 0 on success.
172762306a36Sopenharmony_ci */
172862306a36Sopenharmony_cistatic int ab8500_charger_usb_check_enable(struct ux500_charger *charger,
172962306a36Sopenharmony_ci	int vset_uv, int iset_ua)
173062306a36Sopenharmony_ci{
173162306a36Sopenharmony_ci	u8 usbch_ctrl1 = 0;
173262306a36Sopenharmony_ci	int ret = 0;
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci	struct ab8500_charger *di = to_ab8500_charger_usb_device_info(charger);
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	if (!di->usb.charger_connected)
173762306a36Sopenharmony_ci		return ret;
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
174062306a36Sopenharmony_ci				AB8500_USBCH_CTRL1_REG, &usbch_ctrl1);
174162306a36Sopenharmony_ci	if (ret < 0) {
174262306a36Sopenharmony_ci		dev_err(di->dev, "ab8500 read failed %d\n", __LINE__);
174362306a36Sopenharmony_ci		return ret;
174462306a36Sopenharmony_ci	}
174562306a36Sopenharmony_ci	dev_dbg(di->dev, "USB charger ctrl: 0x%02x\n", usbch_ctrl1);
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	if (!(usbch_ctrl1 & USB_CH_ENA)) {
174862306a36Sopenharmony_ci		dev_info(di->dev, "Charging has been disabled abnormally and will be re-enabled\n");
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci		ret = abx500_mask_and_set_register_interruptible(di->dev,
175162306a36Sopenharmony_ci					AB8500_CHARGER, AB8500_CHARGER_CTRL,
175262306a36Sopenharmony_ci					DROP_COUNT_RESET, DROP_COUNT_RESET);
175362306a36Sopenharmony_ci		if (ret < 0) {
175462306a36Sopenharmony_ci			dev_err(di->dev, "ab8500 write failed %d\n", __LINE__);
175562306a36Sopenharmony_ci			return ret;
175662306a36Sopenharmony_ci		}
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci		ret = ab8500_charger_usb_en(&di->usb_chg, true, vset_uv, iset_ua);
175962306a36Sopenharmony_ci		if (ret < 0) {
176062306a36Sopenharmony_ci			dev_err(di->dev, "Failed to enable VBUS charger %d\n",
176162306a36Sopenharmony_ci					__LINE__);
176262306a36Sopenharmony_ci			return ret;
176362306a36Sopenharmony_ci		}
176462306a36Sopenharmony_ci	}
176562306a36Sopenharmony_ci	return ret;
176662306a36Sopenharmony_ci}
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci/**
176962306a36Sopenharmony_ci * ab8500_charger_ac_check_enable() - enable usb charging
177062306a36Sopenharmony_ci * @charger:	pointer to the ux500_charger structure
177162306a36Sopenharmony_ci * @vset_uv:	charging voltage in microvolt
177262306a36Sopenharmony_ci * @iset_ua:	charger output current in micrompere
177362306a36Sopenharmony_ci *
177462306a36Sopenharmony_ci * Check if the AC charger has been disconnected and reconnected without
177562306a36Sopenharmony_ci * AB8500 rising an interrupt. Returns 0 on success.
177662306a36Sopenharmony_ci */
177762306a36Sopenharmony_cistatic int ab8500_charger_ac_check_enable(struct ux500_charger *charger,
177862306a36Sopenharmony_ci	int vset_uv, int iset_ua)
177962306a36Sopenharmony_ci{
178062306a36Sopenharmony_ci	u8 mainch_ctrl1 = 0;
178162306a36Sopenharmony_ci	int ret = 0;
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	struct ab8500_charger *di = to_ab8500_charger_ac_device_info(charger);
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	if (!di->ac.charger_connected)
178662306a36Sopenharmony_ci		return ret;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
178962306a36Sopenharmony_ci				AB8500_MCH_CTRL1, &mainch_ctrl1);
179062306a36Sopenharmony_ci	if (ret < 0) {
179162306a36Sopenharmony_ci		dev_err(di->dev, "ab8500 read failed %d\n", __LINE__);
179262306a36Sopenharmony_ci		return ret;
179362306a36Sopenharmony_ci	}
179462306a36Sopenharmony_ci	dev_dbg(di->dev, "AC charger ctrl: 0x%02x\n", mainch_ctrl1);
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	if (!(mainch_ctrl1 & MAIN_CH_ENA)) {
179762306a36Sopenharmony_ci		dev_info(di->dev, "Charging has been disabled abnormally and will be re-enabled\n");
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci		ret = abx500_mask_and_set_register_interruptible(di->dev,
180062306a36Sopenharmony_ci					AB8500_CHARGER, AB8500_CHARGER_CTRL,
180162306a36Sopenharmony_ci					DROP_COUNT_RESET, DROP_COUNT_RESET);
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci		if (ret < 0) {
180462306a36Sopenharmony_ci			dev_err(di->dev, "ab8500 write failed %d\n", __LINE__);
180562306a36Sopenharmony_ci			return ret;
180662306a36Sopenharmony_ci		}
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci		ret = ab8500_charger_ac_en(&di->usb_chg, true, vset_uv, iset_ua);
180962306a36Sopenharmony_ci		if (ret < 0) {
181062306a36Sopenharmony_ci			dev_err(di->dev, "failed to enable AC charger %d\n",
181162306a36Sopenharmony_ci				__LINE__);
181262306a36Sopenharmony_ci			return ret;
181362306a36Sopenharmony_ci		}
181462306a36Sopenharmony_ci	}
181562306a36Sopenharmony_ci	return ret;
181662306a36Sopenharmony_ci}
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci/**
181962306a36Sopenharmony_ci * ab8500_charger_watchdog_kick() - kick charger watchdog
182062306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
182162306a36Sopenharmony_ci *
182262306a36Sopenharmony_ci * Kick charger watchdog
182362306a36Sopenharmony_ci * Returns error code in case of failure else 0(on success)
182462306a36Sopenharmony_ci */
182562306a36Sopenharmony_cistatic int ab8500_charger_watchdog_kick(struct ux500_charger *charger)
182662306a36Sopenharmony_ci{
182762306a36Sopenharmony_ci	int ret;
182862306a36Sopenharmony_ci	struct ab8500_charger *di;
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	if (charger->psy->desc->type == POWER_SUPPLY_TYPE_MAINS)
183162306a36Sopenharmony_ci		di = to_ab8500_charger_ac_device_info(charger);
183262306a36Sopenharmony_ci	else if (charger->psy->desc->type == POWER_SUPPLY_TYPE_USB)
183362306a36Sopenharmony_ci		di = to_ab8500_charger_usb_device_info(charger);
183462306a36Sopenharmony_ci	else
183562306a36Sopenharmony_ci		return -ENXIO;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
183862306a36Sopenharmony_ci		AB8500_CHARG_WD_CTRL, CHARG_WD_KICK);
183962306a36Sopenharmony_ci	if (ret)
184062306a36Sopenharmony_ci		dev_err(di->dev, "Failed to kick WD!\n");
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	return ret;
184362306a36Sopenharmony_ci}
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci/**
184662306a36Sopenharmony_ci * ab8500_charger_update_charger_current() - update charger current
184762306a36Sopenharmony_ci * @charger:		pointer to the ab8500_charger structure
184862306a36Sopenharmony_ci * @ich_out_ua:		desired output current in microampere
184962306a36Sopenharmony_ci *
185062306a36Sopenharmony_ci * Update the charger output current for the specified charger
185162306a36Sopenharmony_ci * Returns error code in case of failure else 0(on success)
185262306a36Sopenharmony_ci */
185362306a36Sopenharmony_cistatic int ab8500_charger_update_charger_current(struct ux500_charger *charger,
185462306a36Sopenharmony_ci		int ich_out_ua)
185562306a36Sopenharmony_ci{
185662306a36Sopenharmony_ci	int ret;
185762306a36Sopenharmony_ci	struct ab8500_charger *di;
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	if (charger->psy->desc->type == POWER_SUPPLY_TYPE_MAINS)
186062306a36Sopenharmony_ci		di = to_ab8500_charger_ac_device_info(charger);
186162306a36Sopenharmony_ci	else if (charger->psy->desc->type == POWER_SUPPLY_TYPE_USB)
186262306a36Sopenharmony_ci		di = to_ab8500_charger_usb_device_info(charger);
186362306a36Sopenharmony_ci	else
186462306a36Sopenharmony_ci		return -ENXIO;
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	ret = ab8500_charger_set_output_curr(di, ich_out_ua);
186762306a36Sopenharmony_ci	if (ret) {
186862306a36Sopenharmony_ci		dev_err(di->dev, "%s "
186962306a36Sopenharmony_ci			"Failed to set ChOutputCurentLevel\n",
187062306a36Sopenharmony_ci			__func__);
187162306a36Sopenharmony_ci		return ret;
187262306a36Sopenharmony_ci	}
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	/* Reset the main and usb drop input current measurement counter */
187562306a36Sopenharmony_ci	ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
187662306a36Sopenharmony_ci				AB8500_CHARGER_CTRL, DROP_COUNT_RESET);
187762306a36Sopenharmony_ci	if (ret) {
187862306a36Sopenharmony_ci		dev_err(di->dev, "%s write failed\n", __func__);
187962306a36Sopenharmony_ci		return ret;
188062306a36Sopenharmony_ci	}
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	return ret;
188362306a36Sopenharmony_ci}
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_cistatic int ab8500_charger_get_ext_psy_data(struct device *dev, void *data)
188662306a36Sopenharmony_ci{
188762306a36Sopenharmony_ci	struct power_supply *psy;
188862306a36Sopenharmony_ci	struct power_supply *ext = dev_get_drvdata(dev);
188962306a36Sopenharmony_ci	const char **supplicants = (const char **)ext->supplied_to;
189062306a36Sopenharmony_ci	struct ab8500_charger *di;
189162306a36Sopenharmony_ci	union power_supply_propval ret;
189262306a36Sopenharmony_ci	int j;
189362306a36Sopenharmony_ci	struct ux500_charger *usb_chg;
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	usb_chg = (struct ux500_charger *)data;
189662306a36Sopenharmony_ci	psy = usb_chg->psy;
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	di = to_ab8500_charger_usb_device_info(usb_chg);
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	/*
190162306a36Sopenharmony_ci	 * For all psy where the driver name appears in any supplied_to
190262306a36Sopenharmony_ci	 * in practice what we will find will always be "ab8500_fg" as
190362306a36Sopenharmony_ci	 * the fuel gauge is responsible of keeping track of VBAT.
190462306a36Sopenharmony_ci	 */
190562306a36Sopenharmony_ci	j = match_string(supplicants, ext->num_supplicants, psy->desc->name);
190662306a36Sopenharmony_ci	if (j < 0)
190762306a36Sopenharmony_ci		return 0;
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	/* Go through all properties for the psy */
191062306a36Sopenharmony_ci	for (j = 0; j < ext->desc->num_properties; j++) {
191162306a36Sopenharmony_ci		enum power_supply_property prop;
191262306a36Sopenharmony_ci		prop = ext->desc->properties[j];
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci		if (power_supply_get_property(ext, prop, &ret))
191562306a36Sopenharmony_ci			continue;
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci		switch (prop) {
191862306a36Sopenharmony_ci		case POWER_SUPPLY_PROP_VOLTAGE_NOW:
191962306a36Sopenharmony_ci			switch (ext->desc->type) {
192062306a36Sopenharmony_ci			case POWER_SUPPLY_TYPE_BATTERY:
192162306a36Sopenharmony_ci				/* This will always be "ab8500_fg" */
192262306a36Sopenharmony_ci				dev_dbg(di->dev, "get VBAT from %s\n",
192362306a36Sopenharmony_ci					dev_name(&ext->dev));
192462306a36Sopenharmony_ci				di->vbat = ret.intval;
192562306a36Sopenharmony_ci				break;
192662306a36Sopenharmony_ci			default:
192762306a36Sopenharmony_ci				break;
192862306a36Sopenharmony_ci			}
192962306a36Sopenharmony_ci			break;
193062306a36Sopenharmony_ci		default:
193162306a36Sopenharmony_ci			break;
193262306a36Sopenharmony_ci		}
193362306a36Sopenharmony_ci	}
193462306a36Sopenharmony_ci	return 0;
193562306a36Sopenharmony_ci}
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci/**
193862306a36Sopenharmony_ci * ab8500_charger_check_vbat_work() - keep vbus current within spec
193962306a36Sopenharmony_ci * @work	pointer to the work_struct structure
194062306a36Sopenharmony_ci *
194162306a36Sopenharmony_ci * Due to a asic bug it is necessary to lower the input current to the vbus
194262306a36Sopenharmony_ci * charger when charging with at some specific levels. This issue is only valid
194362306a36Sopenharmony_ci * for below a certain battery voltage. This function makes sure that
194462306a36Sopenharmony_ci * the allowed current limit isn't exceeded.
194562306a36Sopenharmony_ci */
194662306a36Sopenharmony_cistatic void ab8500_charger_check_vbat_work(struct work_struct *work)
194762306a36Sopenharmony_ci{
194862306a36Sopenharmony_ci	int t = 10;
194962306a36Sopenharmony_ci	struct ab8500_charger *di = container_of(work,
195062306a36Sopenharmony_ci		struct ab8500_charger, check_vbat_work.work);
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci	class_for_each_device(power_supply_class, NULL,
195362306a36Sopenharmony_ci			      &di->usb_chg, ab8500_charger_get_ext_psy_data);
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	/* First run old_vbat is 0. */
195662306a36Sopenharmony_ci	if (di->old_vbat == 0)
195762306a36Sopenharmony_ci		di->old_vbat = di->vbat;
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	if (!((di->old_vbat <= VBAT_TRESH_IP_CUR_RED &&
196062306a36Sopenharmony_ci		di->vbat <= VBAT_TRESH_IP_CUR_RED) ||
196162306a36Sopenharmony_ci		(di->old_vbat > VBAT_TRESH_IP_CUR_RED &&
196262306a36Sopenharmony_ci		di->vbat > VBAT_TRESH_IP_CUR_RED))) {
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci		dev_dbg(di->dev, "Vbat did cross threshold, curr: %d, new: %d,"
196562306a36Sopenharmony_ci			" old: %d\n", di->max_usb_in_curr.usb_type_max_ua,
196662306a36Sopenharmony_ci			di->vbat, di->old_vbat);
196762306a36Sopenharmony_ci		ab8500_charger_set_vbus_in_curr(di,
196862306a36Sopenharmony_ci					di->max_usb_in_curr.usb_type_max_ua);
196962306a36Sopenharmony_ci		power_supply_changed(di->usb_chg.psy);
197062306a36Sopenharmony_ci	}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	di->old_vbat = di->vbat;
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	/*
197562306a36Sopenharmony_ci	 * No need to check the battery voltage every second when not close to
197662306a36Sopenharmony_ci	 * the threshold.
197762306a36Sopenharmony_ci	 */
197862306a36Sopenharmony_ci	if (di->vbat < (VBAT_TRESH_IP_CUR_RED + 100000) &&
197962306a36Sopenharmony_ci		(di->vbat > (VBAT_TRESH_IP_CUR_RED - 100000)))
198062306a36Sopenharmony_ci			t = 1;
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	queue_delayed_work(di->charger_wq, &di->check_vbat_work, t * HZ);
198362306a36Sopenharmony_ci}
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci/**
198662306a36Sopenharmony_ci * ab8500_charger_check_hw_failure_work() - check main charger failure
198762306a36Sopenharmony_ci * @work:	pointer to the work_struct structure
198862306a36Sopenharmony_ci *
198962306a36Sopenharmony_ci * Work queue function for checking the main charger status
199062306a36Sopenharmony_ci */
199162306a36Sopenharmony_cistatic void ab8500_charger_check_hw_failure_work(struct work_struct *work)
199262306a36Sopenharmony_ci{
199362306a36Sopenharmony_ci	int ret;
199462306a36Sopenharmony_ci	u8 reg_value;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	struct ab8500_charger *di = container_of(work,
199762306a36Sopenharmony_ci		struct ab8500_charger, check_hw_failure_work.work);
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	/* Check if the status bits for HW failure is still active */
200062306a36Sopenharmony_ci	if (di->flags.mainextchnotok) {
200162306a36Sopenharmony_ci		ret = abx500_get_register_interruptible(di->dev,
200262306a36Sopenharmony_ci			AB8500_CHARGER, AB8500_CH_STATUS2_REG, &reg_value);
200362306a36Sopenharmony_ci		if (ret < 0) {
200462306a36Sopenharmony_ci			dev_err(di->dev, "%s ab8500 read failed\n", __func__);
200562306a36Sopenharmony_ci			return;
200662306a36Sopenharmony_ci		}
200762306a36Sopenharmony_ci		if (!(reg_value & MAIN_CH_NOK)) {
200862306a36Sopenharmony_ci			di->flags.mainextchnotok = false;
200962306a36Sopenharmony_ci			ab8500_power_supply_changed(di, di->ac_chg.psy);
201062306a36Sopenharmony_ci		}
201162306a36Sopenharmony_ci	}
201262306a36Sopenharmony_ci	if (di->flags.vbus_ovv) {
201362306a36Sopenharmony_ci		ret = abx500_get_register_interruptible(di->dev,
201462306a36Sopenharmony_ci			AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG,
201562306a36Sopenharmony_ci			&reg_value);
201662306a36Sopenharmony_ci		if (ret < 0) {
201762306a36Sopenharmony_ci			dev_err(di->dev, "%s ab8500 read failed\n", __func__);
201862306a36Sopenharmony_ci			return;
201962306a36Sopenharmony_ci		}
202062306a36Sopenharmony_ci		if (!(reg_value & VBUS_OVV_TH)) {
202162306a36Sopenharmony_ci			di->flags.vbus_ovv = false;
202262306a36Sopenharmony_ci			ab8500_power_supply_changed(di, di->usb_chg.psy);
202362306a36Sopenharmony_ci		}
202462306a36Sopenharmony_ci	}
202562306a36Sopenharmony_ci	/* If we still have a failure, schedule a new check */
202662306a36Sopenharmony_ci	if (di->flags.mainextchnotok || di->flags.vbus_ovv) {
202762306a36Sopenharmony_ci		queue_delayed_work(di->charger_wq,
202862306a36Sopenharmony_ci			&di->check_hw_failure_work, round_jiffies(HZ));
202962306a36Sopenharmony_ci	}
203062306a36Sopenharmony_ci}
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci/**
203362306a36Sopenharmony_ci * ab8500_charger_kick_watchdog_work() - kick the watchdog
203462306a36Sopenharmony_ci * @work:	pointer to the work_struct structure
203562306a36Sopenharmony_ci *
203662306a36Sopenharmony_ci * Work queue function for kicking the charger watchdog.
203762306a36Sopenharmony_ci *
203862306a36Sopenharmony_ci * For ABB revision 1.0 and 1.1 there is a bug in the watchdog
203962306a36Sopenharmony_ci * logic. That means we have to continuously kick the charger
204062306a36Sopenharmony_ci * watchdog even when no charger is connected. This is only
204162306a36Sopenharmony_ci * valid once the AC charger has been enabled. This is
204262306a36Sopenharmony_ci * a bug that is not handled by the algorithm and the
204362306a36Sopenharmony_ci * watchdog have to be kicked by the charger driver
204462306a36Sopenharmony_ci * when the AC charger is disabled
204562306a36Sopenharmony_ci */
204662306a36Sopenharmony_cistatic void ab8500_charger_kick_watchdog_work(struct work_struct *work)
204762306a36Sopenharmony_ci{
204862306a36Sopenharmony_ci	int ret;
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci	struct ab8500_charger *di = container_of(work,
205162306a36Sopenharmony_ci		struct ab8500_charger, kick_wd_work.work);
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
205462306a36Sopenharmony_ci		AB8500_CHARG_WD_CTRL, CHARG_WD_KICK);
205562306a36Sopenharmony_ci	if (ret)
205662306a36Sopenharmony_ci		dev_err(di->dev, "Failed to kick WD!\n");
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	/* Schedule a new watchdog kick */
205962306a36Sopenharmony_ci	queue_delayed_work(di->charger_wq,
206062306a36Sopenharmony_ci		&di->kick_wd_work, round_jiffies(WD_KICK_INTERVAL));
206162306a36Sopenharmony_ci}
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci/**
206462306a36Sopenharmony_ci * ab8500_charger_ac_work() - work to get and set main charger status
206562306a36Sopenharmony_ci * @work:	pointer to the work_struct structure
206662306a36Sopenharmony_ci *
206762306a36Sopenharmony_ci * Work queue function for checking the main charger status
206862306a36Sopenharmony_ci */
206962306a36Sopenharmony_cistatic void ab8500_charger_ac_work(struct work_struct *work)
207062306a36Sopenharmony_ci{
207162306a36Sopenharmony_ci	int ret;
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci	struct ab8500_charger *di = container_of(work,
207462306a36Sopenharmony_ci		struct ab8500_charger, ac_work);
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci	/*
207762306a36Sopenharmony_ci	 * Since we can't be sure that the events are received
207862306a36Sopenharmony_ci	 * synchronously, we have the check if the main charger is
207962306a36Sopenharmony_ci	 * connected by reading the status register
208062306a36Sopenharmony_ci	 */
208162306a36Sopenharmony_ci	ret = ab8500_charger_detect_chargers(di, false);
208262306a36Sopenharmony_ci	if (ret < 0)
208362306a36Sopenharmony_ci		return;
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci	if (ret & AC_PW_CONN) {
208662306a36Sopenharmony_ci		di->ac.charger_connected = 1;
208762306a36Sopenharmony_ci		di->ac_conn = true;
208862306a36Sopenharmony_ci	} else {
208962306a36Sopenharmony_ci		di->ac.charger_connected = 0;
209062306a36Sopenharmony_ci	}
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	ab8500_power_supply_changed(di, di->ac_chg.psy);
209362306a36Sopenharmony_ci	sysfs_notify(&di->ac_chg.psy->dev.kobj, NULL, "present");
209462306a36Sopenharmony_ci}
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_cistatic void ab8500_charger_usb_attached_work(struct work_struct *work)
209762306a36Sopenharmony_ci{
209862306a36Sopenharmony_ci	struct ab8500_charger *di = container_of(work,
209962306a36Sopenharmony_ci						 struct ab8500_charger,
210062306a36Sopenharmony_ci						 usb_charger_attached_work.work);
210162306a36Sopenharmony_ci	int usbch = (USB_CH_VBUSDROP | USB_CH_VBUSDETDBNC);
210262306a36Sopenharmony_ci	int ret, i;
210362306a36Sopenharmony_ci	u8 statval;
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
210662306a36Sopenharmony_ci		ret = abx500_get_register_interruptible(di->dev,
210762306a36Sopenharmony_ci							AB8500_CHARGER,
210862306a36Sopenharmony_ci							AB8500_CH_USBCH_STAT1_REG,
210962306a36Sopenharmony_ci							&statval);
211062306a36Sopenharmony_ci		if (ret < 0) {
211162306a36Sopenharmony_ci			dev_err(di->dev, "ab8500 read failed %d\n", __LINE__);
211262306a36Sopenharmony_ci			goto reschedule;
211362306a36Sopenharmony_ci		}
211462306a36Sopenharmony_ci		if ((statval & usbch) != usbch)
211562306a36Sopenharmony_ci			goto reschedule;
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci		msleep(CHARGER_STATUS_POLL);
211862306a36Sopenharmony_ci	}
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	ab8500_charger_usb_en(&di->usb_chg, 0, 0, 0);
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci	mutex_lock(&di->charger_attached_mutex);
212362306a36Sopenharmony_ci	mutex_unlock(&di->charger_attached_mutex);
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	return;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_cireschedule:
212862306a36Sopenharmony_ci	queue_delayed_work(di->charger_wq,
212962306a36Sopenharmony_ci			   &di->usb_charger_attached_work,
213062306a36Sopenharmony_ci			   HZ);
213162306a36Sopenharmony_ci}
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_cistatic void ab8500_charger_ac_attached_work(struct work_struct *work)
213462306a36Sopenharmony_ci{
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	struct ab8500_charger *di = container_of(work,
213762306a36Sopenharmony_ci						 struct ab8500_charger,
213862306a36Sopenharmony_ci						 ac_charger_attached_work.work);
213962306a36Sopenharmony_ci	int mainch = (MAIN_CH_STATUS2_MAINCHGDROP |
214062306a36Sopenharmony_ci		      MAIN_CH_STATUS2_MAINCHARGERDETDBNC);
214162306a36Sopenharmony_ci	int ret, i;
214262306a36Sopenharmony_ci	u8 statval;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
214562306a36Sopenharmony_ci		ret = abx500_get_register_interruptible(di->dev,
214662306a36Sopenharmony_ci							AB8500_CHARGER,
214762306a36Sopenharmony_ci							AB8500_CH_STATUS2_REG,
214862306a36Sopenharmony_ci							&statval);
214962306a36Sopenharmony_ci		if (ret < 0) {
215062306a36Sopenharmony_ci			dev_err(di->dev, "ab8500 read failed %d\n", __LINE__);
215162306a36Sopenharmony_ci			goto reschedule;
215262306a36Sopenharmony_ci		}
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci		if ((statval & mainch) != mainch)
215562306a36Sopenharmony_ci			goto reschedule;
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci		msleep(CHARGER_STATUS_POLL);
215862306a36Sopenharmony_ci	}
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	ab8500_charger_ac_en(&di->ac_chg, 0, 0, 0);
216162306a36Sopenharmony_ci	queue_work(di->charger_wq, &di->ac_work);
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci	mutex_lock(&di->charger_attached_mutex);
216462306a36Sopenharmony_ci	mutex_unlock(&di->charger_attached_mutex);
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	return;
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_cireschedule:
216962306a36Sopenharmony_ci	queue_delayed_work(di->charger_wq,
217062306a36Sopenharmony_ci			   &di->ac_charger_attached_work,
217162306a36Sopenharmony_ci			   HZ);
217262306a36Sopenharmony_ci}
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci/**
217562306a36Sopenharmony_ci * ab8500_charger_detect_usb_type_work() - work to detect USB type
217662306a36Sopenharmony_ci * @work:	Pointer to the work_struct structure
217762306a36Sopenharmony_ci *
217862306a36Sopenharmony_ci * Detect the type of USB plugged
217962306a36Sopenharmony_ci */
218062306a36Sopenharmony_cistatic void ab8500_charger_detect_usb_type_work(struct work_struct *work)
218162306a36Sopenharmony_ci{
218262306a36Sopenharmony_ci	int ret;
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci	struct ab8500_charger *di = container_of(work,
218562306a36Sopenharmony_ci		struct ab8500_charger, detect_usb_type_work);
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci	/*
218862306a36Sopenharmony_ci	 * Since we can't be sure that the events are received
218962306a36Sopenharmony_ci	 * synchronously, we have the check if is
219062306a36Sopenharmony_ci	 * connected by reading the status register
219162306a36Sopenharmony_ci	 */
219262306a36Sopenharmony_ci	ret = ab8500_charger_detect_chargers(di, false);
219362306a36Sopenharmony_ci	if (ret < 0)
219462306a36Sopenharmony_ci		return;
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	if (!(ret & USB_PW_CONN)) {
219762306a36Sopenharmony_ci		dev_dbg(di->dev, "%s di->vbus_detected = false\n", __func__);
219862306a36Sopenharmony_ci		di->vbus_detected = false;
219962306a36Sopenharmony_ci		ab8500_charger_set_usb_connected(di, false);
220062306a36Sopenharmony_ci		ab8500_power_supply_changed(di, di->usb_chg.psy);
220162306a36Sopenharmony_ci	} else {
220262306a36Sopenharmony_ci		dev_dbg(di->dev, "%s di->vbus_detected = true\n", __func__);
220362306a36Sopenharmony_ci		di->vbus_detected = true;
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci		if (is_ab8500_1p1_or_earlier(di->parent)) {
220662306a36Sopenharmony_ci			ret = ab8500_charger_detect_usb_type(di);
220762306a36Sopenharmony_ci			if (!ret) {
220862306a36Sopenharmony_ci				ab8500_charger_set_usb_connected(di, true);
220962306a36Sopenharmony_ci				ab8500_power_supply_changed(di,
221062306a36Sopenharmony_ci							    di->usb_chg.psy);
221162306a36Sopenharmony_ci			}
221262306a36Sopenharmony_ci		} else {
221362306a36Sopenharmony_ci			/*
221462306a36Sopenharmony_ci			 * For ABB cut2.0 and onwards we have an IRQ,
221562306a36Sopenharmony_ci			 * USB_LINK_STATUS that will be triggered when the USB
221662306a36Sopenharmony_ci			 * link status changes. The exception is USB connected
221762306a36Sopenharmony_ci			 * during startup. Then we don't get a
221862306a36Sopenharmony_ci			 * USB_LINK_STATUS IRQ
221962306a36Sopenharmony_ci			 */
222062306a36Sopenharmony_ci			if (di->vbus_detected_start) {
222162306a36Sopenharmony_ci				di->vbus_detected_start = false;
222262306a36Sopenharmony_ci				ret = ab8500_charger_detect_usb_type(di);
222362306a36Sopenharmony_ci				if (!ret) {
222462306a36Sopenharmony_ci					ab8500_charger_set_usb_connected(di,
222562306a36Sopenharmony_ci						true);
222662306a36Sopenharmony_ci					ab8500_power_supply_changed(di,
222762306a36Sopenharmony_ci						di->usb_chg.psy);
222862306a36Sopenharmony_ci				}
222962306a36Sopenharmony_ci			}
223062306a36Sopenharmony_ci		}
223162306a36Sopenharmony_ci	}
223262306a36Sopenharmony_ci}
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci/**
223562306a36Sopenharmony_ci * ab8500_charger_usb_link_attach_work() - work to detect USB type
223662306a36Sopenharmony_ci * @work:	pointer to the work_struct structure
223762306a36Sopenharmony_ci *
223862306a36Sopenharmony_ci * Detect the type of USB plugged
223962306a36Sopenharmony_ci */
224062306a36Sopenharmony_cistatic void ab8500_charger_usb_link_attach_work(struct work_struct *work)
224162306a36Sopenharmony_ci{
224262306a36Sopenharmony_ci	struct ab8500_charger *di =
224362306a36Sopenharmony_ci		container_of(work, struct ab8500_charger, attach_work.work);
224462306a36Sopenharmony_ci	int ret;
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	/* Update maximum input current if USB enumeration is not detected */
224762306a36Sopenharmony_ci	if (!di->usb.charger_online) {
224862306a36Sopenharmony_ci		ret = ab8500_charger_set_vbus_in_curr(di,
224962306a36Sopenharmony_ci					di->max_usb_in_curr.usb_type_max_ua);
225062306a36Sopenharmony_ci		if (ret)
225162306a36Sopenharmony_ci			return;
225262306a36Sopenharmony_ci	}
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	ab8500_charger_set_usb_connected(di, true);
225562306a36Sopenharmony_ci	ab8500_power_supply_changed(di, di->usb_chg.psy);
225662306a36Sopenharmony_ci}
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci/**
225962306a36Sopenharmony_ci * ab8500_charger_usb_link_status_work() - work to detect USB type
226062306a36Sopenharmony_ci * @work:	pointer to the work_struct structure
226162306a36Sopenharmony_ci *
226262306a36Sopenharmony_ci * Detect the type of USB plugged
226362306a36Sopenharmony_ci */
226462306a36Sopenharmony_cistatic void ab8500_charger_usb_link_status_work(struct work_struct *work)
226562306a36Sopenharmony_ci{
226662306a36Sopenharmony_ci	int detected_chargers;
226762306a36Sopenharmony_ci	int ret;
226862306a36Sopenharmony_ci	u8 val;
226962306a36Sopenharmony_ci	u8 link_status;
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	struct ab8500_charger *di = container_of(work,
227262306a36Sopenharmony_ci		struct ab8500_charger, usb_link_status_work);
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci	/*
227562306a36Sopenharmony_ci	 * Since we can't be sure that the events are received
227662306a36Sopenharmony_ci	 * synchronously, we have the check if  is
227762306a36Sopenharmony_ci	 * connected by reading the status register
227862306a36Sopenharmony_ci	 */
227962306a36Sopenharmony_ci	detected_chargers = ab8500_charger_detect_chargers(di, false);
228062306a36Sopenharmony_ci	if (detected_chargers < 0)
228162306a36Sopenharmony_ci		return;
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci	/*
228462306a36Sopenharmony_ci	 * Some chargers that breaks the USB spec is
228562306a36Sopenharmony_ci	 * identified as invalid by AB8500 and it refuse
228662306a36Sopenharmony_ci	 * to start the charging process. but by jumping
228762306a36Sopenharmony_ci	 * through a few hoops it can be forced to start.
228862306a36Sopenharmony_ci	 */
228962306a36Sopenharmony_ci	if (is_ab8500(di->parent))
229062306a36Sopenharmony_ci		ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
229162306a36Sopenharmony_ci					AB8500_USB_LINE_STAT_REG, &val);
229262306a36Sopenharmony_ci	else
229362306a36Sopenharmony_ci		ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
229462306a36Sopenharmony_ci					AB8500_USB_LINK1_STAT_REG, &val);
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	if (ret >= 0)
229762306a36Sopenharmony_ci		dev_dbg(di->dev, "UsbLineStatus register = 0x%02x\n", val);
229862306a36Sopenharmony_ci	else
229962306a36Sopenharmony_ci		dev_dbg(di->dev, "Error reading USB link status\n");
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	if (is_ab8500(di->parent))
230262306a36Sopenharmony_ci		link_status = AB8500_USB_LINK_STATUS;
230362306a36Sopenharmony_ci	else
230462306a36Sopenharmony_ci		link_status = AB8505_USB_LINK_STATUS;
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	if (detected_chargers & USB_PW_CONN) {
230762306a36Sopenharmony_ci		if (((val & link_status) >> USB_LINK_STATUS_SHIFT) ==
230862306a36Sopenharmony_ci				USB_STAT_NOT_VALID_LINK &&
230962306a36Sopenharmony_ci				di->invalid_charger_detect_state == 0) {
231062306a36Sopenharmony_ci			dev_dbg(di->dev,
231162306a36Sopenharmony_ci					"Invalid charger detected, state= 0\n");
231262306a36Sopenharmony_ci			/*Enable charger*/
231362306a36Sopenharmony_ci			abx500_mask_and_set_register_interruptible(di->dev,
231462306a36Sopenharmony_ci					AB8500_CHARGER, AB8500_USBCH_CTRL1_REG,
231562306a36Sopenharmony_ci					USB_CH_ENA, USB_CH_ENA);
231662306a36Sopenharmony_ci			/*Enable charger detection*/
231762306a36Sopenharmony_ci			abx500_mask_and_set_register_interruptible(di->dev,
231862306a36Sopenharmony_ci					AB8500_USB, AB8500_USB_LINE_CTRL2_REG,
231962306a36Sopenharmony_ci					USB_CH_DET, USB_CH_DET);
232062306a36Sopenharmony_ci			di->invalid_charger_detect_state = 1;
232162306a36Sopenharmony_ci			/*exit and wait for new link status interrupt.*/
232262306a36Sopenharmony_ci			return;
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci		}
232562306a36Sopenharmony_ci		if (di->invalid_charger_detect_state == 1) {
232662306a36Sopenharmony_ci			dev_dbg(di->dev,
232762306a36Sopenharmony_ci					"Invalid charger detected, state= 1\n");
232862306a36Sopenharmony_ci			/*Stop charger detection*/
232962306a36Sopenharmony_ci			abx500_mask_and_set_register_interruptible(di->dev,
233062306a36Sopenharmony_ci					AB8500_USB, AB8500_USB_LINE_CTRL2_REG,
233162306a36Sopenharmony_ci					USB_CH_DET, 0x00);
233262306a36Sopenharmony_ci			/*Check link status*/
233362306a36Sopenharmony_ci			if (is_ab8500(di->parent))
233462306a36Sopenharmony_ci				ret = abx500_get_register_interruptible(di->dev,
233562306a36Sopenharmony_ci					AB8500_USB, AB8500_USB_LINE_STAT_REG,
233662306a36Sopenharmony_ci					&val);
233762306a36Sopenharmony_ci			else
233862306a36Sopenharmony_ci				ret = abx500_get_register_interruptible(di->dev,
233962306a36Sopenharmony_ci					AB8500_USB, AB8500_USB_LINK1_STAT_REG,
234062306a36Sopenharmony_ci					&val);
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_ci			dev_dbg(di->dev, "USB link status= 0x%02x\n",
234362306a36Sopenharmony_ci				(val & link_status) >> USB_LINK_STATUS_SHIFT);
234462306a36Sopenharmony_ci			di->invalid_charger_detect_state = 2;
234562306a36Sopenharmony_ci		}
234662306a36Sopenharmony_ci	} else {
234762306a36Sopenharmony_ci		di->invalid_charger_detect_state = 0;
234862306a36Sopenharmony_ci	}
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	if (!(detected_chargers & USB_PW_CONN)) {
235162306a36Sopenharmony_ci		di->vbus_detected = false;
235262306a36Sopenharmony_ci		ab8500_charger_set_usb_connected(di, false);
235362306a36Sopenharmony_ci		ab8500_power_supply_changed(di, di->usb_chg.psy);
235462306a36Sopenharmony_ci		return;
235562306a36Sopenharmony_ci	}
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ci	dev_dbg(di->dev,"%s di->vbus_detected = true\n",__func__);
235862306a36Sopenharmony_ci	di->vbus_detected = true;
235962306a36Sopenharmony_ci	ret = ab8500_charger_read_usb_type(di);
236062306a36Sopenharmony_ci	if (ret) {
236162306a36Sopenharmony_ci		if (ret == -ENXIO) {
236262306a36Sopenharmony_ci			/* No valid charger type detected */
236362306a36Sopenharmony_ci			ab8500_charger_set_usb_connected(di, false);
236462306a36Sopenharmony_ci			ab8500_power_supply_changed(di, di->usb_chg.psy);
236562306a36Sopenharmony_ci		}
236662306a36Sopenharmony_ci		return;
236762306a36Sopenharmony_ci	}
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci	if (di->usb_device_is_unrecognised) {
237062306a36Sopenharmony_ci		dev_dbg(di->dev,
237162306a36Sopenharmony_ci			"Potential Legacy Charger device. "
237262306a36Sopenharmony_ci			"Delay work for %d msec for USB enum "
237362306a36Sopenharmony_ci			"to finish",
237462306a36Sopenharmony_ci			WAIT_ACA_RID_ENUMERATION);
237562306a36Sopenharmony_ci		queue_delayed_work(di->charger_wq,
237662306a36Sopenharmony_ci				   &di->attach_work,
237762306a36Sopenharmony_ci				   msecs_to_jiffies(WAIT_ACA_RID_ENUMERATION));
237862306a36Sopenharmony_ci	} else if (di->is_aca_rid == 1) {
237962306a36Sopenharmony_ci		/* Only wait once */
238062306a36Sopenharmony_ci		di->is_aca_rid++;
238162306a36Sopenharmony_ci		dev_dbg(di->dev,
238262306a36Sopenharmony_ci			"%s Wait %d msec for USB enum to finish",
238362306a36Sopenharmony_ci			__func__, WAIT_ACA_RID_ENUMERATION);
238462306a36Sopenharmony_ci		queue_delayed_work(di->charger_wq,
238562306a36Sopenharmony_ci				   &di->attach_work,
238662306a36Sopenharmony_ci				   msecs_to_jiffies(WAIT_ACA_RID_ENUMERATION));
238762306a36Sopenharmony_ci	} else {
238862306a36Sopenharmony_ci		queue_delayed_work(di->charger_wq,
238962306a36Sopenharmony_ci				   &di->attach_work,
239062306a36Sopenharmony_ci				   0);
239162306a36Sopenharmony_ci	}
239262306a36Sopenharmony_ci}
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_cistatic void ab8500_charger_usb_state_changed_work(struct work_struct *work)
239562306a36Sopenharmony_ci{
239662306a36Sopenharmony_ci	int ret;
239762306a36Sopenharmony_ci	unsigned long flags;
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci	struct ab8500_charger *di = container_of(work,
240062306a36Sopenharmony_ci		struct ab8500_charger, usb_state_changed_work.work);
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci	if (!di->vbus_detected)	{
240362306a36Sopenharmony_ci		dev_dbg(di->dev,
240462306a36Sopenharmony_ci			"%s !di->vbus_detected\n",
240562306a36Sopenharmony_ci			__func__);
240662306a36Sopenharmony_ci		return;
240762306a36Sopenharmony_ci	}
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ci	spin_lock_irqsave(&di->usb_state.usb_lock, flags);
241062306a36Sopenharmony_ci	di->usb_state.state = di->usb_state.state_tmp;
241162306a36Sopenharmony_ci	di->usb_state.usb_current_ua = di->usb_state.usb_current_tmp_ua;
241262306a36Sopenharmony_ci	spin_unlock_irqrestore(&di->usb_state.usb_lock, flags);
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	dev_dbg(di->dev, "%s USB state: 0x%02x uA: %d\n",
241562306a36Sopenharmony_ci		__func__, di->usb_state.state, di->usb_state.usb_current_ua);
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci	switch (di->usb_state.state) {
241862306a36Sopenharmony_ci	case AB8500_BM_USB_STATE_RESET_HS:
241962306a36Sopenharmony_ci	case AB8500_BM_USB_STATE_RESET_FS:
242062306a36Sopenharmony_ci	case AB8500_BM_USB_STATE_SUSPEND:
242162306a36Sopenharmony_ci	case AB8500_BM_USB_STATE_MAX:
242262306a36Sopenharmony_ci		ab8500_charger_set_usb_connected(di, false);
242362306a36Sopenharmony_ci		ab8500_power_supply_changed(di, di->usb_chg.psy);
242462306a36Sopenharmony_ci		break;
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci	case AB8500_BM_USB_STATE_RESUME:
242762306a36Sopenharmony_ci		/*
242862306a36Sopenharmony_ci		 * when suspend->resume there should be delay
242962306a36Sopenharmony_ci		 * of 1sec for enabling charging
243062306a36Sopenharmony_ci		 */
243162306a36Sopenharmony_ci		msleep(1000);
243262306a36Sopenharmony_ci		fallthrough;
243362306a36Sopenharmony_ci	case AB8500_BM_USB_STATE_CONFIGURED:
243462306a36Sopenharmony_ci		/*
243562306a36Sopenharmony_ci		 * USB is configured, enable charging with the charging
243662306a36Sopenharmony_ci		 * input current obtained from USB driver
243762306a36Sopenharmony_ci		 */
243862306a36Sopenharmony_ci		if (!ab8500_charger_get_usb_cur(di)) {
243962306a36Sopenharmony_ci			/* Update maximum input current */
244062306a36Sopenharmony_ci			ret = ab8500_charger_set_vbus_in_curr(di,
244162306a36Sopenharmony_ci					di->max_usb_in_curr.usb_type_max_ua);
244262306a36Sopenharmony_ci			if (ret)
244362306a36Sopenharmony_ci				return;
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_ci			ab8500_charger_set_usb_connected(di, true);
244662306a36Sopenharmony_ci			ab8500_power_supply_changed(di, di->usb_chg.psy);
244762306a36Sopenharmony_ci		}
244862306a36Sopenharmony_ci		break;
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci	default:
245162306a36Sopenharmony_ci		break;
245262306a36Sopenharmony_ci	}
245362306a36Sopenharmony_ci}
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_ci/**
245662306a36Sopenharmony_ci * ab8500_charger_check_usbchargernotok_work() - check USB chg not ok status
245762306a36Sopenharmony_ci * @work:	pointer to the work_struct structure
245862306a36Sopenharmony_ci *
245962306a36Sopenharmony_ci * Work queue function for checking the USB charger Not OK status
246062306a36Sopenharmony_ci */
246162306a36Sopenharmony_cistatic void ab8500_charger_check_usbchargernotok_work(struct work_struct *work)
246262306a36Sopenharmony_ci{
246362306a36Sopenharmony_ci	int ret;
246462306a36Sopenharmony_ci	u8 reg_value;
246562306a36Sopenharmony_ci	bool prev_status;
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci	struct ab8500_charger *di = container_of(work,
246862306a36Sopenharmony_ci		struct ab8500_charger, check_usbchgnotok_work.work);
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_ci	/* Check if the status bit for usbchargernotok is still active */
247162306a36Sopenharmony_ci	ret = abx500_get_register_interruptible(di->dev,
247262306a36Sopenharmony_ci		AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG, &reg_value);
247362306a36Sopenharmony_ci	if (ret < 0) {
247462306a36Sopenharmony_ci		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
247562306a36Sopenharmony_ci		return;
247662306a36Sopenharmony_ci	}
247762306a36Sopenharmony_ci	prev_status = di->flags.usbchargernotok;
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci	if (reg_value & VBUS_CH_NOK) {
248062306a36Sopenharmony_ci		di->flags.usbchargernotok = true;
248162306a36Sopenharmony_ci		/* Check again in 1sec */
248262306a36Sopenharmony_ci		queue_delayed_work(di->charger_wq,
248362306a36Sopenharmony_ci			&di->check_usbchgnotok_work, HZ);
248462306a36Sopenharmony_ci	} else {
248562306a36Sopenharmony_ci		di->flags.usbchargernotok = false;
248662306a36Sopenharmony_ci		di->flags.vbus_collapse = false;
248762306a36Sopenharmony_ci	}
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci	if (prev_status != di->flags.usbchargernotok)
249062306a36Sopenharmony_ci		ab8500_power_supply_changed(di, di->usb_chg.psy);
249162306a36Sopenharmony_ci}
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci/**
249462306a36Sopenharmony_ci * ab8500_charger_check_main_thermal_prot_work() - check main thermal status
249562306a36Sopenharmony_ci * @work:	pointer to the work_struct structure
249662306a36Sopenharmony_ci *
249762306a36Sopenharmony_ci * Work queue function for checking the Main thermal prot status
249862306a36Sopenharmony_ci */
249962306a36Sopenharmony_cistatic void ab8500_charger_check_main_thermal_prot_work(
250062306a36Sopenharmony_ci	struct work_struct *work)
250162306a36Sopenharmony_ci{
250262306a36Sopenharmony_ci	int ret;
250362306a36Sopenharmony_ci	u8 reg_value;
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	struct ab8500_charger *di = container_of(work,
250662306a36Sopenharmony_ci		struct ab8500_charger, check_main_thermal_prot_work);
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci	/* Check if the status bit for main_thermal_prot is still active */
250962306a36Sopenharmony_ci	ret = abx500_get_register_interruptible(di->dev,
251062306a36Sopenharmony_ci		AB8500_CHARGER, AB8500_CH_STATUS2_REG, &reg_value);
251162306a36Sopenharmony_ci	if (ret < 0) {
251262306a36Sopenharmony_ci		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
251362306a36Sopenharmony_ci		return;
251462306a36Sopenharmony_ci	}
251562306a36Sopenharmony_ci	if (reg_value & MAIN_CH_TH_PROT)
251662306a36Sopenharmony_ci		di->flags.main_thermal_prot = true;
251762306a36Sopenharmony_ci	else
251862306a36Sopenharmony_ci		di->flags.main_thermal_prot = false;
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	ab8500_power_supply_changed(di, di->ac_chg.psy);
252162306a36Sopenharmony_ci}
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci/**
252462306a36Sopenharmony_ci * ab8500_charger_check_usb_thermal_prot_work() - check usb thermal status
252562306a36Sopenharmony_ci * @work:	pointer to the work_struct structure
252662306a36Sopenharmony_ci *
252762306a36Sopenharmony_ci * Work queue function for checking the USB thermal prot status
252862306a36Sopenharmony_ci */
252962306a36Sopenharmony_cistatic void ab8500_charger_check_usb_thermal_prot_work(
253062306a36Sopenharmony_ci	struct work_struct *work)
253162306a36Sopenharmony_ci{
253262306a36Sopenharmony_ci	int ret;
253362306a36Sopenharmony_ci	u8 reg_value;
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci	struct ab8500_charger *di = container_of(work,
253662306a36Sopenharmony_ci		struct ab8500_charger, check_usb_thermal_prot_work);
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci	/* Check if the status bit for usb_thermal_prot is still active */
253962306a36Sopenharmony_ci	ret = abx500_get_register_interruptible(di->dev,
254062306a36Sopenharmony_ci		AB8500_CHARGER, AB8500_CH_USBCH_STAT2_REG, &reg_value);
254162306a36Sopenharmony_ci	if (ret < 0) {
254262306a36Sopenharmony_ci		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
254362306a36Sopenharmony_ci		return;
254462306a36Sopenharmony_ci	}
254562306a36Sopenharmony_ci	if (reg_value & USB_CH_TH_PROT)
254662306a36Sopenharmony_ci		di->flags.usb_thermal_prot = true;
254762306a36Sopenharmony_ci	else
254862306a36Sopenharmony_ci		di->flags.usb_thermal_prot = false;
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	ab8500_power_supply_changed(di, di->usb_chg.psy);
255162306a36Sopenharmony_ci}
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci/**
255462306a36Sopenharmony_ci * ab8500_charger_mainchunplugdet_handler() - main charger unplugged
255562306a36Sopenharmony_ci * @irq:       interrupt number
255662306a36Sopenharmony_ci * @_di:       pointer to the ab8500_charger structure
255762306a36Sopenharmony_ci *
255862306a36Sopenharmony_ci * Returns IRQ status(IRQ_HANDLED)
255962306a36Sopenharmony_ci */
256062306a36Sopenharmony_cistatic irqreturn_t ab8500_charger_mainchunplugdet_handler(int irq, void *_di)
256162306a36Sopenharmony_ci{
256262306a36Sopenharmony_ci	struct ab8500_charger *di = _di;
256362306a36Sopenharmony_ci
256462306a36Sopenharmony_ci	dev_dbg(di->dev, "Main charger unplugged\n");
256562306a36Sopenharmony_ci	queue_work(di->charger_wq, &di->ac_work);
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci	cancel_delayed_work_sync(&di->ac_charger_attached_work);
256862306a36Sopenharmony_ci	mutex_lock(&di->charger_attached_mutex);
256962306a36Sopenharmony_ci	mutex_unlock(&di->charger_attached_mutex);
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	return IRQ_HANDLED;
257262306a36Sopenharmony_ci}
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_ci/**
257562306a36Sopenharmony_ci * ab8500_charger_mainchplugdet_handler() - main charger plugged
257662306a36Sopenharmony_ci * @irq:       interrupt number
257762306a36Sopenharmony_ci * @_di:       pointer to the ab8500_charger structure
257862306a36Sopenharmony_ci *
257962306a36Sopenharmony_ci * Returns IRQ status(IRQ_HANDLED)
258062306a36Sopenharmony_ci */
258162306a36Sopenharmony_cistatic irqreturn_t ab8500_charger_mainchplugdet_handler(int irq, void *_di)
258262306a36Sopenharmony_ci{
258362306a36Sopenharmony_ci	struct ab8500_charger *di = _di;
258462306a36Sopenharmony_ci
258562306a36Sopenharmony_ci	dev_dbg(di->dev, "Main charger plugged\n");
258662306a36Sopenharmony_ci	queue_work(di->charger_wq, &di->ac_work);
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	mutex_lock(&di->charger_attached_mutex);
258962306a36Sopenharmony_ci	mutex_unlock(&di->charger_attached_mutex);
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	if (is_ab8500(di->parent))
259262306a36Sopenharmony_ci		queue_delayed_work(di->charger_wq,
259362306a36Sopenharmony_ci			   &di->ac_charger_attached_work,
259462306a36Sopenharmony_ci			   HZ);
259562306a36Sopenharmony_ci	return IRQ_HANDLED;
259662306a36Sopenharmony_ci}
259762306a36Sopenharmony_ci
259862306a36Sopenharmony_ci/**
259962306a36Sopenharmony_ci * ab8500_charger_mainextchnotok_handler() - main charger not ok
260062306a36Sopenharmony_ci * @irq:       interrupt number
260162306a36Sopenharmony_ci * @_di:       pointer to the ab8500_charger structure
260262306a36Sopenharmony_ci *
260362306a36Sopenharmony_ci * Returns IRQ status(IRQ_HANDLED)
260462306a36Sopenharmony_ci */
260562306a36Sopenharmony_cistatic irqreturn_t ab8500_charger_mainextchnotok_handler(int irq, void *_di)
260662306a36Sopenharmony_ci{
260762306a36Sopenharmony_ci	struct ab8500_charger *di = _di;
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci	dev_dbg(di->dev, "Main charger not ok\n");
261062306a36Sopenharmony_ci	di->flags.mainextchnotok = true;
261162306a36Sopenharmony_ci	ab8500_power_supply_changed(di, di->ac_chg.psy);
261262306a36Sopenharmony_ci
261362306a36Sopenharmony_ci	/* Schedule a new HW failure check */
261462306a36Sopenharmony_ci	queue_delayed_work(di->charger_wq, &di->check_hw_failure_work, 0);
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	return IRQ_HANDLED;
261762306a36Sopenharmony_ci}
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci/**
262062306a36Sopenharmony_ci * ab8500_charger_mainchthprotr_handler() - Die temp is above main charger
262162306a36Sopenharmony_ci * thermal protection threshold
262262306a36Sopenharmony_ci * @irq:       interrupt number
262362306a36Sopenharmony_ci * @_di:       pointer to the ab8500_charger structure
262462306a36Sopenharmony_ci *
262562306a36Sopenharmony_ci * Returns IRQ status(IRQ_HANDLED)
262662306a36Sopenharmony_ci */
262762306a36Sopenharmony_cistatic irqreturn_t ab8500_charger_mainchthprotr_handler(int irq, void *_di)
262862306a36Sopenharmony_ci{
262962306a36Sopenharmony_ci	struct ab8500_charger *di = _di;
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci	dev_dbg(di->dev,
263262306a36Sopenharmony_ci		"Die temp above Main charger thermal protection threshold\n");
263362306a36Sopenharmony_ci	queue_work(di->charger_wq, &di->check_main_thermal_prot_work);
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_ci	return IRQ_HANDLED;
263662306a36Sopenharmony_ci}
263762306a36Sopenharmony_ci
263862306a36Sopenharmony_ci/**
263962306a36Sopenharmony_ci * ab8500_charger_mainchthprotf_handler() - Die temp is below main charger
264062306a36Sopenharmony_ci * thermal protection threshold
264162306a36Sopenharmony_ci * @irq:       interrupt number
264262306a36Sopenharmony_ci * @_di:       pointer to the ab8500_charger structure
264362306a36Sopenharmony_ci *
264462306a36Sopenharmony_ci * Returns IRQ status(IRQ_HANDLED)
264562306a36Sopenharmony_ci */
264662306a36Sopenharmony_cistatic irqreturn_t ab8500_charger_mainchthprotf_handler(int irq, void *_di)
264762306a36Sopenharmony_ci{
264862306a36Sopenharmony_ci	struct ab8500_charger *di = _di;
264962306a36Sopenharmony_ci
265062306a36Sopenharmony_ci	dev_dbg(di->dev,
265162306a36Sopenharmony_ci		"Die temp ok for Main charger thermal protection threshold\n");
265262306a36Sopenharmony_ci	queue_work(di->charger_wq, &di->check_main_thermal_prot_work);
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_ci	return IRQ_HANDLED;
265562306a36Sopenharmony_ci}
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_cistatic void ab8500_charger_vbus_drop_end_work(struct work_struct *work)
265862306a36Sopenharmony_ci{
265962306a36Sopenharmony_ci	struct ab8500_charger *di = container_of(work,
266062306a36Sopenharmony_ci		struct ab8500_charger, vbus_drop_end_work.work);
266162306a36Sopenharmony_ci	int ret, curr_ua;
266262306a36Sopenharmony_ci	u8 reg_value;
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	di->flags.vbus_drop_end = false;
266562306a36Sopenharmony_ci
266662306a36Sopenharmony_ci	/* Reset the drop counter */
266762306a36Sopenharmony_ci	abx500_set_register_interruptible(di->dev,
266862306a36Sopenharmony_ci				  AB8500_CHARGER, AB8500_CHARGER_CTRL, 0x01);
266962306a36Sopenharmony_ci
267062306a36Sopenharmony_ci	ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
267162306a36Sopenharmony_ci			AB8500_CH_USBCH_STAT2_REG, &reg_value);
267262306a36Sopenharmony_ci	if (ret < 0) {
267362306a36Sopenharmony_ci		dev_err(di->dev, "%s read failed\n", __func__);
267462306a36Sopenharmony_ci		return;
267562306a36Sopenharmony_ci	}
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	curr_ua = ab8500_charge_input_curr_map[
267862306a36Sopenharmony_ci		reg_value >> AUTO_VBUS_IN_CURR_LIM_SHIFT];
267962306a36Sopenharmony_ci
268062306a36Sopenharmony_ci	if (di->max_usb_in_curr.calculated_max_ua != curr_ua) {
268162306a36Sopenharmony_ci		/* USB source is collapsing */
268262306a36Sopenharmony_ci		di->max_usb_in_curr.calculated_max_ua = curr_ua;
268362306a36Sopenharmony_ci		dev_dbg(di->dev,
268462306a36Sopenharmony_ci			 "VBUS input current limiting to %d uA\n",
268562306a36Sopenharmony_ci			 di->max_usb_in_curr.calculated_max_ua);
268662306a36Sopenharmony_ci	} else {
268762306a36Sopenharmony_ci		/*
268862306a36Sopenharmony_ci		 * USB source can not give more than this amount.
268962306a36Sopenharmony_ci		 * Taking more will collapse the source.
269062306a36Sopenharmony_ci		 */
269162306a36Sopenharmony_ci		di->max_usb_in_curr.set_max_ua =
269262306a36Sopenharmony_ci			di->max_usb_in_curr.calculated_max_ua;
269362306a36Sopenharmony_ci		dev_dbg(di->dev,
269462306a36Sopenharmony_ci			 "VBUS input current limited to %d uA\n",
269562306a36Sopenharmony_ci			 di->max_usb_in_curr.set_max_ua);
269662306a36Sopenharmony_ci	}
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci	if (di->usb.charger_connected)
269962306a36Sopenharmony_ci		ab8500_charger_set_vbus_in_curr(di,
270062306a36Sopenharmony_ci					di->max_usb_in_curr.usb_type_max_ua);
270162306a36Sopenharmony_ci}
270262306a36Sopenharmony_ci
270362306a36Sopenharmony_ci/**
270462306a36Sopenharmony_ci * ab8500_charger_vbusdetf_handler() - VBUS falling detected
270562306a36Sopenharmony_ci * @irq:       interrupt number
270662306a36Sopenharmony_ci * @_di:       pointer to the ab8500_charger structure
270762306a36Sopenharmony_ci *
270862306a36Sopenharmony_ci * Returns IRQ status(IRQ_HANDLED)
270962306a36Sopenharmony_ci */
271062306a36Sopenharmony_cistatic irqreturn_t ab8500_charger_vbusdetf_handler(int irq, void *_di)
271162306a36Sopenharmony_ci{
271262306a36Sopenharmony_ci	struct ab8500_charger *di = _di;
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci	di->vbus_detected = false;
271562306a36Sopenharmony_ci	dev_dbg(di->dev, "VBUS falling detected\n");
271662306a36Sopenharmony_ci	queue_work(di->charger_wq, &di->detect_usb_type_work);
271762306a36Sopenharmony_ci
271862306a36Sopenharmony_ci	return IRQ_HANDLED;
271962306a36Sopenharmony_ci}
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci/**
272262306a36Sopenharmony_ci * ab8500_charger_vbusdetr_handler() - VBUS rising detected
272362306a36Sopenharmony_ci * @irq:       interrupt number
272462306a36Sopenharmony_ci * @_di:       pointer to the ab8500_charger structure
272562306a36Sopenharmony_ci *
272662306a36Sopenharmony_ci * Returns IRQ status(IRQ_HANDLED)
272762306a36Sopenharmony_ci */
272862306a36Sopenharmony_cistatic irqreturn_t ab8500_charger_vbusdetr_handler(int irq, void *_di)
272962306a36Sopenharmony_ci{
273062306a36Sopenharmony_ci	struct ab8500_charger *di = _di;
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ci	di->vbus_detected = true;
273362306a36Sopenharmony_ci	dev_dbg(di->dev, "VBUS rising detected\n");
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci	queue_work(di->charger_wq, &di->detect_usb_type_work);
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci	return IRQ_HANDLED;
273862306a36Sopenharmony_ci}
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci/**
274162306a36Sopenharmony_ci * ab8500_charger_usblinkstatus_handler() - USB link status has changed
274262306a36Sopenharmony_ci * @irq:       interrupt number
274362306a36Sopenharmony_ci * @_di:       pointer to the ab8500_charger structure
274462306a36Sopenharmony_ci *
274562306a36Sopenharmony_ci * Returns IRQ status(IRQ_HANDLED)
274662306a36Sopenharmony_ci */
274762306a36Sopenharmony_cistatic irqreturn_t ab8500_charger_usblinkstatus_handler(int irq, void *_di)
274862306a36Sopenharmony_ci{
274962306a36Sopenharmony_ci	struct ab8500_charger *di = _di;
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	dev_dbg(di->dev, "USB link status changed\n");
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ci	queue_work(di->charger_wq, &di->usb_link_status_work);
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ci	return IRQ_HANDLED;
275662306a36Sopenharmony_ci}
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci/**
275962306a36Sopenharmony_ci * ab8500_charger_usbchthprotr_handler() - Die temp is above usb charger
276062306a36Sopenharmony_ci * thermal protection threshold
276162306a36Sopenharmony_ci * @irq:       interrupt number
276262306a36Sopenharmony_ci * @_di:       pointer to the ab8500_charger structure
276362306a36Sopenharmony_ci *
276462306a36Sopenharmony_ci * Returns IRQ status(IRQ_HANDLED)
276562306a36Sopenharmony_ci */
276662306a36Sopenharmony_cistatic irqreturn_t ab8500_charger_usbchthprotr_handler(int irq, void *_di)
276762306a36Sopenharmony_ci{
276862306a36Sopenharmony_ci	struct ab8500_charger *di = _di;
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_ci	dev_dbg(di->dev,
277162306a36Sopenharmony_ci		"Die temp above USB charger thermal protection threshold\n");
277262306a36Sopenharmony_ci	queue_work(di->charger_wq, &di->check_usb_thermal_prot_work);
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci	return IRQ_HANDLED;
277562306a36Sopenharmony_ci}
277662306a36Sopenharmony_ci
277762306a36Sopenharmony_ci/**
277862306a36Sopenharmony_ci * ab8500_charger_usbchthprotf_handler() - Die temp is below usb charger
277962306a36Sopenharmony_ci * thermal protection threshold
278062306a36Sopenharmony_ci * @irq:       interrupt number
278162306a36Sopenharmony_ci * @_di:       pointer to the ab8500_charger structure
278262306a36Sopenharmony_ci *
278362306a36Sopenharmony_ci * Returns IRQ status(IRQ_HANDLED)
278462306a36Sopenharmony_ci */
278562306a36Sopenharmony_cistatic irqreturn_t ab8500_charger_usbchthprotf_handler(int irq, void *_di)
278662306a36Sopenharmony_ci{
278762306a36Sopenharmony_ci	struct ab8500_charger *di = _di;
278862306a36Sopenharmony_ci
278962306a36Sopenharmony_ci	dev_dbg(di->dev,
279062306a36Sopenharmony_ci		"Die temp ok for USB charger thermal protection threshold\n");
279162306a36Sopenharmony_ci	queue_work(di->charger_wq, &di->check_usb_thermal_prot_work);
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci	return IRQ_HANDLED;
279462306a36Sopenharmony_ci}
279562306a36Sopenharmony_ci
279662306a36Sopenharmony_ci/**
279762306a36Sopenharmony_ci * ab8500_charger_usbchargernotokr_handler() - USB charger not ok detected
279862306a36Sopenharmony_ci * @irq:       interrupt number
279962306a36Sopenharmony_ci * @_di:       pointer to the ab8500_charger structure
280062306a36Sopenharmony_ci *
280162306a36Sopenharmony_ci * Returns IRQ status(IRQ_HANDLED)
280262306a36Sopenharmony_ci */
280362306a36Sopenharmony_cistatic irqreturn_t ab8500_charger_usbchargernotokr_handler(int irq, void *_di)
280462306a36Sopenharmony_ci{
280562306a36Sopenharmony_ci	struct ab8500_charger *di = _di;
280662306a36Sopenharmony_ci
280762306a36Sopenharmony_ci	dev_dbg(di->dev, "Not allowed USB charger detected\n");
280862306a36Sopenharmony_ci	queue_delayed_work(di->charger_wq, &di->check_usbchgnotok_work, 0);
280962306a36Sopenharmony_ci
281062306a36Sopenharmony_ci	return IRQ_HANDLED;
281162306a36Sopenharmony_ci}
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci/**
281462306a36Sopenharmony_ci * ab8500_charger_chwdexp_handler() - Charger watchdog expired
281562306a36Sopenharmony_ci * @irq:       interrupt number
281662306a36Sopenharmony_ci * @_di:       pointer to the ab8500_charger structure
281762306a36Sopenharmony_ci *
281862306a36Sopenharmony_ci * Returns IRQ status(IRQ_HANDLED)
281962306a36Sopenharmony_ci */
282062306a36Sopenharmony_cistatic irqreturn_t ab8500_charger_chwdexp_handler(int irq, void *_di)
282162306a36Sopenharmony_ci{
282262306a36Sopenharmony_ci	struct ab8500_charger *di = _di;
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci	dev_dbg(di->dev, "Charger watchdog expired\n");
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci	/*
282762306a36Sopenharmony_ci	 * The charger that was online when the watchdog expired
282862306a36Sopenharmony_ci	 * needs to be restarted for charging to start again
282962306a36Sopenharmony_ci	 */
283062306a36Sopenharmony_ci	if (di->ac.charger_online) {
283162306a36Sopenharmony_ci		di->ac.wd_expired = true;
283262306a36Sopenharmony_ci		ab8500_power_supply_changed(di, di->ac_chg.psy);
283362306a36Sopenharmony_ci	}
283462306a36Sopenharmony_ci	if (di->usb.charger_online) {
283562306a36Sopenharmony_ci		di->usb.wd_expired = true;
283662306a36Sopenharmony_ci		ab8500_power_supply_changed(di, di->usb_chg.psy);
283762306a36Sopenharmony_ci	}
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci	return IRQ_HANDLED;
284062306a36Sopenharmony_ci}
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_ci/**
284362306a36Sopenharmony_ci * ab8500_charger_vbuschdropend_handler() - VBUS drop removed
284462306a36Sopenharmony_ci * @irq:       interrupt number
284562306a36Sopenharmony_ci * @_di:       pointer to the ab8500_charger structure
284662306a36Sopenharmony_ci *
284762306a36Sopenharmony_ci * Returns IRQ status(IRQ_HANDLED)
284862306a36Sopenharmony_ci */
284962306a36Sopenharmony_cistatic irqreturn_t ab8500_charger_vbuschdropend_handler(int irq, void *_di)
285062306a36Sopenharmony_ci{
285162306a36Sopenharmony_ci	struct ab8500_charger *di = _di;
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_ci	dev_dbg(di->dev, "VBUS charger drop ended\n");
285462306a36Sopenharmony_ci	di->flags.vbus_drop_end = true;
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci	/*
285762306a36Sopenharmony_ci	 * VBUS might have dropped due to bad connection.
285862306a36Sopenharmony_ci	 * Schedule a new input limit set to the value SW requests.
285962306a36Sopenharmony_ci	 */
286062306a36Sopenharmony_ci	queue_delayed_work(di->charger_wq, &di->vbus_drop_end_work,
286162306a36Sopenharmony_ci			   round_jiffies(VBUS_IN_CURR_LIM_RETRY_SET_TIME * HZ));
286262306a36Sopenharmony_ci
286362306a36Sopenharmony_ci	return IRQ_HANDLED;
286462306a36Sopenharmony_ci}
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_ci/**
286762306a36Sopenharmony_ci * ab8500_charger_vbusovv_handler() - VBUS overvoltage detected
286862306a36Sopenharmony_ci * @irq:       interrupt number
286962306a36Sopenharmony_ci * @_di:       pointer to the ab8500_charger structure
287062306a36Sopenharmony_ci *
287162306a36Sopenharmony_ci * Returns IRQ status(IRQ_HANDLED)
287262306a36Sopenharmony_ci */
287362306a36Sopenharmony_cistatic irqreturn_t ab8500_charger_vbusovv_handler(int irq, void *_di)
287462306a36Sopenharmony_ci{
287562306a36Sopenharmony_ci	struct ab8500_charger *di = _di;
287662306a36Sopenharmony_ci
287762306a36Sopenharmony_ci	dev_dbg(di->dev, "VBUS overvoltage detected\n");
287862306a36Sopenharmony_ci	di->flags.vbus_ovv = true;
287962306a36Sopenharmony_ci	ab8500_power_supply_changed(di, di->usb_chg.psy);
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ci	/* Schedule a new HW failure check */
288262306a36Sopenharmony_ci	queue_delayed_work(di->charger_wq, &di->check_hw_failure_work, 0);
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci	return IRQ_HANDLED;
288562306a36Sopenharmony_ci}
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci/**
288862306a36Sopenharmony_ci * ab8500_charger_ac_get_property() - get the ac/mains properties
288962306a36Sopenharmony_ci * @psy:       pointer to the power_supply structure
289062306a36Sopenharmony_ci * @psp:       pointer to the power_supply_property structure
289162306a36Sopenharmony_ci * @val:       pointer to the power_supply_propval union
289262306a36Sopenharmony_ci *
289362306a36Sopenharmony_ci * This function gets called when an application tries to get the ac/mains
289462306a36Sopenharmony_ci * properties by reading the sysfs files.
289562306a36Sopenharmony_ci * AC/Mains properties are online, present and voltage.
289662306a36Sopenharmony_ci * online:     ac/mains charging is in progress or not
289762306a36Sopenharmony_ci * present:    presence of the ac/mains
289862306a36Sopenharmony_ci * voltage:    AC/Mains voltage
289962306a36Sopenharmony_ci * Returns error code in case of failure else 0(on success)
290062306a36Sopenharmony_ci */
290162306a36Sopenharmony_cistatic int ab8500_charger_ac_get_property(struct power_supply *psy,
290262306a36Sopenharmony_ci	enum power_supply_property psp,
290362306a36Sopenharmony_ci	union power_supply_propval *val)
290462306a36Sopenharmony_ci{
290562306a36Sopenharmony_ci	struct ab8500_charger *di;
290662306a36Sopenharmony_ci	int ret;
290762306a36Sopenharmony_ci
290862306a36Sopenharmony_ci	di = to_ab8500_charger_ac_device_info(psy_to_ux500_charger(psy));
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci	switch (psp) {
291162306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_HEALTH:
291262306a36Sopenharmony_ci		if (di->flags.mainextchnotok)
291362306a36Sopenharmony_ci			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
291462306a36Sopenharmony_ci		else if (di->ac.wd_expired || di->usb.wd_expired)
291562306a36Sopenharmony_ci			val->intval = POWER_SUPPLY_HEALTH_DEAD;
291662306a36Sopenharmony_ci		else if (di->flags.main_thermal_prot)
291762306a36Sopenharmony_ci			val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
291862306a36Sopenharmony_ci		else
291962306a36Sopenharmony_ci			val->intval = POWER_SUPPLY_HEALTH_GOOD;
292062306a36Sopenharmony_ci		break;
292162306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_ONLINE:
292262306a36Sopenharmony_ci		val->intval = di->ac.charger_online;
292362306a36Sopenharmony_ci		break;
292462306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_PRESENT:
292562306a36Sopenharmony_ci		val->intval = di->ac.charger_connected;
292662306a36Sopenharmony_ci		break;
292762306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
292862306a36Sopenharmony_ci		ret = ab8500_charger_get_ac_voltage(di);
292962306a36Sopenharmony_ci		if (ret >= 0)
293062306a36Sopenharmony_ci			di->ac.charger_voltage_uv = ret;
293162306a36Sopenharmony_ci		/* On error, use previous value */
293262306a36Sopenharmony_ci		val->intval = di->ac.charger_voltage_uv;
293362306a36Sopenharmony_ci		break;
293462306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
293562306a36Sopenharmony_ci		/*
293662306a36Sopenharmony_ci		 * This property is used to indicate when CV mode is entered
293762306a36Sopenharmony_ci		 * for the AC charger
293862306a36Sopenharmony_ci		 */
293962306a36Sopenharmony_ci		di->ac.cv_active = ab8500_charger_ac_cv(di);
294062306a36Sopenharmony_ci		val->intval = di->ac.cv_active;
294162306a36Sopenharmony_ci		break;
294262306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_NOW:
294362306a36Sopenharmony_ci		ret = ab8500_charger_get_ac_current(di);
294462306a36Sopenharmony_ci		if (ret >= 0)
294562306a36Sopenharmony_ci			di->ac.charger_current_ua = ret;
294662306a36Sopenharmony_ci		val->intval = di->ac.charger_current_ua;
294762306a36Sopenharmony_ci		break;
294862306a36Sopenharmony_ci	default:
294962306a36Sopenharmony_ci		return -EINVAL;
295062306a36Sopenharmony_ci	}
295162306a36Sopenharmony_ci	return 0;
295262306a36Sopenharmony_ci}
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci/**
295562306a36Sopenharmony_ci * ab8500_charger_usb_get_property() - get the usb properties
295662306a36Sopenharmony_ci * @psy:        pointer to the power_supply structure
295762306a36Sopenharmony_ci * @psp:        pointer to the power_supply_property structure
295862306a36Sopenharmony_ci * @val:        pointer to the power_supply_propval union
295962306a36Sopenharmony_ci *
296062306a36Sopenharmony_ci * This function gets called when an application tries to get the usb
296162306a36Sopenharmony_ci * properties by reading the sysfs files.
296262306a36Sopenharmony_ci * USB properties are online, present and voltage.
296362306a36Sopenharmony_ci * online:     usb charging is in progress or not
296462306a36Sopenharmony_ci * present:    presence of the usb
296562306a36Sopenharmony_ci * voltage:    vbus voltage
296662306a36Sopenharmony_ci * Returns error code in case of failure else 0(on success)
296762306a36Sopenharmony_ci */
296862306a36Sopenharmony_cistatic int ab8500_charger_usb_get_property(struct power_supply *psy,
296962306a36Sopenharmony_ci	enum power_supply_property psp,
297062306a36Sopenharmony_ci	union power_supply_propval *val)
297162306a36Sopenharmony_ci{
297262306a36Sopenharmony_ci	struct ab8500_charger *di;
297362306a36Sopenharmony_ci	int ret;
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_ci	di = to_ab8500_charger_usb_device_info(psy_to_ux500_charger(psy));
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_ci	switch (psp) {
297862306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_HEALTH:
297962306a36Sopenharmony_ci		if (di->flags.usbchargernotok)
298062306a36Sopenharmony_ci			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
298162306a36Sopenharmony_ci		else if (di->ac.wd_expired || di->usb.wd_expired)
298262306a36Sopenharmony_ci			val->intval = POWER_SUPPLY_HEALTH_DEAD;
298362306a36Sopenharmony_ci		else if (di->flags.usb_thermal_prot)
298462306a36Sopenharmony_ci			val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
298562306a36Sopenharmony_ci		else if (di->flags.vbus_ovv)
298662306a36Sopenharmony_ci			val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
298762306a36Sopenharmony_ci		else
298862306a36Sopenharmony_ci			val->intval = POWER_SUPPLY_HEALTH_GOOD;
298962306a36Sopenharmony_ci		break;
299062306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_ONLINE:
299162306a36Sopenharmony_ci		val->intval = di->usb.charger_online;
299262306a36Sopenharmony_ci		break;
299362306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_PRESENT:
299462306a36Sopenharmony_ci		val->intval = di->usb.charger_connected;
299562306a36Sopenharmony_ci		break;
299662306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
299762306a36Sopenharmony_ci		ret = ab8500_charger_get_vbus_voltage(di);
299862306a36Sopenharmony_ci		if (ret >= 0)
299962306a36Sopenharmony_ci			di->usb.charger_voltage_uv = ret;
300062306a36Sopenharmony_ci		val->intval = di->usb.charger_voltage_uv;
300162306a36Sopenharmony_ci		break;
300262306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
300362306a36Sopenharmony_ci		/*
300462306a36Sopenharmony_ci		 * This property is used to indicate when CV mode is entered
300562306a36Sopenharmony_ci		 * for the USB charger
300662306a36Sopenharmony_ci		 */
300762306a36Sopenharmony_ci		di->usb.cv_active = ab8500_charger_usb_cv(di);
300862306a36Sopenharmony_ci		val->intval = di->usb.cv_active;
300962306a36Sopenharmony_ci		break;
301062306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_NOW:
301162306a36Sopenharmony_ci		ret = ab8500_charger_get_usb_current(di);
301262306a36Sopenharmony_ci		if (ret >= 0)
301362306a36Sopenharmony_ci			di->usb.charger_current_ua = ret;
301462306a36Sopenharmony_ci		val->intval = di->usb.charger_current_ua;
301562306a36Sopenharmony_ci		break;
301662306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_AVG:
301762306a36Sopenharmony_ci		/*
301862306a36Sopenharmony_ci		 * This property is used to indicate when VBUS has collapsed
301962306a36Sopenharmony_ci		 * due to too high output current from the USB charger
302062306a36Sopenharmony_ci		 */
302162306a36Sopenharmony_ci		if (di->flags.vbus_collapse)
302262306a36Sopenharmony_ci			val->intval = 1;
302362306a36Sopenharmony_ci		else
302462306a36Sopenharmony_ci			val->intval = 0;
302562306a36Sopenharmony_ci		break;
302662306a36Sopenharmony_ci	default:
302762306a36Sopenharmony_ci		return -EINVAL;
302862306a36Sopenharmony_ci	}
302962306a36Sopenharmony_ci	return 0;
303062306a36Sopenharmony_ci}
303162306a36Sopenharmony_ci
303262306a36Sopenharmony_ci/**
303362306a36Sopenharmony_ci * ab8500_charger_init_hw_registers() - Set up charger related registers
303462306a36Sopenharmony_ci * @di:		pointer to the ab8500_charger structure
303562306a36Sopenharmony_ci *
303662306a36Sopenharmony_ci * Set up charger OVV, watchdog and maximum voltage registers as well as
303762306a36Sopenharmony_ci * charging of the backup battery
303862306a36Sopenharmony_ci */
303962306a36Sopenharmony_cistatic int ab8500_charger_init_hw_registers(struct ab8500_charger *di)
304062306a36Sopenharmony_ci{
304162306a36Sopenharmony_ci	int ret = 0;
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_ci	/* Setup maximum charger current and voltage for ABB cut2.0 */
304462306a36Sopenharmony_ci	if (!is_ab8500_1p1_or_earlier(di->parent)) {
304562306a36Sopenharmony_ci		ret = abx500_set_register_interruptible(di->dev,
304662306a36Sopenharmony_ci			AB8500_CHARGER,
304762306a36Sopenharmony_ci			AB8500_CH_VOLT_LVL_MAX_REG, CH_VOL_LVL_4P6);
304862306a36Sopenharmony_ci		if (ret) {
304962306a36Sopenharmony_ci			dev_err(di->dev,
305062306a36Sopenharmony_ci				"failed to set CH_VOLT_LVL_MAX_REG\n");
305162306a36Sopenharmony_ci			goto out;
305262306a36Sopenharmony_ci		}
305362306a36Sopenharmony_ci
305462306a36Sopenharmony_ci		ret = abx500_set_register_interruptible(di->dev,
305562306a36Sopenharmony_ci			AB8500_CHARGER, AB8500_CH_OPT_CRNTLVL_MAX_REG,
305662306a36Sopenharmony_ci			CH_OP_CUR_LVL_1P6);
305762306a36Sopenharmony_ci		if (ret) {
305862306a36Sopenharmony_ci			dev_err(di->dev,
305962306a36Sopenharmony_ci				"failed to set CH_OPT_CRNTLVL_MAX_REG\n");
306062306a36Sopenharmony_ci			goto out;
306162306a36Sopenharmony_ci		}
306262306a36Sopenharmony_ci	}
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_ci	if (is_ab8505_2p0(di->parent))
306562306a36Sopenharmony_ci		ret = abx500_mask_and_set_register_interruptible(di->dev,
306662306a36Sopenharmony_ci			AB8500_CHARGER,
306762306a36Sopenharmony_ci			AB8500_USBCH_CTRL2_REG,
306862306a36Sopenharmony_ci			VBUS_AUTO_IN_CURR_LIM_ENA,
306962306a36Sopenharmony_ci			VBUS_AUTO_IN_CURR_LIM_ENA);
307062306a36Sopenharmony_ci	else
307162306a36Sopenharmony_ci		/*
307262306a36Sopenharmony_ci		 * VBUS OVV set to 6.3V and enable automatic current limitation
307362306a36Sopenharmony_ci		 */
307462306a36Sopenharmony_ci		ret = abx500_set_register_interruptible(di->dev,
307562306a36Sopenharmony_ci			AB8500_CHARGER,
307662306a36Sopenharmony_ci			AB8500_USBCH_CTRL2_REG,
307762306a36Sopenharmony_ci			VBUS_OVV_SELECT_6P3V | VBUS_AUTO_IN_CURR_LIM_ENA);
307862306a36Sopenharmony_ci	if (ret) {
307962306a36Sopenharmony_ci		dev_err(di->dev,
308062306a36Sopenharmony_ci			"failed to set automatic current limitation\n");
308162306a36Sopenharmony_ci		goto out;
308262306a36Sopenharmony_ci	}
308362306a36Sopenharmony_ci
308462306a36Sopenharmony_ci	/* Enable main watchdog in OTP */
308562306a36Sopenharmony_ci	ret = abx500_set_register_interruptible(di->dev,
308662306a36Sopenharmony_ci		AB8500_OTP_EMUL, AB8500_OTP_CONF_15, OTP_ENABLE_WD);
308762306a36Sopenharmony_ci	if (ret) {
308862306a36Sopenharmony_ci		dev_err(di->dev, "failed to enable main WD in OTP\n");
308962306a36Sopenharmony_ci		goto out;
309062306a36Sopenharmony_ci	}
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_ci	/* Enable main watchdog */
309362306a36Sopenharmony_ci	ret = abx500_set_register_interruptible(di->dev,
309462306a36Sopenharmony_ci		AB8500_SYS_CTRL2_BLOCK,
309562306a36Sopenharmony_ci		AB8500_MAIN_WDOG_CTRL_REG, MAIN_WDOG_ENA);
309662306a36Sopenharmony_ci	if (ret) {
309762306a36Sopenharmony_ci		dev_err(di->dev, "failed to enable main watchdog\n");
309862306a36Sopenharmony_ci		goto out;
309962306a36Sopenharmony_ci	}
310062306a36Sopenharmony_ci
310162306a36Sopenharmony_ci	/*
310262306a36Sopenharmony_ci	 * Due to internal synchronisation, Enable and Kick watchdog bits
310362306a36Sopenharmony_ci	 * cannot be enabled in a single write.
310462306a36Sopenharmony_ci	 * A minimum delay of 2*32 kHz period (62.5µs) must be inserted
310562306a36Sopenharmony_ci	 * between writing Enable then Kick bits.
310662306a36Sopenharmony_ci	 */
310762306a36Sopenharmony_ci	udelay(63);
310862306a36Sopenharmony_ci
310962306a36Sopenharmony_ci	/* Kick main watchdog */
311062306a36Sopenharmony_ci	ret = abx500_set_register_interruptible(di->dev,
311162306a36Sopenharmony_ci		AB8500_SYS_CTRL2_BLOCK,
311262306a36Sopenharmony_ci		AB8500_MAIN_WDOG_CTRL_REG,
311362306a36Sopenharmony_ci		(MAIN_WDOG_ENA | MAIN_WDOG_KICK));
311462306a36Sopenharmony_ci	if (ret) {
311562306a36Sopenharmony_ci		dev_err(di->dev, "failed to kick main watchdog\n");
311662306a36Sopenharmony_ci		goto out;
311762306a36Sopenharmony_ci	}
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci	/* Disable main watchdog */
312062306a36Sopenharmony_ci	ret = abx500_set_register_interruptible(di->dev,
312162306a36Sopenharmony_ci		AB8500_SYS_CTRL2_BLOCK,
312262306a36Sopenharmony_ci		AB8500_MAIN_WDOG_CTRL_REG, MAIN_WDOG_DIS);
312362306a36Sopenharmony_ci	if (ret) {
312462306a36Sopenharmony_ci		dev_err(di->dev, "failed to disable main watchdog\n");
312562306a36Sopenharmony_ci		goto out;
312662306a36Sopenharmony_ci	}
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_ci	/* Set watchdog timeout */
312962306a36Sopenharmony_ci	ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
313062306a36Sopenharmony_ci		AB8500_CH_WD_TIMER_REG, WD_TIMER);
313162306a36Sopenharmony_ci	if (ret) {
313262306a36Sopenharmony_ci		dev_err(di->dev, "failed to set charger watchdog timeout\n");
313362306a36Sopenharmony_ci		goto out;
313462306a36Sopenharmony_ci	}
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci	ret = ab8500_charger_led_en(di, false);
313762306a36Sopenharmony_ci	if (ret < 0) {
313862306a36Sopenharmony_ci		dev_err(di->dev, "failed to disable LED\n");
313962306a36Sopenharmony_ci		goto out;
314062306a36Sopenharmony_ci	}
314162306a36Sopenharmony_ci
314262306a36Sopenharmony_ci	ret = abx500_set_register_interruptible(di->dev,
314362306a36Sopenharmony_ci		AB8500_RTC,
314462306a36Sopenharmony_ci		AB8500_RTC_BACKUP_CHG_REG,
314562306a36Sopenharmony_ci		(di->bm->bkup_bat_v & 0x3) | di->bm->bkup_bat_i);
314662306a36Sopenharmony_ci	if (ret) {
314762306a36Sopenharmony_ci		dev_err(di->dev, "failed to setup backup battery charging\n");
314862306a36Sopenharmony_ci		goto out;
314962306a36Sopenharmony_ci	}
315062306a36Sopenharmony_ci
315162306a36Sopenharmony_ci	/* Enable backup battery charging */
315262306a36Sopenharmony_ci	ret = abx500_mask_and_set_register_interruptible(di->dev,
315362306a36Sopenharmony_ci		AB8500_RTC, AB8500_RTC_CTRL_REG,
315462306a36Sopenharmony_ci		RTC_BUP_CH_ENA, RTC_BUP_CH_ENA);
315562306a36Sopenharmony_ci	if (ret < 0) {
315662306a36Sopenharmony_ci		dev_err(di->dev, "%s mask and set failed\n", __func__);
315762306a36Sopenharmony_ci		goto out;
315862306a36Sopenharmony_ci	}
315962306a36Sopenharmony_ci
316062306a36Sopenharmony_ciout:
316162306a36Sopenharmony_ci	return ret;
316262306a36Sopenharmony_ci}
316362306a36Sopenharmony_ci
316462306a36Sopenharmony_ci/*
316562306a36Sopenharmony_ci * ab8500 charger driver interrupts and their respective isr
316662306a36Sopenharmony_ci */
316762306a36Sopenharmony_cistatic struct ab8500_charger_interrupts ab8500_charger_irq[] = {
316862306a36Sopenharmony_ci	{"MAIN_CH_UNPLUG_DET", ab8500_charger_mainchunplugdet_handler},
316962306a36Sopenharmony_ci	{"MAIN_CHARGE_PLUG_DET", ab8500_charger_mainchplugdet_handler},
317062306a36Sopenharmony_ci	{"MAIN_EXT_CH_NOT_OK", ab8500_charger_mainextchnotok_handler},
317162306a36Sopenharmony_ci	{"MAIN_CH_TH_PROT_R", ab8500_charger_mainchthprotr_handler},
317262306a36Sopenharmony_ci	{"MAIN_CH_TH_PROT_F", ab8500_charger_mainchthprotf_handler},
317362306a36Sopenharmony_ci	{"VBUS_DET_F", ab8500_charger_vbusdetf_handler},
317462306a36Sopenharmony_ci	{"VBUS_DET_R", ab8500_charger_vbusdetr_handler},
317562306a36Sopenharmony_ci	{"USB_LINK_STATUS", ab8500_charger_usblinkstatus_handler},
317662306a36Sopenharmony_ci	{"USB_CH_TH_PROT_R", ab8500_charger_usbchthprotr_handler},
317762306a36Sopenharmony_ci	{"USB_CH_TH_PROT_F", ab8500_charger_usbchthprotf_handler},
317862306a36Sopenharmony_ci	{"USB_CHARGER_NOT_OKR", ab8500_charger_usbchargernotokr_handler},
317962306a36Sopenharmony_ci	{"VBUS_OVV", ab8500_charger_vbusovv_handler},
318062306a36Sopenharmony_ci	{"CH_WD_EXP", ab8500_charger_chwdexp_handler},
318162306a36Sopenharmony_ci	{"VBUS_CH_DROP_END", ab8500_charger_vbuschdropend_handler},
318262306a36Sopenharmony_ci};
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_cistatic int ab8500_charger_usb_notifier_call(struct notifier_block *nb,
318562306a36Sopenharmony_ci		unsigned long event, void *power)
318662306a36Sopenharmony_ci{
318762306a36Sopenharmony_ci	struct ab8500_charger *di =
318862306a36Sopenharmony_ci		container_of(nb, struct ab8500_charger, nb);
318962306a36Sopenharmony_ci	enum ab8500_usb_state bm_usb_state;
319062306a36Sopenharmony_ci	/*
319162306a36Sopenharmony_ci	 * FIXME: it appears the AB8500 PHY never sends what it should here.
319262306a36Sopenharmony_ci	 * Fix the PHY driver to properly notify the desired current.
319362306a36Sopenharmony_ci	 * Also broadcast microampere and not milliampere.
319462306a36Sopenharmony_ci	 */
319562306a36Sopenharmony_ci	unsigned mA = *((unsigned *)power);
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci	if (event != USB_EVENT_VBUS) {
319862306a36Sopenharmony_ci		dev_dbg(di->dev, "not a standard host, returning\n");
319962306a36Sopenharmony_ci		return NOTIFY_DONE;
320062306a36Sopenharmony_ci	}
320162306a36Sopenharmony_ci
320262306a36Sopenharmony_ci	/* TODO: State is fabricate  here. See if charger really needs USB
320362306a36Sopenharmony_ci	 * state or if mA is enough
320462306a36Sopenharmony_ci	 */
320562306a36Sopenharmony_ci	if ((di->usb_state.usb_current_ua == 2000) && (mA > 2))
320662306a36Sopenharmony_ci		bm_usb_state = AB8500_BM_USB_STATE_RESUME;
320762306a36Sopenharmony_ci	else if (mA == 0)
320862306a36Sopenharmony_ci		bm_usb_state = AB8500_BM_USB_STATE_RESET_HS;
320962306a36Sopenharmony_ci	else if (mA == 2)
321062306a36Sopenharmony_ci		bm_usb_state = AB8500_BM_USB_STATE_SUSPEND;
321162306a36Sopenharmony_ci	else if (mA >= 8) /* 8, 100, 500 */
321262306a36Sopenharmony_ci		bm_usb_state = AB8500_BM_USB_STATE_CONFIGURED;
321362306a36Sopenharmony_ci	else /* Should never occur */
321462306a36Sopenharmony_ci		bm_usb_state = AB8500_BM_USB_STATE_RESET_FS;
321562306a36Sopenharmony_ci
321662306a36Sopenharmony_ci	dev_dbg(di->dev, "%s usb_state: 0x%02x mA: %d\n",
321762306a36Sopenharmony_ci		__func__, bm_usb_state, mA);
321862306a36Sopenharmony_ci
321962306a36Sopenharmony_ci	spin_lock(&di->usb_state.usb_lock);
322062306a36Sopenharmony_ci	di->usb_state.state_tmp = bm_usb_state;
322162306a36Sopenharmony_ci	/* FIXME: broadcast ua instead, see above */
322262306a36Sopenharmony_ci	di->usb_state.usb_current_tmp_ua = mA * 1000;
322362306a36Sopenharmony_ci	spin_unlock(&di->usb_state.usb_lock);
322462306a36Sopenharmony_ci
322562306a36Sopenharmony_ci	/*
322662306a36Sopenharmony_ci	 * wait for some time until you get updates from the usb stack
322762306a36Sopenharmony_ci	 * and negotiations are completed
322862306a36Sopenharmony_ci	 */
322962306a36Sopenharmony_ci	queue_delayed_work(di->charger_wq, &di->usb_state_changed_work, HZ/2);
323062306a36Sopenharmony_ci
323162306a36Sopenharmony_ci	return NOTIFY_OK;
323262306a36Sopenharmony_ci}
323362306a36Sopenharmony_ci
323462306a36Sopenharmony_cistatic int __maybe_unused ab8500_charger_resume(struct device *dev)
323562306a36Sopenharmony_ci{
323662306a36Sopenharmony_ci	int ret;
323762306a36Sopenharmony_ci	struct ab8500_charger *di = dev_get_drvdata(dev);
323862306a36Sopenharmony_ci
323962306a36Sopenharmony_ci	/*
324062306a36Sopenharmony_ci	 * For ABB revision 1.0 and 1.1 there is a bug in the watchdog
324162306a36Sopenharmony_ci	 * logic. That means we have to continuously kick the charger
324262306a36Sopenharmony_ci	 * watchdog even when no charger is connected. This is only
324362306a36Sopenharmony_ci	 * valid once the AC charger has been enabled. This is
324462306a36Sopenharmony_ci	 * a bug that is not handled by the algorithm and the
324562306a36Sopenharmony_ci	 * watchdog have to be kicked by the charger driver
324662306a36Sopenharmony_ci	 * when the AC charger is disabled
324762306a36Sopenharmony_ci	 */
324862306a36Sopenharmony_ci	if (di->ac_conn && is_ab8500_1p1_or_earlier(di->parent)) {
324962306a36Sopenharmony_ci		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
325062306a36Sopenharmony_ci			AB8500_CHARG_WD_CTRL, CHARG_WD_KICK);
325162306a36Sopenharmony_ci		if (ret)
325262306a36Sopenharmony_ci			dev_err(di->dev, "Failed to kick WD!\n");
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci		/* If not already pending start a new timer */
325562306a36Sopenharmony_ci		queue_delayed_work(di->charger_wq, &di->kick_wd_work,
325662306a36Sopenharmony_ci				   round_jiffies(WD_KICK_INTERVAL));
325762306a36Sopenharmony_ci	}
325862306a36Sopenharmony_ci
325962306a36Sopenharmony_ci	/* If we still have a HW failure, schedule a new check */
326062306a36Sopenharmony_ci	if (di->flags.mainextchnotok || di->flags.vbus_ovv) {
326162306a36Sopenharmony_ci		queue_delayed_work(di->charger_wq,
326262306a36Sopenharmony_ci			&di->check_hw_failure_work, 0);
326362306a36Sopenharmony_ci	}
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_ci	if (di->flags.vbus_drop_end)
326662306a36Sopenharmony_ci		queue_delayed_work(di->charger_wq, &di->vbus_drop_end_work, 0);
326762306a36Sopenharmony_ci
326862306a36Sopenharmony_ci	return 0;
326962306a36Sopenharmony_ci}
327062306a36Sopenharmony_ci
327162306a36Sopenharmony_cistatic int __maybe_unused ab8500_charger_suspend(struct device *dev)
327262306a36Sopenharmony_ci{
327362306a36Sopenharmony_ci	struct ab8500_charger *di = dev_get_drvdata(dev);
327462306a36Sopenharmony_ci
327562306a36Sopenharmony_ci	/* Cancel any pending jobs */
327662306a36Sopenharmony_ci	cancel_delayed_work(&di->check_hw_failure_work);
327762306a36Sopenharmony_ci	cancel_delayed_work(&di->vbus_drop_end_work);
327862306a36Sopenharmony_ci
327962306a36Sopenharmony_ci	flush_delayed_work(&di->attach_work);
328062306a36Sopenharmony_ci	flush_delayed_work(&di->usb_charger_attached_work);
328162306a36Sopenharmony_ci	flush_delayed_work(&di->ac_charger_attached_work);
328262306a36Sopenharmony_ci	flush_delayed_work(&di->check_usbchgnotok_work);
328362306a36Sopenharmony_ci	flush_delayed_work(&di->check_vbat_work);
328462306a36Sopenharmony_ci	flush_delayed_work(&di->kick_wd_work);
328562306a36Sopenharmony_ci
328662306a36Sopenharmony_ci	flush_work(&di->usb_link_status_work);
328762306a36Sopenharmony_ci	flush_work(&di->ac_work);
328862306a36Sopenharmony_ci	flush_work(&di->detect_usb_type_work);
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci	if (atomic_read(&di->current_stepping_sessions))
329162306a36Sopenharmony_ci		return -EAGAIN;
329262306a36Sopenharmony_ci
329362306a36Sopenharmony_ci	return 0;
329462306a36Sopenharmony_ci}
329562306a36Sopenharmony_ci
329662306a36Sopenharmony_cistatic char *supply_interface[] = {
329762306a36Sopenharmony_ci	"ab8500_chargalg",
329862306a36Sopenharmony_ci	"ab8500_fg",
329962306a36Sopenharmony_ci	"ab8500_btemp",
330062306a36Sopenharmony_ci};
330162306a36Sopenharmony_ci
330262306a36Sopenharmony_cistatic const struct power_supply_desc ab8500_ac_chg_desc = {
330362306a36Sopenharmony_ci	.name		= "ab8500_ac",
330462306a36Sopenharmony_ci	.type		= POWER_SUPPLY_TYPE_MAINS,
330562306a36Sopenharmony_ci	.properties	= ab8500_charger_ac_props,
330662306a36Sopenharmony_ci	.num_properties	= ARRAY_SIZE(ab8500_charger_ac_props),
330762306a36Sopenharmony_ci	.get_property	= ab8500_charger_ac_get_property,
330862306a36Sopenharmony_ci};
330962306a36Sopenharmony_ci
331062306a36Sopenharmony_cistatic const struct power_supply_desc ab8500_usb_chg_desc = {
331162306a36Sopenharmony_ci	.name		= "ab8500_usb",
331262306a36Sopenharmony_ci	.type		= POWER_SUPPLY_TYPE_USB,
331362306a36Sopenharmony_ci	.properties	= ab8500_charger_usb_props,
331462306a36Sopenharmony_ci	.num_properties	= ARRAY_SIZE(ab8500_charger_usb_props),
331562306a36Sopenharmony_ci	.get_property	= ab8500_charger_usb_get_property,
331662306a36Sopenharmony_ci};
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_cistatic int ab8500_charger_bind(struct device *dev)
331962306a36Sopenharmony_ci{
332062306a36Sopenharmony_ci	struct ab8500_charger *di = dev_get_drvdata(dev);
332162306a36Sopenharmony_ci	int ch_stat;
332262306a36Sopenharmony_ci	int ret;
332362306a36Sopenharmony_ci
332462306a36Sopenharmony_ci	/* Create a work queue for the charger */
332562306a36Sopenharmony_ci	di->charger_wq = alloc_ordered_workqueue("ab8500_charger_wq",
332662306a36Sopenharmony_ci						 WQ_MEM_RECLAIM);
332762306a36Sopenharmony_ci	if (di->charger_wq == NULL) {
332862306a36Sopenharmony_ci		dev_err(dev, "failed to create work queue\n");
332962306a36Sopenharmony_ci		return -ENOMEM;
333062306a36Sopenharmony_ci	}
333162306a36Sopenharmony_ci
333262306a36Sopenharmony_ci	ch_stat = ab8500_charger_detect_chargers(di, false);
333362306a36Sopenharmony_ci
333462306a36Sopenharmony_ci	if (ch_stat & AC_PW_CONN) {
333562306a36Sopenharmony_ci		if (is_ab8500(di->parent))
333662306a36Sopenharmony_ci			queue_delayed_work(di->charger_wq,
333762306a36Sopenharmony_ci					   &di->ac_charger_attached_work,
333862306a36Sopenharmony_ci					   HZ);
333962306a36Sopenharmony_ci	}
334062306a36Sopenharmony_ci	if (ch_stat & USB_PW_CONN) {
334162306a36Sopenharmony_ci		if (is_ab8500(di->parent))
334262306a36Sopenharmony_ci			queue_delayed_work(di->charger_wq,
334362306a36Sopenharmony_ci					   &di->usb_charger_attached_work,
334462306a36Sopenharmony_ci					   HZ);
334562306a36Sopenharmony_ci		di->vbus_detected = true;
334662306a36Sopenharmony_ci		di->vbus_detected_start = true;
334762306a36Sopenharmony_ci		queue_work(di->charger_wq,
334862306a36Sopenharmony_ci			   &di->detect_usb_type_work);
334962306a36Sopenharmony_ci	}
335062306a36Sopenharmony_ci
335162306a36Sopenharmony_ci	ret = component_bind_all(dev, di);
335262306a36Sopenharmony_ci	if (ret) {
335362306a36Sopenharmony_ci		dev_err(dev, "can't bind component devices\n");
335462306a36Sopenharmony_ci		destroy_workqueue(di->charger_wq);
335562306a36Sopenharmony_ci		return ret;
335662306a36Sopenharmony_ci	}
335762306a36Sopenharmony_ci
335862306a36Sopenharmony_ci	return 0;
335962306a36Sopenharmony_ci}
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_cistatic void ab8500_charger_unbind(struct device *dev)
336262306a36Sopenharmony_ci{
336362306a36Sopenharmony_ci	struct ab8500_charger *di = dev_get_drvdata(dev);
336462306a36Sopenharmony_ci	int ret;
336562306a36Sopenharmony_ci
336662306a36Sopenharmony_ci	/* Disable AC charging */
336762306a36Sopenharmony_ci	ab8500_charger_ac_en(&di->ac_chg, false, 0, 0);
336862306a36Sopenharmony_ci
336962306a36Sopenharmony_ci	/* Disable USB charging */
337062306a36Sopenharmony_ci	ab8500_charger_usb_en(&di->usb_chg, false, 0, 0);
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_ci	/* Backup battery voltage and current disable */
337362306a36Sopenharmony_ci	ret = abx500_mask_and_set_register_interruptible(di->dev,
337462306a36Sopenharmony_ci		AB8500_RTC, AB8500_RTC_CTRL_REG, RTC_BUP_CH_ENA, 0);
337562306a36Sopenharmony_ci	if (ret < 0)
337662306a36Sopenharmony_ci		dev_err(di->dev, "%s mask and set failed\n", __func__);
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_ci	/* Delete the work queue */
337962306a36Sopenharmony_ci	destroy_workqueue(di->charger_wq);
338062306a36Sopenharmony_ci
338162306a36Sopenharmony_ci	/* Unbind fg, btemp, algorithm */
338262306a36Sopenharmony_ci	component_unbind_all(dev, di);
338362306a36Sopenharmony_ci}
338462306a36Sopenharmony_ci
338562306a36Sopenharmony_cistatic const struct component_master_ops ab8500_charger_comp_ops = {
338662306a36Sopenharmony_ci	.bind = ab8500_charger_bind,
338762306a36Sopenharmony_ci	.unbind = ab8500_charger_unbind,
338862306a36Sopenharmony_ci};
338962306a36Sopenharmony_ci
339062306a36Sopenharmony_cistatic struct platform_driver *const ab8500_charger_component_drivers[] = {
339162306a36Sopenharmony_ci	&ab8500_fg_driver,
339262306a36Sopenharmony_ci	&ab8500_btemp_driver,
339362306a36Sopenharmony_ci	&ab8500_chargalg_driver,
339462306a36Sopenharmony_ci};
339562306a36Sopenharmony_ci
339662306a36Sopenharmony_cistatic int ab8500_charger_probe(struct platform_device *pdev)
339762306a36Sopenharmony_ci{
339862306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
339962306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
340062306a36Sopenharmony_ci	struct component_match *match = NULL;
340162306a36Sopenharmony_ci	struct power_supply_config ac_psy_cfg = {}, usb_psy_cfg = {};
340262306a36Sopenharmony_ci	struct ab8500_charger *di;
340362306a36Sopenharmony_ci	int charger_status;
340462306a36Sopenharmony_ci	int i, irq;
340562306a36Sopenharmony_ci	int ret;
340662306a36Sopenharmony_ci
340762306a36Sopenharmony_ci	di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
340862306a36Sopenharmony_ci	if (!di)
340962306a36Sopenharmony_ci		return -ENOMEM;
341062306a36Sopenharmony_ci
341162306a36Sopenharmony_ci	di->bm = &ab8500_bm_data;
341262306a36Sopenharmony_ci
341362306a36Sopenharmony_ci	di->autopower_cfg = of_property_read_bool(np, "autopower_cfg");
341462306a36Sopenharmony_ci
341562306a36Sopenharmony_ci	/* get parent data */
341662306a36Sopenharmony_ci	di->dev = dev;
341762306a36Sopenharmony_ci	di->parent = dev_get_drvdata(pdev->dev.parent);
341862306a36Sopenharmony_ci
341962306a36Sopenharmony_ci	/* Get ADC channels */
342062306a36Sopenharmony_ci	if (!is_ab8505(di->parent)) {
342162306a36Sopenharmony_ci		di->adc_main_charger_v = devm_iio_channel_get(dev, "main_charger_v");
342262306a36Sopenharmony_ci		if (IS_ERR(di->adc_main_charger_v)) {
342362306a36Sopenharmony_ci			ret = dev_err_probe(dev, PTR_ERR(di->adc_main_charger_v),
342462306a36Sopenharmony_ci					    "failed to get ADC main charger voltage\n");
342562306a36Sopenharmony_ci			return ret;
342662306a36Sopenharmony_ci		}
342762306a36Sopenharmony_ci		di->adc_main_charger_c = devm_iio_channel_get(dev, "main_charger_c");
342862306a36Sopenharmony_ci		if (IS_ERR(di->adc_main_charger_c)) {
342962306a36Sopenharmony_ci			ret = dev_err_probe(dev, PTR_ERR(di->adc_main_charger_c),
343062306a36Sopenharmony_ci					    "failed to get ADC main charger current\n");
343162306a36Sopenharmony_ci			return ret;
343262306a36Sopenharmony_ci		}
343362306a36Sopenharmony_ci	}
343462306a36Sopenharmony_ci	di->adc_vbus_v = devm_iio_channel_get(dev, "vbus_v");
343562306a36Sopenharmony_ci	if (IS_ERR(di->adc_vbus_v)) {
343662306a36Sopenharmony_ci		ret = dev_err_probe(dev, PTR_ERR(di->adc_vbus_v),
343762306a36Sopenharmony_ci				    "failed to get ADC USB charger voltage\n");
343862306a36Sopenharmony_ci		return ret;
343962306a36Sopenharmony_ci	}
344062306a36Sopenharmony_ci	di->adc_usb_charger_c = devm_iio_channel_get(dev, "usb_charger_c");
344162306a36Sopenharmony_ci	if (IS_ERR(di->adc_usb_charger_c)) {
344262306a36Sopenharmony_ci		ret = dev_err_probe(dev, PTR_ERR(di->adc_usb_charger_c),
344362306a36Sopenharmony_ci				    "failed to get ADC USB charger current\n");
344462306a36Sopenharmony_ci		return ret;
344562306a36Sopenharmony_ci	}
344662306a36Sopenharmony_ci
344762306a36Sopenharmony_ci	/*
344862306a36Sopenharmony_ci	 * VDD ADC supply needs to be enabled from this driver when there
344962306a36Sopenharmony_ci	 * is a charger connected to avoid erroneous BTEMP_HIGH/LOW
345062306a36Sopenharmony_ci	 * interrupts during charging
345162306a36Sopenharmony_ci	 */
345262306a36Sopenharmony_ci	di->regu = devm_regulator_get(dev, "vddadc");
345362306a36Sopenharmony_ci	if (IS_ERR(di->regu)) {
345462306a36Sopenharmony_ci		ret = PTR_ERR(di->regu);
345562306a36Sopenharmony_ci		dev_err(dev, "failed to get vddadc regulator\n");
345662306a36Sopenharmony_ci		return ret;
345762306a36Sopenharmony_ci	}
345862306a36Sopenharmony_ci
345962306a36Sopenharmony_ci	/* Request interrupts */
346062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) {
346162306a36Sopenharmony_ci		irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name);
346262306a36Sopenharmony_ci		if (irq < 0)
346362306a36Sopenharmony_ci			return irq;
346462306a36Sopenharmony_ci
346562306a36Sopenharmony_ci		ret = devm_request_threaded_irq(dev,
346662306a36Sopenharmony_ci			irq, NULL, ab8500_charger_irq[i].isr,
346762306a36Sopenharmony_ci			IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
346862306a36Sopenharmony_ci			ab8500_charger_irq[i].name, di);
346962306a36Sopenharmony_ci
347062306a36Sopenharmony_ci		if (ret != 0) {
347162306a36Sopenharmony_ci			dev_err(dev, "failed to request %s IRQ %d: %d\n"
347262306a36Sopenharmony_ci				, ab8500_charger_irq[i].name, irq, ret);
347362306a36Sopenharmony_ci			return ret;
347462306a36Sopenharmony_ci		}
347562306a36Sopenharmony_ci		dev_dbg(dev, "Requested %s IRQ %d: %d\n",
347662306a36Sopenharmony_ci			ab8500_charger_irq[i].name, irq, ret);
347762306a36Sopenharmony_ci	}
347862306a36Sopenharmony_ci
347962306a36Sopenharmony_ci	/* initialize lock */
348062306a36Sopenharmony_ci	spin_lock_init(&di->usb_state.usb_lock);
348162306a36Sopenharmony_ci	mutex_init(&di->usb_ipt_crnt_lock);
348262306a36Sopenharmony_ci
348362306a36Sopenharmony_ci	di->autopower = false;
348462306a36Sopenharmony_ci	di->invalid_charger_detect_state = 0;
348562306a36Sopenharmony_ci
348662306a36Sopenharmony_ci	/* AC and USB supply config */
348762306a36Sopenharmony_ci	ac_psy_cfg.of_node = np;
348862306a36Sopenharmony_ci	ac_psy_cfg.supplied_to = supply_interface;
348962306a36Sopenharmony_ci	ac_psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface);
349062306a36Sopenharmony_ci	ac_psy_cfg.drv_data = &di->ac_chg;
349162306a36Sopenharmony_ci	usb_psy_cfg.of_node = np;
349262306a36Sopenharmony_ci	usb_psy_cfg.supplied_to = supply_interface;
349362306a36Sopenharmony_ci	usb_psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface);
349462306a36Sopenharmony_ci	usb_psy_cfg.drv_data = &di->usb_chg;
349562306a36Sopenharmony_ci
349662306a36Sopenharmony_ci	/* AC supply */
349762306a36Sopenharmony_ci	/* ux500_charger sub-class */
349862306a36Sopenharmony_ci	di->ac_chg.ops.enable = &ab8500_charger_ac_en;
349962306a36Sopenharmony_ci	di->ac_chg.ops.check_enable = &ab8500_charger_ac_check_enable;
350062306a36Sopenharmony_ci	di->ac_chg.ops.kick_wd = &ab8500_charger_watchdog_kick;
350162306a36Sopenharmony_ci	di->ac_chg.ops.update_curr = &ab8500_charger_update_charger_current;
350262306a36Sopenharmony_ci	di->ac_chg.max_out_volt_uv = ab8500_charger_voltage_map[
350362306a36Sopenharmony_ci		ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
350462306a36Sopenharmony_ci	di->ac_chg.max_out_curr_ua =
350562306a36Sopenharmony_ci		ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1];
350662306a36Sopenharmony_ci	di->ac_chg.wdt_refresh = CHG_WD_INTERVAL;
350762306a36Sopenharmony_ci	/*
350862306a36Sopenharmony_ci	 * The AB8505 only supports USB charging. If we are not the
350962306a36Sopenharmony_ci	 * AB8505, register an AC charger.
351062306a36Sopenharmony_ci	 *
351162306a36Sopenharmony_ci	 * TODO: if this should be opt-in, add DT properties for this.
351262306a36Sopenharmony_ci	 */
351362306a36Sopenharmony_ci	if (!is_ab8505(di->parent))
351462306a36Sopenharmony_ci		di->ac_chg.enabled = true;
351562306a36Sopenharmony_ci
351662306a36Sopenharmony_ci	/* USB supply */
351762306a36Sopenharmony_ci	/* ux500_charger sub-class */
351862306a36Sopenharmony_ci	di->usb_chg.ops.enable = &ab8500_charger_usb_en;
351962306a36Sopenharmony_ci	di->usb_chg.ops.check_enable = &ab8500_charger_usb_check_enable;
352062306a36Sopenharmony_ci	di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick;
352162306a36Sopenharmony_ci	di->usb_chg.ops.update_curr = &ab8500_charger_update_charger_current;
352262306a36Sopenharmony_ci	di->usb_chg.max_out_volt_uv = ab8500_charger_voltage_map[
352362306a36Sopenharmony_ci		ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
352462306a36Sopenharmony_ci	di->usb_chg.max_out_curr_ua =
352562306a36Sopenharmony_ci		ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1];
352662306a36Sopenharmony_ci	di->usb_chg.wdt_refresh = CHG_WD_INTERVAL;
352762306a36Sopenharmony_ci	di->usb_state.usb_current_ua = -1;
352862306a36Sopenharmony_ci
352962306a36Sopenharmony_ci	mutex_init(&di->charger_attached_mutex);
353062306a36Sopenharmony_ci
353162306a36Sopenharmony_ci	/* Init work for HW failure check */
353262306a36Sopenharmony_ci	INIT_DEFERRABLE_WORK(&di->check_hw_failure_work,
353362306a36Sopenharmony_ci		ab8500_charger_check_hw_failure_work);
353462306a36Sopenharmony_ci	INIT_DEFERRABLE_WORK(&di->check_usbchgnotok_work,
353562306a36Sopenharmony_ci		ab8500_charger_check_usbchargernotok_work);
353662306a36Sopenharmony_ci
353762306a36Sopenharmony_ci	INIT_DELAYED_WORK(&di->ac_charger_attached_work,
353862306a36Sopenharmony_ci			  ab8500_charger_ac_attached_work);
353962306a36Sopenharmony_ci	INIT_DELAYED_WORK(&di->usb_charger_attached_work,
354062306a36Sopenharmony_ci			  ab8500_charger_usb_attached_work);
354162306a36Sopenharmony_ci
354262306a36Sopenharmony_ci	/*
354362306a36Sopenharmony_ci	 * For ABB revision 1.0 and 1.1 there is a bug in the watchdog
354462306a36Sopenharmony_ci	 * logic. That means we have to continuously kick the charger
354562306a36Sopenharmony_ci	 * watchdog even when no charger is connected. This is only
354662306a36Sopenharmony_ci	 * valid once the AC charger has been enabled. This is
354762306a36Sopenharmony_ci	 * a bug that is not handled by the algorithm and the
354862306a36Sopenharmony_ci	 * watchdog have to be kicked by the charger driver
354962306a36Sopenharmony_ci	 * when the AC charger is disabled
355062306a36Sopenharmony_ci	 */
355162306a36Sopenharmony_ci	INIT_DEFERRABLE_WORK(&di->kick_wd_work,
355262306a36Sopenharmony_ci		ab8500_charger_kick_watchdog_work);
355362306a36Sopenharmony_ci
355462306a36Sopenharmony_ci	INIT_DEFERRABLE_WORK(&di->check_vbat_work,
355562306a36Sopenharmony_ci		ab8500_charger_check_vbat_work);
355662306a36Sopenharmony_ci
355762306a36Sopenharmony_ci	INIT_DELAYED_WORK(&di->attach_work,
355862306a36Sopenharmony_ci		ab8500_charger_usb_link_attach_work);
355962306a36Sopenharmony_ci
356062306a36Sopenharmony_ci	INIT_DELAYED_WORK(&di->usb_state_changed_work,
356162306a36Sopenharmony_ci		ab8500_charger_usb_state_changed_work);
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_ci	INIT_DELAYED_WORK(&di->vbus_drop_end_work,
356462306a36Sopenharmony_ci		ab8500_charger_vbus_drop_end_work);
356562306a36Sopenharmony_ci
356662306a36Sopenharmony_ci	/* Init work for charger detection */
356762306a36Sopenharmony_ci	INIT_WORK(&di->usb_link_status_work,
356862306a36Sopenharmony_ci		ab8500_charger_usb_link_status_work);
356962306a36Sopenharmony_ci	INIT_WORK(&di->ac_work, ab8500_charger_ac_work);
357062306a36Sopenharmony_ci	INIT_WORK(&di->detect_usb_type_work,
357162306a36Sopenharmony_ci		ab8500_charger_detect_usb_type_work);
357262306a36Sopenharmony_ci
357362306a36Sopenharmony_ci	/* Init work for checking HW status */
357462306a36Sopenharmony_ci	INIT_WORK(&di->check_main_thermal_prot_work,
357562306a36Sopenharmony_ci		ab8500_charger_check_main_thermal_prot_work);
357662306a36Sopenharmony_ci	INIT_WORK(&di->check_usb_thermal_prot_work,
357762306a36Sopenharmony_ci		ab8500_charger_check_usb_thermal_prot_work);
357862306a36Sopenharmony_ci
357962306a36Sopenharmony_ci
358062306a36Sopenharmony_ci	/* Initialize OVV, and other registers */
358162306a36Sopenharmony_ci	ret = ab8500_charger_init_hw_registers(di);
358262306a36Sopenharmony_ci	if (ret) {
358362306a36Sopenharmony_ci		dev_err(dev, "failed to initialize ABB registers\n");
358462306a36Sopenharmony_ci		return ret;
358562306a36Sopenharmony_ci	}
358662306a36Sopenharmony_ci
358762306a36Sopenharmony_ci	/* Register AC charger class */
358862306a36Sopenharmony_ci	if (di->ac_chg.enabled) {
358962306a36Sopenharmony_ci		di->ac_chg.psy = devm_power_supply_register(dev,
359062306a36Sopenharmony_ci						       &ab8500_ac_chg_desc,
359162306a36Sopenharmony_ci						       &ac_psy_cfg);
359262306a36Sopenharmony_ci		if (IS_ERR(di->ac_chg.psy)) {
359362306a36Sopenharmony_ci			dev_err(dev, "failed to register AC charger\n");
359462306a36Sopenharmony_ci			return PTR_ERR(di->ac_chg.psy);
359562306a36Sopenharmony_ci		}
359662306a36Sopenharmony_ci	}
359762306a36Sopenharmony_ci
359862306a36Sopenharmony_ci	/* Register USB charger class */
359962306a36Sopenharmony_ci	di->usb_chg.psy = devm_power_supply_register(dev,
360062306a36Sopenharmony_ci						     &ab8500_usb_chg_desc,
360162306a36Sopenharmony_ci						     &usb_psy_cfg);
360262306a36Sopenharmony_ci	if (IS_ERR(di->usb_chg.psy)) {
360362306a36Sopenharmony_ci		dev_err(dev, "failed to register USB charger\n");
360462306a36Sopenharmony_ci		return PTR_ERR(di->usb_chg.psy);
360562306a36Sopenharmony_ci	}
360662306a36Sopenharmony_ci
360762306a36Sopenharmony_ci	/*
360862306a36Sopenharmony_ci	 * Check what battery we have, since we always have the USB
360962306a36Sopenharmony_ci	 * psy, use that as a handle.
361062306a36Sopenharmony_ci	 */
361162306a36Sopenharmony_ci	ret = ab8500_bm_of_probe(di->usb_chg.psy, di->bm);
361262306a36Sopenharmony_ci	if (ret)
361362306a36Sopenharmony_ci		return dev_err_probe(dev, ret,
361462306a36Sopenharmony_ci				     "failed to get battery information\n");
361562306a36Sopenharmony_ci
361662306a36Sopenharmony_ci	/* Identify the connected charger types during startup */
361762306a36Sopenharmony_ci	charger_status = ab8500_charger_detect_chargers(di, true);
361862306a36Sopenharmony_ci	if (charger_status & AC_PW_CONN) {
361962306a36Sopenharmony_ci		di->ac.charger_connected = 1;
362062306a36Sopenharmony_ci		di->ac_conn = true;
362162306a36Sopenharmony_ci		ab8500_power_supply_changed(di, di->ac_chg.psy);
362262306a36Sopenharmony_ci		sysfs_notify(&di->ac_chg.psy->dev.kobj, NULL, "present");
362362306a36Sopenharmony_ci	}
362462306a36Sopenharmony_ci
362562306a36Sopenharmony_ci	platform_set_drvdata(pdev, di);
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ci	/* Create something that will match the subdrivers when we bind */
362862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ab8500_charger_component_drivers); i++) {
362962306a36Sopenharmony_ci		struct device_driver *drv = &ab8500_charger_component_drivers[i]->driver;
363062306a36Sopenharmony_ci		struct device *p = NULL, *d;
363162306a36Sopenharmony_ci
363262306a36Sopenharmony_ci		while ((d = platform_find_device_by_driver(p, drv))) {
363362306a36Sopenharmony_ci			put_device(p);
363462306a36Sopenharmony_ci			component_match_add(dev, &match, component_compare_dev, d);
363562306a36Sopenharmony_ci			p = d;
363662306a36Sopenharmony_ci		}
363762306a36Sopenharmony_ci		put_device(p);
363862306a36Sopenharmony_ci	}
363962306a36Sopenharmony_ci	if (!match) {
364062306a36Sopenharmony_ci		dev_err(dev, "no matching components\n");
364162306a36Sopenharmony_ci		ret = -ENODEV;
364262306a36Sopenharmony_ci		goto remove_ab8500_bm;
364362306a36Sopenharmony_ci	}
364462306a36Sopenharmony_ci	if (IS_ERR(match)) {
364562306a36Sopenharmony_ci		dev_err(dev, "could not create component match\n");
364662306a36Sopenharmony_ci		ret = PTR_ERR(match);
364762306a36Sopenharmony_ci		goto remove_ab8500_bm;
364862306a36Sopenharmony_ci	}
364962306a36Sopenharmony_ci
365062306a36Sopenharmony_ci	di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
365162306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(di->usb_phy)) {
365262306a36Sopenharmony_ci		dev_err(dev, "failed to get usb transceiver\n");
365362306a36Sopenharmony_ci		ret = -EINVAL;
365462306a36Sopenharmony_ci		goto remove_ab8500_bm;
365562306a36Sopenharmony_ci	}
365662306a36Sopenharmony_ci	di->nb.notifier_call = ab8500_charger_usb_notifier_call;
365762306a36Sopenharmony_ci	ret = usb_register_notifier(di->usb_phy, &di->nb);
365862306a36Sopenharmony_ci	if (ret) {
365962306a36Sopenharmony_ci		dev_err(dev, "failed to register usb notifier\n");
366062306a36Sopenharmony_ci		goto put_usb_phy;
366162306a36Sopenharmony_ci	}
366262306a36Sopenharmony_ci
366362306a36Sopenharmony_ci	ret = component_master_add_with_match(&pdev->dev,
366462306a36Sopenharmony_ci					      &ab8500_charger_comp_ops,
366562306a36Sopenharmony_ci					      match);
366662306a36Sopenharmony_ci	if (ret) {
366762306a36Sopenharmony_ci		dev_err(dev, "failed to add component master\n");
366862306a36Sopenharmony_ci		goto free_notifier;
366962306a36Sopenharmony_ci	}
367062306a36Sopenharmony_ci
367162306a36Sopenharmony_ci	return 0;
367262306a36Sopenharmony_ci
367362306a36Sopenharmony_cifree_notifier:
367462306a36Sopenharmony_ci	usb_unregister_notifier(di->usb_phy, &di->nb);
367562306a36Sopenharmony_ciput_usb_phy:
367662306a36Sopenharmony_ci	usb_put_phy(di->usb_phy);
367762306a36Sopenharmony_ciremove_ab8500_bm:
367862306a36Sopenharmony_ci	ab8500_bm_of_remove(di->usb_chg.psy, di->bm);
367962306a36Sopenharmony_ci	return ret;
368062306a36Sopenharmony_ci}
368162306a36Sopenharmony_ci
368262306a36Sopenharmony_cistatic int ab8500_charger_remove(struct platform_device *pdev)
368362306a36Sopenharmony_ci{
368462306a36Sopenharmony_ci	struct ab8500_charger *di = platform_get_drvdata(pdev);
368562306a36Sopenharmony_ci
368662306a36Sopenharmony_ci	component_master_del(&pdev->dev, &ab8500_charger_comp_ops);
368762306a36Sopenharmony_ci
368862306a36Sopenharmony_ci	usb_unregister_notifier(di->usb_phy, &di->nb);
368962306a36Sopenharmony_ci	ab8500_bm_of_remove(di->usb_chg.psy, di->bm);
369062306a36Sopenharmony_ci	usb_put_phy(di->usb_phy);
369162306a36Sopenharmony_ci
369262306a36Sopenharmony_ci	return 0;
369362306a36Sopenharmony_ci}
369462306a36Sopenharmony_ci
369562306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(ab8500_charger_pm_ops, ab8500_charger_suspend, ab8500_charger_resume);
369662306a36Sopenharmony_ci
369762306a36Sopenharmony_cistatic const struct of_device_id ab8500_charger_match[] = {
369862306a36Sopenharmony_ci	{ .compatible = "stericsson,ab8500-charger", },
369962306a36Sopenharmony_ci	{ },
370062306a36Sopenharmony_ci};
370162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ab8500_charger_match);
370262306a36Sopenharmony_ci
370362306a36Sopenharmony_cistatic struct platform_driver ab8500_charger_driver = {
370462306a36Sopenharmony_ci	.probe = ab8500_charger_probe,
370562306a36Sopenharmony_ci	.remove = ab8500_charger_remove,
370662306a36Sopenharmony_ci	.driver = {
370762306a36Sopenharmony_ci		.name = "ab8500-charger",
370862306a36Sopenharmony_ci		.of_match_table = ab8500_charger_match,
370962306a36Sopenharmony_ci		.pm = &ab8500_charger_pm_ops,
371062306a36Sopenharmony_ci	},
371162306a36Sopenharmony_ci};
371262306a36Sopenharmony_ci
371362306a36Sopenharmony_cistatic int __init ab8500_charger_init(void)
371462306a36Sopenharmony_ci{
371562306a36Sopenharmony_ci	int ret;
371662306a36Sopenharmony_ci
371762306a36Sopenharmony_ci	ret = platform_register_drivers(ab8500_charger_component_drivers,
371862306a36Sopenharmony_ci			ARRAY_SIZE(ab8500_charger_component_drivers));
371962306a36Sopenharmony_ci	if (ret)
372062306a36Sopenharmony_ci		return ret;
372162306a36Sopenharmony_ci
372262306a36Sopenharmony_ci	ret = platform_driver_register(&ab8500_charger_driver);
372362306a36Sopenharmony_ci	if (ret) {
372462306a36Sopenharmony_ci		platform_unregister_drivers(ab8500_charger_component_drivers,
372562306a36Sopenharmony_ci				ARRAY_SIZE(ab8500_charger_component_drivers));
372662306a36Sopenharmony_ci		return ret;
372762306a36Sopenharmony_ci	}
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_ci	return 0;
373062306a36Sopenharmony_ci}
373162306a36Sopenharmony_ci
373262306a36Sopenharmony_cistatic void __exit ab8500_charger_exit(void)
373362306a36Sopenharmony_ci{
373462306a36Sopenharmony_ci	platform_unregister_drivers(ab8500_charger_component_drivers,
373562306a36Sopenharmony_ci			ARRAY_SIZE(ab8500_charger_component_drivers));
373662306a36Sopenharmony_ci	platform_driver_unregister(&ab8500_charger_driver);
373762306a36Sopenharmony_ci}
373862306a36Sopenharmony_ci
373962306a36Sopenharmony_cimodule_init(ab8500_charger_init);
374062306a36Sopenharmony_cimodule_exit(ab8500_charger_exit);
374162306a36Sopenharmony_ci
374262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
374362306a36Sopenharmony_ciMODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy");
374462306a36Sopenharmony_ciMODULE_ALIAS("platform:ab8500-charger");
374562306a36Sopenharmony_ciMODULE_DESCRIPTION("AB8500 charger management driver");
3746